IoT

STM32 Bare Metal Programming: Register-Level, Linker Script & DMA

TOKEN

Program STM32 secara langsung ke register tanpa library HAL โ€” pelajari linker script, startup code, interrupt handler, DMA, dan ADC

1. Mengapa Bare Metal?

Bare metal programming berarti memprogram mikrokontroler tanpa library abstraksi seperti HAL atau Arduino framework. Kita berinteraksi langsung dengan hardware registers melalui pointer ke address yang spesifik. Ini memberikan kontrol penuh, binary yang sangat kecil, dan pemahaman mendalam tentang hardware.

AspekArduino/HALBare Metal
Binary size10-50 KB0.5-2 KB
Startup time~100 ms~1 ยตs
PredictabilityAbstraksi bisa mengejutkan100% prediktable
Pemahaman HWTingkat tinggiTingkat register
Kurva belajarMudahSulit
DebuggingSerial.printGDB + register view
โš™๏ธ
Bare Metal
Kontrol Total
  • โœ… Binary sangat kecil
  • โœ… Prediktable real-time
  • โœ… Tidak ada dependency
  • โŒ Sulit untuk pemula
  • โŒ Tidak portabel antar chip
๐Ÿ”ง
HAL / Arduino
Produktivitas Tinggi
  • โœ… Mudah dipelajari
  • โœ… Portabel antar chip
  • โœ… Library ecosystem besar
  • โŒ Binary lebih besar
  • โŒ Overhead abstraksi

2. Setup Toolchain ARM GCC

Bash
# 1. Install ARM GCC cross-compiler
# Linux/Mac:
sudo apt install gcc-arm-none-eabi libnewlib-arm-none-eabi
# Atau download dari: https://developer.arm.com/downloads/-/gnu-rm

# 2. Install OpenOCD untuk flashing/debugging
sudo apt install openocd
# Atau: https://github.com/openocd-org/openocd

# 3. Install GDB untuk ARM
arm-none-eabi-gdb --version

# 4. Verifikasi
arm-none-eabi-gcc --version
# arm-none-eabi-gcc (GNU Arm Embedded Toolchain 13.2)

# 5. Install ST-Link tools (untuk ST-Link debugger)
sudo apt install stlink-tools
# Atau: https://github.com/stlink-org/stlink

# 6. Install Make
sudo apt install make

Makefile untuk Bare Metal

Makefile
# Toolchain
CC      = arm-none-eabi-gcc
AS      = arm-none-eabi-as
LD      = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
OBJDUMP = arm-none-eabi-objdump
SIZE    = arm-none-eabi-size
GDB     = arm-none-eabi-gdb

# Target MCU: STM32F103C8T6 (Blue Pill)
TARGET  = stm32f103
CPU     = cortex-m3
FPU     = none
FLOAT   = soft

# Files
C_SRC   = src/main.c src/startup.c src/system.c
ASM_SRC = src/startup_stm32f103.s
LD_SCRIPT = linker/stm32f103c8.ld
TARGET_ELF = build/$(TARGET).elf
TARGET_BIN = build/$(TARGET).bin
TARGET_HEX = build/$(TARGET).hex

# Flags
CFLAGS  = -mcpu=$(CPU) -mthumb -mfloat-abi=$(FLOAT)
CFLAGS += -Wall -Werror -std=c11
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -Os -g
CFLAGS += -Iinclude
CFLAGS += -DSTM32F103xB

LDFLAGS = -T$(LD_SCRIPT) -Wl,--gc-sections
LDFLAGS += --specs=nano.specs --specs=nosys.specs
LDFLAGS += -mcpu=$(CPU) -mthumb -mfloat-abi=$(FLOAT)
LDFLAGS += -Wl,-Map=build/$(TARGET).map

.PHONY: all clean flash debug

all: $(TARGET_ELF) $(TARGET_BIN) $(TARGET_HEX)
	$(SIZE) $(TARGET_ELF)

build/%.o: src/%.c
	@mkdir -p build
	$(CC) $(CFLAGS) -c $< -o $@

$(TARGET_ELF): $(C_SRC:.c=.o)
	$(CC) $(LDFLAGS) $^ -o $@

$(TARGET_BIN): $(TARGET_ELF)
	$(OBJCOPY) -O binary $< $@

$(TARGET_HEX): $(TARGET_ELF)
	$(OBJCOPY) -O ihex $< $@

