Belajar Firmware Engineer - Rust for Firmware
Episode 15 of 28

Belajar Firmware Engineer - Rust for Firmware

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.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

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.

Mengapa Rust untuk Firmware?

C memberi kebebasan penuh — dan dengan kebebasan itu datang tanggung jawab. Rust menawarkan kebebasan yang sama dengan jaring pengaman:

AspekCRust
Memory safetyTangan sendiri (bug umum)Dijamin kompiler (ownership)
Data raceSulit dideteksiTidak bisa terjadi (safe code)
Null pointerAda (NULL)Tidak ada (Option)
OverheadZeroZero-cost abstraksi
GCTidak adaTidak ada (cocok embedded)
Safety certificationMISRA (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).

no_std: Rust Tanpa OS

Firmware memakai no_std — Rust tanpa standard library (yang butuh OS). Hanya core library (tidak butuh allocator) tersedia:

Cargo.toml - target firmware
[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"
Firmware Rust: blink tanpa std
#![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).

Ekosistem Embedded Rust 2026

KomponenPeran
embedded-halTraits abstrak (GPIO, I2C, SPI, delay) — driver portabel lintas chip
esp-hal / esp-idf-halDukungan resmi Espressif
stm32-rs / stm32-halDukungan STM32
EmbassyRuntime async + timer + executor untuk firmware
rticReal-time concurrency framework berbasis prioritas
cargo-embed / probe-rsFlash + 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.

Ownership di Firmware

Prinsip Rust terasa "aneh" di awal, tapi justru menyelamatkan di embedded:

Ownership - satu owner, peminjaman aman
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 lagi
  • Satu owner per data → tidak ada double-free.
  • Borrow checker → tidak ada use-after-free; semua diperiksa saat compile.
  • Send/Sync → data yang dibagi antar task harus memenuhi batasan thread-safety.

Ini 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.

Interop dengan C

Proyek nyata jarang 100% Rust sejak hari pertama. Rust bisa memanggil C (FFI) dan sebaliknya:

FFI: panggil fungsi C dari Rust
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).

Kesalahan Umum Rust Firmware

  1. Berkelahi dengan borrow checker — biasanya tanda desain salah, bukan kompiler jahat; refactor struktur data.
  2. Memakai std di firmware — butuh OS; pakai no_std + core.
  3. Unsafe yang berlebihanunsafe menghilangkan jaminan; bungkus rapat dan dokumentasikan.
  4. Melupakan panic handler — panic default hang; pasang handler yang mencatat + reboot.
  5. Mengabaikan ukuran binary — profil opt-level/lto; gunakan cargo bloat.

Penutup

Inti yang harus dibawa pulang:

  • Rust menghilangkan use-after-free, buffer overflow, dan data race di level kompiler — cocok untuk firmware yang aman.
  • no_std = Rust tanpa OS; hanya core yang tersedia.
  • Ekosistem 2026: embedded-hal, esp-hal/stm32-rs, Embassy, probe-rs.
  • Ownership/borrowing menjamin keamanan memori tanpa GC.
  • Interop C memungkinkan migrasi bertahap; Rust dan C bisa satu project.

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!