Belajar C++ - Embedded & High-performance Systems
Series/Belajar C++/Episode 21
Episode 21 of 24

Belajar C++ - Embedded & High-performance Systems

Episode ini membahas C++ untuk embedded dan real-time applications: kendala memori dan perilaku deterministik, integrasi dengan RTOS, profiling kode embedded dan optimasi tingkat rendah, serta deployment firmware dan pertimbangan hardware.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Pendahuluan

Kontroler mobil, perangkat medis, dan sistem kendali industri berjalan pada perangkat dengan sumber daya yang sangat terbatas — kilobyte RAM, tanpa filesystem, tanpa OS penuh. C++ semakin dominan di dunia embedded karena memberi kinerja dan kontrol penuh dengan abstraksi yang lebih aman daripada C murni.

Episode 21 membawa kalian ke embedded dan high-performance systems: prinsip C++ untuk sistem real-time, hidup dengan kendala memori yang keras, integrasi dengan RTOS, cara memprofil kode embedded yang sulit diamati, optimasi tingkat rendah, serta proses deployment firmware ke hardware.

C++ untuk Embedded dan Real-time

Persyaratan Sistem Real-time

Sistem real-time menjamin penyelesaian tugas dalam batas waktu tertentu. Kegagalan batas waktu bisa berarti bencana — mobil tidak berhenti tepat waktu, perangkat medis memberikan dosis salah. Karena itu embedded C++ menuntut:

  • Determinisme: waktu eksekusi dapat diprediksi.
  • Tanpa alokasi dinamis di jalur kritis: new dan malloc bisa berjalan sangat lambat atau gagal.
  • Tanpa exception di jalur kritis: unwinding membutuhkan waktu yang tidak terbatas.
  • constexpr dan metaprogramming untuk memindahkan kerja ke kompilasi.

Contoh gaya embedded yang memenuhi aturan ini:

Gaya embedded aman
#include <cstdint>
#include <array>
 
constexpr std::uint16_t maksimum(const std::array<std::uint16_t, 4>& a) {
    std::uint16_t m = 0;
    for (auto v : a) {
        if (v > m) m = v;
    }
    return m;
}
 
int main() {
    constexpr std::array<std::uint16_t, 4> sampel{10, 40, 25, 18};
    constexpr auto hasil = maksimum(sampel);
    return hasil;
}
EOF
g++ -std=c++20 -Os embedded.cpp -o embedded

constexpr std::array<std::uint16_t, 4> dan constexpr auto hasil membuat semua perhitungan terjadi saat kompilasi — tidak ada alokasi heap, tidak ada variabel runtime, hasil sudah tetap di biner. Gaya ini ideal untuk perangkat dengan RAM terbatas.

Kendala Memori dan Perilaku Deterministik

Hidup dengan Kilobyte RAM

Di embedded, heap sering dihindari sepenuhnya. Semua buffer dialokasikan statis atau di stack dengan ukuran yang diketahui saat kompilasi. std::array menggantikan std::vector, dan tipe ukuran tetap menggantikan tipe yang bergantung platform:

Kompilasi tanpa heap
g++ -std=c++20 -fno-exceptions -fno-rtti \
    -ffreestanding -fstack-usage -Os app.cpp

Bendera -fno-exceptions dan -fno-rtti mematikan fitur yang membutuhkan runtime besar, dan -ffreestanding menandai program sebagai freestanding — tanpa asumsi library standar penuh. -fstack-usage melaporkan pemakaian stack per fungsi, penting untuk merancang budget memori.

Menghindari Bug Timer

Perilaku deterministik juga berarti menghindari operasi yang waktunya tidak pasti: algoritma yang biayanya bergantung pada data (seperti hash map) bisa diganti dengan array terurut atau lookup table. Ukur waktu eksekusi dengan counter hardware atau pin GPIO yang di-toggle — episode 15 membahas alat profiling untuk sistem desktop, dan versi embeddednya memakai alat yang lebih dekat ke hardware.

Integrasi RTOS

Task dan Scheduler

RTOS (Real-Time Operating System) seperti FreeRTOS dan Zephyr menyediakan multitasking dengan prioritas dan jaminan waktu. Konsep yang dipakai RTOS sangat mirip dengan thread di episode 12: task, mutex, semaphore, dan queue. Bedanya, semua berbasis prioritas tetap dan tidak ada heap di jalur kritis:

Task FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
 
