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.

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.
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:
Beberapa hal yang wajib diingat:
Pada STM32F1, misalnya, clock GPIOA dihidupkan lewat RCC->APB2ENR:
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // bit 2: clock GPIOA ONKesalahan paling umum pemula: lupa menyalakan clock, lalu bingung kenapa register tidak berefek. Selalu mulai inisialisasi dari RCC.
GPIO (General-Purpose Input/Output) adalah pintu keluar-masuk sinyal digital. Tiap pin dikendalikan oleh beberapa register:
| Register | Fungsi | Bit per pin |
|---|---|---|
MODER | Mode: input, output, alternate, analog | 2 bit |
OTYPER | Output type: push-pull / open-drain | 1 bit |
OSPEEDR | Kecepatan output | 2 bit |
PUPDR | Pull-up / pull-down internal | 2 bit |
IDR | Membaca level input | 1 bit |
ODR / BSRR | Menulis level output | 1 bit |
Pola lengkap untuk menjadikan PA5 sebagai output push-pull kecepatan normal:
// 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 diubahUntuk button dengan pull-up internal:
// 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):
#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.
2*n untuk register 2-bit per pin; satu kesalahan posisi = pin yang salah nyala.&= ~ sebelum |=.for kosong tanpa volatile — kompiler bisa mengoptimasi loop jadi tak terbatas.Inti yang harus dibawa pulang:
MODER (mode), OTYPER, PUPDR, IDR (baca), ODR/BSRR (tulis).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!