flash: $(TARGET_BIN)
	st-flash write $< 0x08000000

debug: $(TARGET_ELF)
	$(GDB) $< -ex "target remote :3333" -ex "monitor reset halt"

clean:
	rm -rf build/

3. Memory Map STM32

STM32 menggunakan arsitektur ARM Cortex-M yang memiliki memory map yang konsisten. Memahami memory map sangat penting untuk bare metal programming.

RegionAddressSizeDeskripsi
Flash0x0800_000064-128 KBProgram code
SRAM0x2000_000020 KBRAM untuk data
APB10x4000_0000-Low-speed peripherals
APB20x4001_0000-High-speed peripherals
AHB0x4002_0000-DMA, GPIO, RCC
Cortex-M Core0xE000_E000-NVIC, SysTick, SCB

4. Register-Level GPIO Programming

C โ€” include/stm32f103.h
#ifndef STM32F103_H
#define STM32F103_H

#include <stdint.h>

// ============ Peripheral Base Addresses ============
#define PERIPH_BASE       0x40000000UL
#define APB1_BASE         (PERIPH_BASE)
#define APB2_BASE         (PERIPH_BASE + 0x10000UL)
#define AHB_BASE          (PERIPH_BASE + 0x20000UL)

// ============ RCC (Reset & Clock Control) ============
#define RCC_BASE          (AHB_BASE + 0x1000UL)
typedef struct {
    volatile uint32_t CR;         // 0x00: Clock control
    volatile uint32_t CFGR;       // 0x04: Clock configuration
    volatile uint32_t CIR;        // 0x08: Clock interrupt
    volatile uint32_t APB2RSTR;   // 0x0C: APB2 reset
    volatile uint32_t APB1RSTR;   // 0x10: APB1 reset
    volatile uint32_t AHBENR;     // 0x14: AHB enable
    volatile uint32_t APB2ENR;    // 0x18: APB2 enable โ† PENTING
    volatile uint32_t APB1ENR;    // 0x1C: APB1 enable
} RCC_TypeDef;
#define RCC  ((RCC_TypeDef *)RCC_BASE)

// RCC APB2ENR bits
#define RCC_APB2ENR_IOPAEN  (1 << 2)   // GPIOA clock enable
#define RCC_APB2ENR_IOPBEN  (1 << 3)   // GPIOB clock enable
#define RCC_APB2ENR_IOPCEN  (1 << 4)   // GPIOC clock enable
#define RCC_APB2ENR_ADC1EN  (1 << 9)   // ADC1 clock enable
#define RCC_APB2ENR_SPI1EN  (1 << 12)  // SPI1 clock enable
#define RCC_APB2ENR_USART1EN (1 << 14) // USART1 clock enable

// ============ GPIO ============
#define GPIOA_BASE        (APB2_BASE + 0x0800UL)
#define GPIOB_BASE        (APB2_BASE + 0x0C00UL)
#define GPIOC_BASE        (APB2_BASE + 0x1000UL)

typedef struct {
    volatile uint32_t CRL;    // 0x00: Configuration low (pin 0-7)
    volatile uint32_t CRH;    // 0x04: Configuration high (pin 8-15)
    volatile uint32_t IDR;    // 0x08: Input data register
    volatile uint32_t ODR;    // 0x0C: Output data register
    volatile uint32_t BSRR;   // 0x10: Bit set/reset register
    volatile uint32_t BRR;    // 0x14: Bit reset register
    volatile uint32_t LCKR;   // 0x18: Lock register
} GPIO_TypeDef;

#define GPIOA  ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB  ((GPIO_TypeDef *)GPIOB_BASE)
#define GPIOC  ((GPIO_TypeDef *)GPIOC_BASE)

