Startup Code STM32: Reset Handler, Vector Table và những gì xảy ra trước main()
Giải thích startup code STM32: vector table, reset handler, MSP, copy .data, zero .bss - những gì firmware phải làm trước khi gọi main().
Mỗi lần STM32 reset - dù là power-on, watchdog, hay bạn nhấn nút RESET - CPU không nhảy thẳng vào main(). Nó đọc từ một địa chỉ cố định, tìm vector table, rồi nhảy vào reset handler. Chỉ sau khi reset handler làm xong công việc chuẩn bị, main() mới được gọi.
Hiểu cái chuỗi này giúp debug được những lỗi “lạ nhất” - firmware bị crash trước khi main() chạy, biến global bị sai, bootloader không jump được vào application.
Vector Table là gì?
Vector table là một mảng các địa chỉ (pointer) nằm ở đầu Flash, bắt đầu từ 0x08000000 trên STM32.
/* Cấu trúc vector table - simplified */
uint32_t VectorTable[] = {
(uint32_t)&_estack, /* [0] MSP - giá trị khởi tạo Stack Pointer */
(uint32_t)Reset_Handler, /* [1] Reset Vector - địa chỉ reset handler */
(uint32_t)NMI_Handler, /* [2] NMI */
(uint32_t)HardFault_Handler, /* [3] HardFault */
/* ... các exception và interrupt handler khác ... */
(uint32_t)SysTick_Handler, /* [15] SysTick */
(uint32_t)WWDG_IRQHandler, /* [16] Peripheral interrupt 0 */
/* ... */
};
Hai entry đầu tiên đặc biệt quan trọng:
- Entry [0] - không phải địa chỉ hàm, mà là giá trị khởi tạo của Main Stack Pointer (MSP). CPU load giá trị này vào register SP ngay khi reset.
- Entry [1] - địa chỉ của Reset Handler - hàm đầu tiên CPU nhảy vào.
Chuỗi khởi động từ reset đến main()
CPU reset
CPU đọc 0x08000000 → load MSP. Đọc 0x08000004 → nhảy vào Reset_Handler.
Copy .data Flash → RAM
Reset handler copy vùng initialized data từ LMA (Flash) sang VMA (RAM).
Zero-fill .bss
Reset handler zero-fill toàn bộ section .bss trong RAM.
SystemInit()
Cấu hình clock, PLL, flash wait state. Gọi trước main().
main()
Application code bắt đầu chạy với môi trường C đã sẵn sàng.
Reset Handler - assembly + C
File startup_stm32g0xx.s (tạo bởi CubeMX) thực chất làm rất ít:
Reset_Handler:
/* 1. Nếu có FPU, enable Coprocessor Access Register */
/* 2. Copy .data từ Flash sang RAM */
ldr r0, =_sdata /* VMA start */
ldr r1, =_edata /* VMA end */
ldr r2, =_sidata /* LMA start (nguồn trong Flash) */
copy_loop:
cmp r0, r1
ittt lt
ldrlt r3, [r2], #4
strlt r3, [r0], #4
blt copy_loop
/* 3. Zero-fill .bss */
ldr r0, =_sbss
ldr r1, =_ebss
mov r2, #0
zero_loop:
cmp r0, r1
itt lt
strlt r2, [r0], #4
blt zero_loop
/* 4. Gọi SystemInit() */
bl SystemInit
/* 5. Gọi main() */
bl main
/* 6. Nếu main() return - vòng lặp vô tận */
infinite_loop:
b infinite_loop
Đây là lý do biến global int x = 5; có đúng giá trị khi main() bắt đầu - bước 2 đã copy từ Flash sang RAM. Và lý do int y; bằng 0 - bước 3 đã zero-fill.
MSP - Stack Pointer được khởi tạo ở đâu?
Entry [0] của vector table là giá trị nạp vào MSP. Giá trị này thường là địa chỉ cuối RAM (stack grows down trên Cortex-M):
/* Trong linker script */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* 0x20000000 + 144K = 0x20024000 */
/* Trong vector table */
uint32_t VectorTable[] = {
(uint32_t)&_estack, /* MSP = 0x20024000 */
...
};
Nếu giá trị này sai (ví dụ linker script khai báo sai RAM LENGTH), CPU vẫn khởi động nhưng stack sẽ overlap với data - dẫn đến corruption khó debug.
VTOR - Vector Table Offset Register
Mặc định, CPU tìm vector table tại 0x00000000 - được map tới 0x08000000 (Flash) qua BOOT pin hoặc alias.
VTOR (Vector Table Offset Register) cho phép đặt vector table ở vị trí khác. Đây là cơ chế quan trọng khi làm bootloader:
/* Application cần relocate vector table về địa chỉ của mình */
#define APP_BASE_ADDRESS 0x08010000 /* Application bắt đầu tại đây */
SCB->VTOR = APP_BASE_ADDRESS;
/* Từ giờ, CPU tìm vector table tại 0x08010000, không phải 0x08000000 */
Nếu bootloader jump vào application mà không set VTOR, application sẽ dùng vector table của bootloader - interrupt handler sẽ nhảy sai, crash ngay khi có interrupt đầu tiên.
| Mục | Giá trị | Ghi chú |
|---|---|---|
| 0x08000000 | Entry [0]: MSP initial value | CPU load vào SP register. Phải là địa chỉ hợp lệ trong RAM. |
| 0x08000004 | Entry [1]: Reset Handler address | CPU nhảy vào đây. Bit 0 = 1 (Thumb mode flag, không phải địa chỉ thật). |
| 0x08000008+ | Exception và interrupt handlers | NMI, HardFault, MemManage, BusFault, UsageFault, SysTick, peripheral IRQ. |
Debug: firmware crash trước main()
Nếu firmware crash mà breakpoint tại main() chưa kịp hit:
Checklist debug crash trước main()
Liên quan đến bootloader
Khi viết bootloader, hai thứ phải làm trước khi jump sang application:
void JumpToApplication(uint32_t app_address) {
/* 1. Tắt tất cả interrupt đang pending */
__disable_irq();
/* 2. Reset peripheral đang dùng nếu cần */
/* ... deinit UART, DMA, ... */
/* 3. Set VTOR về vector table của application */
SCB->VTOR = app_address;
/* 4. Load MSP từ entry [0] của application vector table */
__set_MSP(*(uint32_t*)app_address);
/* 5. Lấy Reset Handler address từ entry [1] */
typedef void (*FuncPtr)(void);
FuncPtr app_reset = (FuncPtr)(*(uint32_t*)(app_address + 4));
/* 6. Jump */
app_reset();
}
Chi tiết về bootloader, jump sequence và OTA update sẽ có trong bài blog riêng.
Bài liên quan
- Flash, EEPROM và RAM khác nhau như thế nào?
- Linker Script STM32: MEMORY, sections và LMA/VMA
- Reset Vector và Bootloader trên Cortex-M
Tài liệu tham khảo
- ARM Cortex-M0+ Technical Reference Manual - Vector Table, VTOR, startup sequence
- STM32G0B1 Reference Manual RM0444
- STM32CubeG0 startup file
Thấy nội dung này hữu ích?
Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
Reset Vector và Bootloader trên Cortex-M: VTOR, MSP và jump sequence
Reset vector là gì, VTOR hoạt động ra sao, và chuỗi bước cần thiết để bootloader jump đúng cách vào application - tránh crash sau khi có interrupt đầu tiên.
Flash, EEPROM và RAM khác nhau như thế nào?
Giải thích nguyên lý hoạt động của Flash, EEPROM và RAM.
Flash Operations STM32: Erase, Write, Polling và tại sao program đứng
Cách thao tác Flash STM32 qua HAL: unlock, erase, write, polling vs interrupt, và nguyên nhân program freeze khi xóa Flash.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.