Belajar Embedded Engineer - Rust untuk Embedded
Episode 11 of 28

Belajar Embedded Engineer - Rust untuk Embedded

Menambahkan Rust sebagai senjata kedua: memahami no_std tanpa OS, memory safety tanpa garbage collector, ownership yang mencegah race condition, serta ekosistem embedded-hal dan cargo-embed, ditutup praktik aplikasi embedded Rust pertama yang aman dan idiomatik

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

Pendahuluan

Di episode 1 kalian sudah mendengar ramalannya: Rust mainstream untuk embedded. Kini tibalah waktunya membuktikannya. Rust menawarkan apa yang selama puluhan tahun menjadi mimpi firmware engineer: memory safety saat compile time, tanpa biaya runtime. Bug yang di C/C++ butuh debugging berminggu-minggu — buffer overflow, use-after-free, race condition — di Rust dicegah oleh compiler sebelum binary lahir.

Tentu ada trade-off: kurva belajar ownership yang curam dan ekosistem yang masih berkembang. Tapi di 2026, toolchain embedded Rust (embassy, esp-hal, stm32-hal) sudah matang untuk produksi — dari keyboard mekanik sampai aerospace. Episode ini membangun fondasinya.

no_std: Rust Tanpa OS

Embedded Rust bekerja dalam dua mode. Untuk MCU kecil, targetnya no_std — Rust tanpa standard library, karena std membutuhkan OS dan heap global:

Aspekstdno_std
Memakai heapGlobal allocator defaultHarus manual (opsional)
Thread/OSThreads bawaanBare-metal atau RTOS
Kapan dipakaiHost, Linux, aplikasi besarMCU, driver, kernel
ContohDesktop appSTM32/ESP32 firmware

Ciri no_std dalam kode: #![no_std] di crate root dan atribut #![no_main] untuk entry point tanpa runtime. Semua kode yang memakai std (file I/O, thread, String) harus ditulis ulang dengan alternatif embedded — alloc crate, fixed-size buffers, dan pattern heapless.

Memory Safety: Janji yang Dipenuhi di Compile Time

Kekuatan inti Rust adalah ownership: setiap data punya satu pemilik, dan saat pemilik dihapus, data dihapus. Dua aturan yang mengubah segalanya:

  1. Setiap nilai punya satu owner — tidak ada dua referensi yang bisa memodifikasi bersamaan.
  2. Borrowing diawasi — boleh banyak referensi baca, atau satu referensi tulis, tidak keduanya.

Dampaknya pada embedded: race condition yang di C memerlukan disiplin manual (episode 8), di Rust tidak bisa di-compile. Contoh — berbagi data antara ISR dan task adalah pola paling rawan di C:

rust
#![no_std]
#![no_main]
 
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use core::cell::Cell;
 
static TICK: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
 
#[interrupt]
fn SysTick() {
    cortex_m::interrupt::free(|cs| {
        TICK.borrow(cs).set(TICK.borrow(cs).get() + 1);
    });
}
 
#[entry]
fn main() -> ! {
    loop {
        let now = cortex_m::interrupt::free(|cs| TICK.borrow(cs).get());
        if now % 1000 == 0 {
            toggle_led();
        }
    }
}

Mutex di cortex-m (bukan mutex thread) adalah cara Rust memaksa akses aman ke data yang dibagi ISR: compiler memastikan hanya lewat critical section yang tepat data itu disentuh. Data race = compile error, bukan bug yang menunggu di lapangan.

Ekosistem: embedded-hal & Alat Bantu

Ekosistem embedded Rust dibangun di atas embedded-hal — trait abstrak untuk GPIO, I2C, SPI, dan UART. Selama chip memiliki implementasi embedded-hal, kode driver kalian portable: driver yang ditulis untuk sensor bisa dipakai di STM32, ESP32, RP2040, dan nRF tanpa mengubah satu baris pun.

Toolchain untuk embedded Rust:

ToolFungsi
cargo + thumbv7em-none-eabihf targetCompile ke ARM Cortex-M
cargo-embed / probe-rsFlash + debug via debug probe
defmtLogging format minimal dengan overhead kecil
embassyAsync runtime embedded modern (alternatif RTOS)

Setup singkat:

Setup toolchain Rust embedded
rustup target add thumbv7em-none-eabihf   # STM32F4
cargo install probe-rs-tools
cargo init --bin my-firmware

Untuk flash dan debug langsung:

Flash & run via probe-rs
cargo embed --release

Project minimal dengan cortex-m + embedded-hal untuk STM32:

Cargo.toml
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
embedded-hal = "1.0"
stm32f4xx-hal = { version = "0.18", features = ["stm32f401"] }
src/main.rs
#![no_std]
#![no_main]
 
use cortex_m_rt::entry;
use embedded_hal::digital::OutputPin;
use stm32f4xx_hal::{pac, prelude::*};
 
#[entry]
fn main() -> ! {
    let dp = pac::Peripherals::take().unwrap();
    let rcc = dp.RCC.constrain();
    let clocks = rcc.cfgr.sysclk(84.MHz()).freeze();
    let gpioc = dp.GPIOC.split();
 
    let mut led = gpioc.pc13.into_push_pull_output();
    loop {
        led.set_high().ok();
        cortex_m::asm::delay(2_000_000);
        led.set_low().ok();
        cortex_m::asm::delay(2_000_000);
    }
}

Perhatikan: tidak ada unsafe, tidak ada global variable, tidak ada memset manual. Pin LED dibungkus tipe PushPullOutput — compiler tidak mengizinkan memakainya sebagai input, jadi kesalahan konfigurasi pin tercegah di type system.

Note

Jangan panik dengan kurva belajar. Kalian tidak perlu "berpindah" dari C — kalian menambah senjata. Strategi terbaik: tulis modul kecil yang aman (driver, state machine) dalam Rust sementara sistem tetap C, atau sebaliknya. Banyak tim produksi di 2026 justru memakai keduanya: C untuk legacy dan driver chip-level, Rust untuk logika aplikasi yang paling rawan bug.

Common Pitfalls

  1. Menggunakan std tanpa sadar — Rust di MCU wajib no_std; compiler akan menolak banyak crate biasa.
  2. Lupa menambah target toolchainthumbv7em-none-eabihf untuk Cortex-M4F; arsitektur lain beda target.
  3. Memakai allocator tanpa menginisialisasi — heap butuh allocator global; untuk MCU kecil lebih baik hindari.
  4. Frustrasi di ownership pertama — itu normal; pola Cell, Mutex, dan static mut adalah bahasa baru yang butuh latihan.
  5. Mengharapkan magic — Rust mencegah kelas bug, bukan semua bug; logika salah tetap salah.

Penutup

Inti yang harus dibawa pulang:

  • no_std adalah mode Rust untuk MCU — tanpa OS, tanpa heap default.
  • Ownership mencegah race condition dan memory bug di compile time — bukan saat produksi.
  • embedded-hal membuat driver portable antar chip; probe-rs/cargo-embed untuk flash & debug.
  • Rust dan C bisa hidup berdampingan — Rust untuk logika rawan bug, C untuk legacy & driver chip-level.

Di episode 12 selanjutnya kita menghubungkan perangkat ke dunia: communication & networking embedded — TCP/IP stack, MQTT, dan secure communication, dengan praktik membuat perangkat terhubung. Dunia yang kalian pelajari di episode 1 — "hampir semua perangkat terhubung" — sekarang kita wujudkan. Sampai jumpa di episode 12!

Belajar Embedded Engineer - Rust untuk Embedded | Belajar Embedded Engineer