Memasuki era baru firmware dengan Rust: mengapa memory safety menjadi standar 2026, bekerja dalam mode no_std, ekosistem embedded Rust seperti Embassy dan esp-hal, ownership dan borrowing di firmware, interop dengan C, serta praktik menulis firmware Rust pertama.

Setelah 14 episode membangun fondasi dengan C, pada episode ini kita menulis firmware dengan bahasa yang menjadi standar baru 2026: Rust. Bukan karena tren — tapi karena Rust menghilangkan di level kompiler kelas bug yang paling mahal di firmware: use-after-free, buffer overflow, dan data race.
Mengapa Rust penting sekarang? Di 2026, Rust menjadi mainstream untuk firmware baru: produsen chip mengeluarkan dukungan resmi (ESP32, nRF, RP2040), dan posisi low-level Rust paling banyak dicari (episode 1). Jika kalian bisa C dan Rust, kalian punya dua senjata untuk semua jenis project.
C memberi kebebasan penuh — dan dengan kebebasan itu datang tanggung jawab. Rust menawarkan kebebasan yang sama dengan jaring pengaman:
| Aspek | C | Rust |
|---|---|---|
| Memory safety | Tangan sendiri (bug umum) | Dijamin kompiler (ownership) |
| Data race | Sulit dideteksi | Tidak bisa terjadi (safe code) |
| Null pointer | Ada (NULL) | Tidak ada (Option) |
| Overhead | Zero | Zero-cost abstraksi |
| GC | Tidak ada | Tidak ada (cocok embedded) |
| Safety certification | MISRA (manual) | Rust std/knurling tooling |
Rust "hanya" sesederhana C yang aman — aturan ownership/borrowing menjamin: tidak ada dua owner, tidak ada reference yang hidup lebih lama dari datanya, dan panic (crash) lebih baik dari UB (perilaku tak terdefinisi).
Firmware memakai no_std — Rust tanpa standard library (yang butuh OS). Hanya core library (tidak butuh allocator) tersedia:
[package]
name = "blinky"
version = "0.1.0"
edition = "2021"
[dependencies]
esp-hal = "0.22"
esp-println = "0.12"
[profile.release]
opt-level = "s"
lto = "fat"#![no_std]
#![no_main]
use esp_hal::prelude::*;
use esp_hal::timer::timg::TimerGroup;
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let mut led = peripherals.GPIO5.output();
let timg = TimerGroup::new(peripherals.TIMG0);
let mut delay = timg.timer0.delay();
loop {
led.toggle();
delay.delay_millis(500);
}
}Perhatikan #![no_main] — main bukan fungsi biasa, dan #[entry] memberitahu runtime. Kode ini tidak bisa panic diam-diam: jika panic terjadi, dipanggil panic handler (yang bisa kita sesuaikan).
| Komponen | Peran |
|---|---|
| embedded-hal | Traits abstrak (GPIO, I2C, SPI, delay) — driver portabel lintas chip |
| esp-hal / esp-idf-hal | Dukungan resmi Espressif |
| stm32-rs / stm32-hal | Dukungan STM32 |
| Embassy | Runtime async + timer + executor untuk firmware |
| rtic | Real-time concurrency framework berbasis prioritas |
| cargo-embed / probe-rs | Flash + debug tanpa OpenOCD |
Pola kunci: driver ditulis terhadap embedded-hal traits, sehingga satu driver sensor bisa dipakai di ESP32, STM32, dan nRF tanpa diubah — portabilitas yang di C hanya impian.
Prinsip Rust terasa "aneh" di awal, tapi justru menyelamatkan di embedded:
fn read_sensor(sensor: &mut Sensor) -> u16 {
sensor.read() // &mut = meminjam sementara
}
let mut s = Sensor::new();
let value = read_sensor(&mut s);
// setelah peminjaman selesai, s bisa dipakai lagiIni berarti bug memory yang di C butuh berhari-hari debugging (episode 9) di Rust tidak bisa compile.
Tip
Untuk memulai, gunakan template resmi: cargo generate esp-rs/esp-template (ESP32) atau buku The Embedded Rust Book untuk ARM. Jangan menulis semuanya dari nol — ekosistem sudah menyediakan HAL, startup, dan tooling yang matang di 2026.
Proyek nyata jarang 100% Rust sejak hari pertama. Rust bisa memanggil C (FFI) dan sebaliknya:
extern "C" {
fn uart_puts(s: *const u8); // fungsi dari lib C
}
// bungkus dalam safe wrapper
fn log_msg(s: &str) {
unsafe { uart_puts(s.as_ptr()) }
}Strategi migrasi umum: mulai dengan satu modul baru (misal parser atau kalkulasi) dalam Rust, pertahankan sisanya C, lalu perluas. Rust dan C bisa hidup satu project — buffer untuk extern "C" harus tetap valid sepanjang panggilan (borrow checker mengingatkan kalian).
std di firmware — butuh OS; pakai no_std + core.unsafe menghilangkan jaminan; bungkus rapat dan dokumentasikan.opt-level/lto; gunakan cargo bloat.Inti yang harus dibawa pulang:
no_std = Rust tanpa OS; hanya core yang tersedia.Di episode 16 selanjutnya kita kembali ke jantung sistem real-time: Real-Time Constraints — deadline, determinism, WCET, dan desain firmware yang harus merespons tepat waktu di bawah segala kondisi. Kalian akan berpikir seperti insinyur sistem kontrol!