Belajar Embedded Engineer - MCU & Peripherals
Episode 4 of 28

Belajar Embedded Engineer - MCU & Peripherals

Mengendalikan dunia luar lewat peripheral MCU: GPIO untuk pin digital, UART/SPI/I2C untuk komunikasi, timer untuk pewaktuan, dan interrupt untuk respons asinkron, lengkap dengan praktik mengontrol peripheral nyata dan tabel perbandingan protokol yang wajib dipilih dengan tepat

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

Pendahuluan

Di episode 3 kalian mengasah C/C++ embedded — pointer, volatile, dan pola-pola seperti ring buffer. Sekarang waktunya membuka jendela ke dunia nyata: peripheral. Inilah bagian yang membuat embedded unik — kode kalian benar-benar menggerakkan sesuatu yang bisa dilihat, disentuh, dan diukur.

Peripheral adalah modul hardware yang melekat di MCU. Kalian tidak membelinya satu per satu; semuanya sudah ada di dalam chip, tinggal diaktifkan dan dikonfigurasi lewat register. Kuncinya bukan menghafal nilai register, melainkan memahami pola kerja setiap keluarga peripheral: GPIO, UART, SPI, I2C, timer, dan interrupt. Kuasai polanya, dan board apa pun terasa familiar.

GPIO: Pintu Masuk Dunia Digital

GPIO (General-Purpose Input/Output) adalah pin yang bisa jadi input atau output digital. Ini peripheral paling dasar dan paling sering dipakai. Tiga register yang harus kalian konfigurasi (STM32F4):

  1. MODER — mode pin (input, output, alternate function, analog).
  2. OTYPER — tipe output (push-pull / open-drain).
  3. OSPEEDR + PUPDR — kecepatan dan pull-up/pull-down.

Contoh nyala LED dari episode 0, tanpa library:

c
#include <stdint.h>
 
#define RCC_AHB1ENR (*(volatile uint32_t *)0x40023830)
#define GPIOA_MODER (*(volatile uint32_t *)0x40020000)
#define GPIOA_ODR   (*(volatile uint32_t *)0x40020014)
 
#define LED_PIN 5U
 
void led_init(void) {
    RCC_AHB1ENR |= (1U << 0);              /* clock GPIOA aktif */
    GPIOA_MODER = (GPIOA_MODER & ~(3U << (LED_PIN * 2))) | (1U << (LED_PIN * 2)); /* output */
}
 
int main(void) {
    led_init();
    for (;;) {
        GPIOA_ODR ^= (1U << LED_PIN);      /* toggle LED */
        for (volatile uint32_t i = 0; i < 500000; i++); /* delay kasar */
    }
}

Perhatikan urutannya: nyalakan clock dulu sebelum menyentuh register peripheral. Ini pitfall klasik — kalian menulis register yang clock-nya mati, dan tidak terjadi apa-apa.

UART: Komunikasi Serial Paling Sederhana

UART adalah protokol point-to-point dua kabel (TX, RX) dengan kecepatan yang disepakati (baud rate). Inilah "printf" firmware — jalan utama melihat apa yang terjadi di dalam perangkat. Pada banyak board, UART terhubung ke USB-serial sehingga outputnya muncul di terminal PC.

Untuk menerima data asinkron, pakai interrupt + ring buffer — pola dari episode 3:

c
static volatile uint8_t rx_buf[64];
static volatile uint8_t rx_head = 0;
 
void USART2_IRQHandler(void) {
    if (USART2->SR & (1U << 5)) {          /* RXNE: data diterima */
        uint8_t b = USART2->DR;
        rx_buf[rx_head] = b;
        rx_head = (rx_head + 1) % 64;
    }
}

Pola ini membuat main loop tetap bebas: data masuk mengalir di buffer tanpa menunggu, dan diproses saat dibutuhkan. Inilah fondasi komunikasi semua firmware.

SPI vs I2C: Memilih Protokol yang Tepat

Dua protokol komunikasi antar-chip yang paling umum untuk sensor, display, dan memory eksternal:

AspekSPII2C
Kabel4 (SCLK, MOSI, MISO, CS)2 (SCL, SDA)
KecepatanTinggi (MHz)Sedang (100-400 kHz, bisa lebih)
Banyak device1 CS per deviceAlamat 7-bit, banyak device di bus sama
KompleksitasMudah, tapi butuh pinLebih kompleks (addressing, ack)
Ideal untukDisplay, flash, data besarSensor, RTC, konfigurasi

Aturan praktis: data besar dan cepat → SPI; banyak sensor kecil → I2C. Keduanya dikonfigurasi dengan pola register yang sama (enable clock → set mode/kecepatan → transfer). Pilih salah satu, kuasai, maka yang lain tinggal menyesuaikan.

Timer & Interrupt: Mesin Waktu Firmware

Timer peripheral menghitung clock dan bisa memicu aksi pada interval presisi — jauh lebih akurat daripada for loop delay yang kita pakai di awal. Inilah jantung scheduling di bare-metal (dipakai penuh di episode 6-7).

Interrupt adalah mekanisme agar hardware bisa "menyela" CPU saat ada kejadian: data UART tiba, pin berubah, timer habis. Tanpa interrupt, CPU harus polling terus-menerus — membuang clock dan daya. Desain interrupt yang benar (prioritas, ISR singkat, concurrency safety) kita bedah mendalam di episode 8.

Common Pitfalls

  1. Lupa enable clock peripheral — "register tidak merespons" padahal clock mati.
  2. Salah pin multiplexing — pin fisik tidak terhubung ke fungsi UART/SPI yang diharapkan.
  3. Debounce diabaikan — tombol memantul ribuan kali saat ditekan; butuh debounce software.
  4. ISR terlalu panjang — memblokir interrupt lain dan menciptakan jitter (episode 8).
  5. Tegangan logic tak cocok — sensor 5V ke pin 3.3V tanpa level shifter = MCU mati.

Tip

Jangan langsung menyalahkan register saat hardware tidak merespons. Debug dengan pola yang sama setiap kali: (1) cek power & ground, (2) cek clock peripheral, (3) cek pin multiplexing, (4) cek wiring fisik. Lebih dari separuh "bug firmware" pemula ternyata adalah kabel yang salah colok.

Penutup

Inti yang harus dibawa pulang:

  • Peripheral dikendalikan lewat register dengan pola: enable clock → konfigurasi mode → operasi.
  • GPIO untuk pin digital; UART untuk komunikasi, dipasangkan interrupt + ring buffer.
  • Pilih SPI untuk data besar, I2C untuk banyak sensor.
  • Timer untuk pewaktuan presisi; interrupt untuk respons asinkron.

Di episode 5 selanjutnya kita masuk ke wilayah yang membedakan firmware hebat dari firmware biasa: memory & DMA — mengelola Flash/RAM/registers, memahami alignment, dan melepas beban CPU dengan Direct Memory Access. Memori di embedded bukan sekadar tempat simpan, tapi juga masalah performa dan keandalan. Sampai jumpa di episode 5!