void sensor_task(void* param) {
    (void)param;
    for (;;) {
        // baca sensor lalu proses
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}
 
int main() {
    xTaskCreate(sensor_task, "sensor", 256, nullptr, 1, nullptr);
    vTaskStartScheduler();
}

xTaskCreate(sensor_task, "sensor", 256, nullptr, 1, nullptr) membuat task dengan stack 256 word dan prioritas 1, lalu vTaskStartScheduler() menyerahkan kontrol ke scheduler. Task berjalan periodik dengan vTaskDelay(pdMS_TO_TICKS(10)).

Komunikasi Antar Task

Komunikasi antar task memakai queue RTOS alih-alih shared memory mentah. Queue menyalin data dengan mekanisme blocking yang deterministik — aman tanpa mutex manual. Semaphore membatasi akses ke resource bersama, dan event groups menunggu kombinasi kejadian. Pola ini menghindari data race yang dibahas di episode 12.

Profiling Embedded dan Optimasi

Mengamati Perangkat yang Kecil

Perangkat embedded sering tidak punya layar atau filesystem. Profiling memakai alat yang sederhana: toggle GPIO pin di sekitar fungsi yang diukur lalu amati dengan logic analyzer atau osiloskop. FreeRTOS juga punya tracing tools untuk melihat timeline task.

Optimasi Tingkat Rendah

Optimasi embedded berfokus pada ukuran biner dan kecepatan dengan tradeoff yang disadari:

  • -Os: optimasi ukuran untuk chip dengan flash kecil.
  • -ffunction-sections -fdata-sections: memudahkan linker membuang kode mati.
  • Lookup table: ganti perhitungan mahal dengan tabel konstanta.
  • Interrupt handler singkat: jangan lakukan kerja berat di ISR.
Build optimasi ukuran
g++ -std=c++20 -Os -ffunction-sections -fdata-sections \
    -Wl,--gc-sections -fno-exceptions -fno-rtti app.cpp

-Wl,--gc-sections menyuruh linker membuang section yang tidak dipakai, dan -Os mengoptimasi ukuran. Kombinasi ini adalah standar untuk mengecilkan firmware.

Deployment Firmware

Dari Biner ke Perangkat

Firmware adalah executable embedded yang ditanam ke flash perangkat. Proses deployment: compile, hasilkan file biner mentah dengan objcopy, lalu tulis ke perangkat dengan flasher atau debug probe:

Hasilkan firmware biner
arm-none-eabi-objcopy -O binary app.elf app.bin
arm-none-eabi-size app.elf

arm-none-eabi-objcopy -O binary app.elf app.bin mengonversi ELF menjadi biner mentah untuk ditanam, dan arm-none-eabi-size app.elf menampilkan pemakaian flash dan RAM per section. Ukuran inilah budget yang harus dipertahankan selama pengembangan.

Toolchain dan Debug

Toolchain embedded memakai compiler dengan prefix target seperti arm-none-eabi-. Debugging berjalan lewat OpenOCD dan GDB yang terhubung ke debug probe di perangkat:

GDB terhubung via OpenOCD
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg &
gdb -ex 'target remote localhost:3333' -ex load app.elf

gdb -ex 'target remote localhost:3333' -ex load app.elf menghubungkan GDB ke OpenOCD yang berkomunikasi dengan probe, lalu memuat firmware ke RAM atau flash. Dari sini kalian memakai GDB seperti biasa — breakpoint, step, dan memeriksa register.

Info

Selalu kompilasi dengan -Wall -Wextra di embedded dan aktifkan -fstack-usage. Kesalahan stack overflow di perangkat tanpa OS sulit dideteksi dan bisa merusak data tak terduga.

Penutup

Inti yang harus dibawa pulang:

  • Sistem real-time menuntut determinisme dan tanpa alokasi dinamis di jalur kritis.
  • constexpr, std::array, dan tipe ukuran tetap menjadi fondasi kode embedded.
  • RTOS menyediakan task, queue, dan semaphore dengan prioritas tetap.
  • Profiling embedded memakai GPIO, logic analyzer, dan tracing RTOS.
  • -Os, --gc-sections, -fno-exceptions mengecilkan firmware.
  • Deployment memakai objcopy untuk biner dan OpenOCD plus GDB untuk memuat.

Di episode 22 selanjutnya kita akan membahas observability dan production support — logging, tracing, dan monitoring untuk aplikasi C++, analisis crash dump dan post-mortem debugging, release engineering dengan versioning dan packaging, serta maintenance dan dokumentasi.

Belajar C++ - Embedded & High-performance Systems | Belajar C++