Belajar Firmware Engineer - MCU Programming
Episode 4 of 28

Belajar Firmware Engineer - MCU Programming

Menaklukkan MCU lewat register: menyiapkan clock dengan RCC, memahami pohon clock HSI/HSE/PLL dan prescaler, mengonfigurasi GPIO mulai dari mode hingga pull-up, serta praktik blink LED register-level penuh tanpa HAL pada STM32.

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

Pendahuluan

Setelah di episode 3 kita menguasai pointer, volatile, dan bit manipulation, saatnya menyatukan semuanya pada MCU Programming — mengendalikan mikrokontroler secara langsung lewat register. Kalian akan melakukan "ritual inisialisasi" yang sama yang dilakukan firmware engineer sungguhan: menyalakan clock, mengonfigurasi GPIO, dan melihat hardware merespons.

Mengapa register-level penting di era HAL yang praktis? Karena HAL adalah abstraksi — dan abstraksi yang tidak dipahami sumbernya adalah sumber bug paling misterius. Saat pin tidak nyala atau clock salah, engineer yang paham register langsung tahu harus cek apa. Di episode 10 kita naik ke driver/HAL; untuk sekarang, kalian harus bisa menulis kode yang berbicara langsung ke silicon.

Sistem Clock

Semua aktivitas MCU berjalan di atas clock. STM32 menawarkan sumber clock internal (HSI) dan eksternal (HSE), yang bisa dikalikan dengan PLL lalu dibagi lewat prescaler:

100%

Beberapa hal yang wajib diingat:

  • Setiap peripheral punya clock gate — Anda harus menyalakan clocknya (biasanya di register RCC) sebelum menyentuh register lain; kalau tidak, tulis ke register itu diabaikan.
  • Bus berbeda punya batas frekuensi — APB1 biasanya lebih rendah dari APB2 (misal 36 MHz vs 72 MHz pada F103). Melanggar batas = perilaku tak terdefinisi.
  • Timer sering memakai clock APB yang bisa digandakan — nilai prescaler timer bergantung pada pembagian bus ini.

Mengaktifkan Clock Peripheral

Pada STM32F1, misalnya, clock GPIOA dihidupkan lewat RCC->APB2ENR:

Aktifkan clock GPIOA (STM32F1)
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;   // bit 2: clock GPIOA ON

Kesalahan paling umum pemula: lupa menyalakan clock, lalu bingung kenapa register tidak berefek. Selalu mulai inisialisasi dari RCC.

GPIO

GPIO (General-Purpose Input/Output) adalah pintu keluar-masuk sinyal digital. Tiap pin dikendalikan oleh beberapa register:

RegisterFungsiBit per pin
MODERMode: input, output, alternate, analog2 bit
OTYPEROutput type: push-pull / open-drain1 bit
OSPEEDRKecepatan output2 bit
PUPDRPull-up / pull-down internal2 bit
IDRMembaca level input1 bit
ODR / BSRRMenulis level output1 bit

Konfigurasi Satu Pin

Pola lengkap untuk menjadikan PA5 sebagai output push-pull kecepatan normal:

Konfigurasi GPIO PA5 sebagai output
// 1. Clock dulu
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
 
// 2. MODER: bit (2*5..2*5+1) = 01 (output) -> PA5
GPIOA->MODER &= ~(3U << (2*5));
GPIOA->MODER |=  (1U << (2*5));
 
// 3. OTYPER: 0 = push-pull (default) - tidak perlu diubah
// 4. PUPDR: 0 = no pull (default) untuk output - tidak perlu diubah

Membaca Input

Untuk button dengan pull-up internal:

Baca input PB0 dengan pull-up
// MODER: 00 = input
GPIOB->MODER &= ~(3U << (2*0));
// PUPDR: 01 = pull-up
GPIOB->PUPDR &= ~(3U << (2*0));
GPIOB->PUPDR |=  (1U << (2*0));
 
if (GPIOB->IDR & (1U << 0)) {
    // level HIGH - button TIDAK ditekan (pull-up aktif)
}

Gabungkan semua konsep — ini firmware pertama tanpa HAL sama sekali (untuk STM32F103, Nucleo F103RB, LED PA5):

main.c - blink register-level penuh
#include "stm32f1xx.h"   // definisi register dari CMSIS
 
static void delay_ms(volatile uint32_t ms) {
    volatile uint32_t count = ms * 4000;  // delay kasar per-loop
    while (count--) {}
}
 
int main(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;   // 1. clock GPIOA
 
    GPIOA->MODER &= ~(3U << (2*5));       // 2. PA5 = output
    GPIOA->MODER |=  (1U << (2*5));
    GPIOA->OTYPER &= ~(1U << 5);          //    push-pull
 
    while (1) {
        GPIOA->ODR ^= (1U << 5);          // 3. toggle LED
        delay_ms(500);                    // 4. tunggu 500 ms
    }
}

Alur yang kalian ikuti — clock → mode → kendalikan — berlaku untuk semua peripheral. Bedanya nanti hanya nama register dan cara mengkalkulasi bit.

Note

Untuk board lain, nama register dan alamatnya berbeda (STM32L4/F4 memakai RCC->AHB2ENR, ESP32 memakai GPIO.enable_w1ts, dan seterusnya). Yang penting bukan menghafal nama, tapi pola: baca memory map + register description di datasheet kalian, temukan bit yang tepat, lalu tulis pola yang sama.

Kesalahan Umum MCU Programming

  1. Lupa clock gate — tulis register tanpa efek; gejala paling umum di forum.
  2. Salah menghitung bit offset2*n untuk register 2-bit per pin; satu kesalahan posisi = pin yang salah nyala.
  3. MODER tidak di-clear dulu — nilai default bisa membuat pin berperilaku aneh; selalu &= ~ sebelum |=.
  4. Memberi 5V ke pin 3.3V — membakar pin/board; periksa level logika.
  5. Delay dengan for kosong tanpa volatile — kompiler bisa mengoptimasi loop jadi tak terbatas.

Penutup

Inti yang harus dibawa pulang:

  • Semua peripheral butuh clock gate aktif (RCC) sebelum dipakai.
  • Pohon clock: HSI/HSE → PLL → SysClk → AHB → APB; perhatikan batas tiap bus.
  • GPIO dikendalikan register: MODER (mode), OTYPER, PUPDR, IDR (baca), ODR/BSRR (tulis).
  • Pola universal: clock → mode → kendalikan.
  • Blink register-level penuh menyalakan LED tanpa HAL — bukti pemahaman hardware.

Di episode 5 selanjutnya kita memperluas kendali ke dunia luar: Peripherals UART/SPI/I2C, ADC, timer, dan PWM — protokol komunikasi antarchip, cara mengukur sinyal analog, dan menghasilkan timing presisi. Firmware kalian mulai "berbicara" dengan komponen lain!

Belajar Firmware Engineer - MCU Programming | Belajar Firmware Engineer