// ============ ADC ============
#define ADC1_BASE         (APB2_BASE + 0x2400UL)
typedef struct {
    volatile uint32_t SR;     // 0x00: Status
    volatile uint32_t CR1;    // 0x04: Control 1
    volatile uint32_t CR2;    // 0x08: Control 2
    volatile uint32_t SMPR1;  // 0x0C: Sample time 1
    volatile uint32_t SMPR2;  // 0x10: Sample time 2
    volatile uint32_t JOFR1;  // 0x14-0x20
    volatile uint32_t JOFR2;
    volatile uint32_t JOFR3;
    volatile uint32_t JOFR4;
    volatile uint32_t HTR;    // 0x24
    volatile uint32_t LTR;    // 0x28
    volatile uint32_t SQR1;   // 0x2C
    volatile uint32_t SQR2;   // 0x30
    volatile uint32_t SQR3;   // 0x34
    volatile uint32_t JSQR;   // 0x38
    volatile uint32_t JDR1;   // 0x3C-0x48
    volatile uint32_t JDR2;
    volatile uint32_t JDR3;
    volatile uint32_t JDR4;
    volatile uint32_t DR;     // 0x4C: Data register
} ADC_TypeDef;

#define ADC1  ((ADC_TypeDef *)ADC1_BASE)

// ============ NVIC ============
#define NVIC_BASE         (0xE000E100UL)
typedef struct {
    volatile uint32_t ISER[8];    // Interrupt Set Enable
    uint32_t RESERVED0[24];
    volatile uint32_t ICER[8];    // Interrupt Clear Enable
    uint32_t RESERVED1[24];
    volatile uint32_t ISPR[8];    // Interrupt Set Pending
    uint32_t RESERVED2[24];
    volatile uint32_t ICPR[8];    // Interrupt Clear Pending
} NVIC_TypeDef;
#define NVIC  ((NVIC_TypeDef *)NVIC_BASE)

#endif // STM32F103_H

Blink LED Tanpa HAL

C โ€” src/main.c (Blink)
#include "stm32f103.h"

// System clock: 8 MHz internal oscillator (HSI)
#define HSI_FREQ  8000000UL

static void delay(volatile uint32_t count) {
    while (count--) {
        __asm volatile("nop");
    }
}

void system_init(void) {
    // GPIOC clock enable (untuk LED PC13)
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
}

void gpio_init(void) {
    // PC13 = Output Push-Pull, 2 MHz
    // CRL register: pin 13 ada di CRH (pin 8-15)
    // Mode bits (0:1): 10 = Output 2 MHz
    // CNF bits (2:3):  00 = Push-pull output
    // Bit position: (13-8)*4 = 20

    // Clear bits untuk pin 13
    GPIOC->CRH &= ~(0xF << 20);
    // Set: Output push-pull, 2 MHz
    GPIOC->CRH |= (0x2 << 20);  // Mode=10, CNF=00
}

void led_on(void) {
    // BSRR: write 1 ke bit 13 = set HIGH (LED OFF untuk active-low PC13)
    // BRR:  write 1 ke bit 13 = set LOW  (LED ON untuk active-low PC13)
    GPIOC->BRR = (1 << 13);
}

void led_off(void) {
    GPIOC->BSRR = (1 << 13);
}

void led_toggle(void) {
    GPIOC->ODR ^= (1 << 13);
}

int main(void) {
    system_init();
    gpio_init();

    while (1) {
        led_toggle();
        delay(HSI_FREQ / 10);  // ~100ms @ 8 MHz
    }
}

5. Startup Code

ARM Assembly โ€” startup_stm32f103.s
/* STM32F103 Startup Code โ€” Bare Metal */

.syntax unified
.cpu cortex-m3
.thumb

/* ============ Vector Table ============ */
.section .isr_vector, "a"
.global g_pfnVectors

g_pfnVectors:
    .word _estack              /* 0x00: Initial stack pointer */
    .word Reset_Handler        /* 0x04: Reset */
    .word NMI_Handler          /* 0x08: NMI */
    .word HardFault_Handler    /* 0x0C: Hard Fault */
    .word MemManage_Handler    /* 0x10: MPU Fault */
    .word BusFault_Handler     /* 0x14: Bus Fault */
    .word UsageFault_Handler   /* 0x18: Usage Fault */
    .word 0                    /* 0x1C: Reserved */
    .word 0                    /* 0x20: Reserved */
    .word 0                    /* 0x24: Reserved */
    .word 0                    /* 0x28: Reserved */
    .word SVC_Handler          /* 0x2C: SVCall */
    .word DebugMon_Handler     /* 0x30: Debug Monitor */
    .word 0                    /* 0x34: Reserved */
    .word PendSV_Handler       /* 0x38: PendSV */
    .word SysTick_Handler      /* 0x3C: SysTick */
    /* External IRQs (0-67 for STM32F103) */
    .word WWDG_IRQHandler         /* IRQ 0 */
    .word PVD_IRQHandler          /* IRQ 1 */
    .word TAMPER_IRQHandler       /* IRQ 2 */
    .word RTC_IRQHandler          /* IRQ 3 */
    .word FLASH_IRQHandler        /* IRQ 4 */
    .word RCC_IRQHandler          /* IRQ 5 */
    .word EXTI0_IRQHandler        /* IRQ 6 */
    .word EXTI1_IRQHandler        /* IRQ 7 */
    .word EXTI2_IRQHandler        /* IRQ 8 */
    .word EXTI3_IRQHandler        /* IRQ 9 */
    .word EXTI4_IRQHandler        /* IRQ 10 */
    .word DMA1_Channel1_IRQHandler /* IRQ 11 */
    .word DMA1_Channel2_IRQHandler /* IRQ 12 */
    .word DMA1_Channel3_IRQHandler /* IRQ 13 */
    .word DMA1_Channel4_IRQHandler /* IRQ 14 */
    .word DMA1_Channel5_IRQHandler /* IRQ 15 */
    .word ADC1_2_IRQHandler       /* IRQ 18 */
    .word TIM2_IRQHandler         /* IRQ 28 */
    .word TIM3_IRQHandler         /* IRQ 29 */
    .word TIM4_IRQHandler         /* IRQ 30 */
    .word USART1_IRQHandler       /* IRQ 37 */
    .word USART2_IRQHandler       /* IRQ 38 */
    .word SPI1_IRQHandler         /* IRQ 35 */

/* ============ Reset Handler ============ */
.section .text.Reset_Handler
.global Reset_Handler
.type Reset_Handler, %function

Reset_Handler:
    /* Set stack pointer */
    ldr sp, =_estack

    /* Copy .data dari flash ke SRAM */
    ldr r0, =_sdata
    ldr r1, =_edata
    ldr r2, =_sidata
copy_data:
    cmp r0, r1
    bge zero_bss
    ldr r3, [r2], #4
    str r3, [r0], #4
    b copy_data

    /* Zero out .bss */
zero_bss:
    ldr r0, =_sbss
    ldr r1, =_ebss
    movs r2, #0
zero_loop:
    cmp r0, r1
    bge call_main
    str r2, [r0], #4
    b zero_loop

    /* Call main() */
call_main:
    bl main

    /* Infinite loop jika main return */
hang:
    b hang

/* ============ Default Handlers ============ */
.global Default_Handler
.type Default_Handler, %function
Default_Handler:
    b .

.weak NMI_Handler
.weak HardFault_Handler
.weak MemManage_Handler
.weak BusFault_Handler
.weak UsageFault_Handler
.weak SVC_Handler
.weak DebugMon_Handler
.weak PendSV_Handler
.weak SysTick_Handler
.weak EXTI0_IRQHandler
.weak TIM2_IRQHandler
.weak ADC1_2_IRQHandler
.weak DMA1_Channel1_IRQHandler
.weak USART1_IRQHandler

.set NMI_Handler, Default_Handler
.set HardFault_Handler, Default_Handler
.set MemManage_Handler, Default_Handler
.set BusFault_Handler, Default_Handler
.set UsageFault_Handler, Default_Handler
.set SVC_Handler, Default_Handler
.set DebugMon_Handler, Default_Handler
.set PendSV_Handler, Default_Handler
.set SysTick_Handler, Default_Handler
.set EXTI0_IRQHandler, Default_Handler
.set TIM2_IRQHandler, Default_Handler
.set ADC1_2_IRQHandler, Default_Handler
.set DMA1_Channel1_IRQHandler, Default_Handler
.set USART1_IRQHandler, Default_Handler

6. Linker Script (.ld)

Linker Script โ€” linker/stm32f103c8.ld
/* STM32F103C8T6 Linker Script */
/* 64KB Flash, 20KB SRAM */

MEMORY
{
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 64K
    SRAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}

_estack = ORIGIN(SRAM) + LENGTH(SRAM);

SECTIONS
{
    /* Vector table โ€” harus di awal flash */
    .isr_vector :
    {
        . = ALIGN(4);
        KEEP(*(.isr_vector))
        . = ALIGN(4);
    } > FLASH

    /* Code dan read-only data */
    .text :
    {
        . = ALIGN(4);
        *(.text)
        *(.text*)
        *(.rodata)
        *(.rodata*)
        . = ALIGN(4);
        _etext = .;
    } > FLASH

    /* Data initialized: disimpan di flash, di-copy ke SRAM */
    _sidata = LOADADDR(.data);
    .data :
    {
        . = ALIGN(4);
        _sdata = .;
        *(.data)
        *(.data*)
        . = ALIGN(4);
        _edata = .;
    } > SRAM AT> FLASH

    /* BSS: zero-initialized data */
    .bss :
    {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } > SRAM

    /* Heap & Stack info */
    .heap (NOLOAD) :
    {
        . = ALIGN(8);
        _end = .;
        . = . + 0x1000;  /* 4KB heap */
        . = ALIGN(8);
    } > SRAM

    /DISCARD/ :
    {
        *(.ARM.exidx*)
        *(.ARM.extab*)
    }
}

7. Interrupt Handling (NVIC)

C โ€” Interrupt Example
#include "stm32f103.h"

// EXTI (External Interrupt) registers
#define EXTI_BASE   (APB2_BASE + 0x0400UL)
#define AFIO_BASE   (APB2_BASE + 0x0000UL)

typedef struct {
    volatile uint32_t IMR;    // Interrupt mask
    volatile uint32_t EMR;    // Event mask
    volatile uint32_t RTSR;   // Rising trigger select
    volatile uint32_t FTSR;   // Falling trigger select
    volatile uint32_t SWIER;  // Software interrupt event
    volatile uint32_t PR;     // Pending register
} EXTI_TypeDef;

typedef struct {
    volatile uint32_t EVCR;
    volatile uint32_t MAPR;
    volatile uint32_t EXTICR[4];
} AFIO_TypeDef;

#define EXTI  ((EXTI_TypeDef *)EXTI_BASE)
#define AFIO  ((AFIO_TypeDef *)AFIO_BASE)

// Setup EXT0 interrupt pada PA0 (tombol)
void setup_exti0(void) {
    // 1. Enable GPIOA dan AFIO clock
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | (1 << 0);  // AFIO

    // 2. Set PA0 as input with pull-up
    GPIOA->CRL &= ~(0xF << 0);     // Clear PA0 config
    GPIOA->CRL |= (0x8 << 0);       // Input with pull-up
    GPIOA->ODR |= (1 << 0);          // Pull-up

    // 3. Map EXTI0 to PA0
    AFIO->EXTICR[0] &= ~(0xF << 0); // EXTI0 = PA0

    // 4. Configure EXTI0: falling edge trigger
    EXTI->IMR  |= (1 << 0);   // Unmask EXTI0
    EXTI->FTSR |= (1 << 0);   // Falling edge
    EXTI->RTSR &= ~(1 << 0);  // Disable rising edge

    // 5. Enable NVIC IRQ untuk EXTI0 (IRQ 6)
    NVIC->ISER[6 / 32] = (1 << (6 % 32));
}

// Interrupt handler โ€” nama harus sesuai vector table
void EXTI0_IRQHandler(void) {
    if (EXTI->PR & (1 << 0)) {
        EXTI->PR = (1 << 0);  // Clear pending (write 1 to clear)
        GPIOC->ODR ^= (1 << 13);  // Toggle LED
    }
}

8. DMA: Direct Memory Access

DMA memungkinkan transfer data antara peripheral dan memory tanpa campur tangan CPU. Ini sangat efisien untuk ADC sampling, UART transfer, dan SPI communication.

C โ€” DMA untuk ADC
#include "stm32f103.h"

// DMA1 registers
#define DMA1_BASE  (AHB_BASE + 0x0000UL)

typedef struct {
    volatile uint32_t CCR;    // Channel config
    volatile uint32_t CNDTR;  // Number of data
    volatile uint32_t CPAR;   // Peripheral address
    volatile uint32_t CMAR;   // Memory address
} DMA_Channel_TypeDef;

typedef struct {
    volatile uint32_t ISR;    // Interrupt status
    volatile uint32_t IFCR;   // Interrupt flag clear
} DMA_TypeDef;

#define DMA1         ((DMA_TypeDef *)DMA1_BASE)
#define DMA1_CH1     ((DMA_Channel_TypeDef *)(DMA1_BASE + 0x08))

// Buffer untuk ADC data via DMA
volatile uint16_t adc_buffer[100];  // 100 samples

void setup_adc_dma(void) {
    // 1. Enable clocks
    RCC->AHBENR  |= (1 << 0);      // DMA1 clock
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN;

    // 2. Setup PA0 sebagai analog input
    GPIOA->CRL &= ~(0xF << 0);  // Analog mode

    // 3. Configure ADC1
    ADC1->CR2  = 0;               // Reset
    ADC1->SQR3 = 0;               // Channel 0
    ADC1->SMPR2 = (0b111 << 0);  // 239.5 cycles sample time
    ADC1->CR1  = (1 << 8);       // SCAN mode
    ADC1->CR2  = (1 << 1)        // CONT: Continuous conversion
               | (1 << 8)        // DMA: Enable DMA
               | (1 << 3);       // RSTCAL: Reset calibration

    // 4. Calibrate ADC
    ADC1->CR2 |= (1 << 2);  // CAL
    while (ADC1->CR2 & (1 << 2));  // Tunggu selesai

    // 5. Configure DMA1 Channel 1 (ADC1)
    DMA1_CH1->CPAR  = (uint32_t)&(ADC1->DR);  // Source: ADC data register
    DMA1_CH1->CMAR  = (uint32_t)adc_buffer;     // Dest: RAM buffer
    DMA1_CH1->CNDTR = 100;                       // 100 transfers
    DMA1_CH1->CCR   = (0 << 10)   // MSIZE: 16-bit
                    | (0 << 8)      // PSIZE: 16-bit
                    | (1 << 7)      // MINC: Memory increment
                    | (0 << 6)      // PINC: No peripheral increment
                    | (1 << 5)      // CIRC: Circular mode
                    | (0 << 4)      // DIR: Peripheral to memory
                    | (1 << 0);     // EN: Enable

    // 6. Start ADC
    ADC1->CR2 |= (1 << 0);  // ADON: Power on
    ADC1->CR2 |= (1 << 22); // SWSTART: Start conversion
}

int main(void) {
    setup_adc_dma();

    while (1) {
        // adc_buffer selalu ter-update oleh DMA!
        // CPU bisa melakukan hal lain
        uint32_t sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += adc_buffer[i];
        }
        uint16_t avg = sum / 100;
        float voltage = (avg * 3.3f) / 4096.0f;

        // Gunakan voltage...
        (void)voltage;
    }
}

9. ADC: Analog to Digital Converter

STM32F103 memiliki ADC 12-bit dengan hingga 10 channel. Pengukuran analog sangat penting untuk sensor suhu, potensiometer, dan sensor analog lainnya.

ParameterNilaiPenjelasan
Resolusi12-bit (0-4095)Bisa di-set 6/8/10/12 bit
Vref3.3V (typical)Reference voltage
Sampling Time1.5 - 239.5 cyclesLebih lama = lebih akurat
Conversion Time1 ยตs minimumSample time + 12.5 cycles
Channels10 externalPA0-PA7, PB0-PB1

10. Quiz Pemahaman

Pertanyaan 1: Mengapa startup code perlu copy .data dari flash ke SRAM?

a) SRAM lebih cepat dari flash
b) Karena .data (variabel ter-inisialisasi) harus di SRAM, tapi aslinya tersimpan di flash
c) Untuk menghemat flash
d) Tidak perlu, itu optional

Pertanyaan 2: Fungsi BSRR register pada GPIO STM32?

a) Mengatur konfigurasi pin
b) Set atau reset bit GPIO secara atomic
c) Membaca status input
d) Mengatur clock

Pertanyaan 3: Keunggulan DMA dibanding CPU polling untuk ADC?

a) DMA lebih akurat
b) DMA membebaskan CPU untuk tugas lain
c) DMA mengkonsumsi lebih sedikit daya
d) DMA tidak memerlukan RAM

Pertanyaan 4: Di address berapa vector table STM32 disimpan?

a) 0x2000_0000
b) 0x4000_0000
c) 0x0800_0000
d) 0xE000_E000

Pertanyaan 5: Resolusi ADC 12-bit STM32 memiliki range berapa?

a) 0-255
b) 0-1023
c) 0-4095
d) 0-65535
โ† SebelumnyaRPi Kubernetes Selanjutnya โ†’Zigbee vs Thread vs Matter
๐Ÿ” Zoom
100%
๐ŸŽจ Tema