Trong phát triển STM32, file khởi động được cung cấp bởi ST offic chính cho toolchain GCC được viết bằng assembler ARM. Bài viết này sẽ phân tích cấu trúc của file đó và thực hiện lại nó bằng ngôn ngữ C.
Chúng ta sẽ lấy ví dụ từ dự án STM32F103C8T6 do ST cung cấp, bao gồm file khởi động startup_stm32f10x_md.s và script liên kết stm32_flash.ld. File khởi động này sử dụng assembler ARM để định nghĩa bảng vector ngoại lệ Cortex-M3, cũng như thực hiện hàm Reset_Handler bằng assembler. Script liên kết quy định cách liên kết chương trình và phân bổ vùng nhớ.
Phần mã nguồn C hoàn chỉnh cho file khởi động STM32F103 MD được tìm thấy ở phần phụ lục.
Phân tích script liên kết
Script liên kết nguyên bản được tìm thấy ở phần phụ lục STM32F103 MD.
Hàm khởi động
Script liên kết bắt đầu bằng việc khai báo hàm⼊⼝点, hay nói cách khác là hàm đầu tiên được gọi sau khi hệ thống khởi động: Reset_Handler.
/* Điểm⼊⼝ */
ENTRY(Reset_Handler)
Phân bổ vùng nhớ
Sau đó, script quy định vùng nhớ và cách sử dụng:
/* Khai báo vùng nhớ */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
Thông tin về vùng nhớ như sau:
- Vùng RAM, có thể đọc (r), viết (w) và chạy (x), kích thước 20K, bắt đầu từ địa chỉ 0x20000000.
- Vùng FLASH, có thể đọc (r) và chạy (x), kích thước 64K, bắt đầu từ địa chỉ 0x8000000.
Đối với các model STM32F103 khác nhau, kích thước RAM và FLASH có thể thay đổi, do đó cần điều chỉnh các giá trị này để phù hợp với bộ vi xử lý đang sử dụng.
Cấu hình Heap và Stack
Phần tiếp theo là cấu hình stack:
/* Địa chỉ cao nhất của vùng nhớ stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
/* Tạo lỗi liên kết nếu heap và stack không đủ lớn trong RAM */
_Min_Heap_Size = 0x0; /* Kích thước yêu cầu của heap */
_Min_Stack_Size = 0x400; /* Kích thước yêu cầu của stack */
Biến _estack xác định điểm bắt đầu của stack, do stack phát triển từ cao xuống thấp. Nếu không sử dụng malloc, có thể設置 _Min_Heap_Size thành 0.
Quy định các đoạn mã
SECTIONS
{
/* ...... */
}
Cấu trúc SECTIONS trong script liên kết quy định cách phân bổ các đoạn mã. Mỗi đoạn mã (section) có một特성 riêng, như mã nguồn, dữ liệu đã khởi tạo, dữ liệu未 khởi tạo, vv.
Các đoạn mã thông dụng bao gồm .text .data .bss .rodata:
.textchứa mã nguồn nhị phân, các hàm đã biên dịch, có thể đọc và chạy nhưng không thể viết..datachứa các biến toàn cục đã khởi tạo có giá trị khác 0, có thể đọc và viết nhưng không chạy..bsschứa các biến toàn cục未 khởi tạo, sẽ được khởi tạo thành 0 khi chạy, có thể đọc và viết..rodatachứa các dữ liệu chỉ đọc như chuỗi, biếnconst, không thể chạy.
Trong GCC, chúng ta có thể chỉ định đoạn mã cho một biến hoặc hàm bằng cách sử dụng __attribute__((section("xxx"))):
__attribute__((section(".data"))) int a = 1;
Từ C23 trở lên, có thể sử dụng [[__attr]] để chỉ định đoạn mã:
[[gnu::section(".data")]] int a = 1;
Phân tích file khởi động STM32F103 MD
File khởi động STM32F103 MD thực hiện ba chức năng chính: định nghĩa bảng vector ngoại lệ, hiện thực hàm Reset_Handler, và cung cấp các hàm xử lý ngoại lệ mặc định cho các ngoại lệ chưa được xử lý.
Phân tích mã nguồn
Below là phân tích mã nguồn assembler và cách chuyển đổi sang C.
Khai báo biến toàn cục
.global g_pfnVectors
.global Default_Handler
Trong C, tương đương với việc khai báo các biến toàn cục:
extern uint32_t g_pfnVectors[];
extern void Default_Handler(void);
Định nghĩa các đoạn mã
/* Copy data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
Trong C, các đoạn mã này có thể được hiện thực như sau:
static void CopyDataInit(void)
{
const uint32_t *src = (const uint32_t *)_sidata;
const uint32_t *data_end = (const uint32_t *)_edata;
uint32_t *data_begin = (uint32_t *)_sdata;
while (data_begin < data_end)
{
*data_begin = *src;
data_begin++;
src++;
}
}
static void FillZerobss(void)
{
const uint32_t *bss_end = (const uint32_t *)_ebss;
uint32_t *bss_begin = (uint32_t *)_sbss;
while (bss_begin < bss_end)
{
*bss_begin = 0x00;
bss_begin++;
}
}
void Reset_Handler(void)
{
CopyDataInit();
FillZerobss();
SystemInit();
__libc_init_array();
main();
while(1){} // Vòng lặp vô hạn sau khi main() kết thúc
}
Bảng vector ngoại lệ
g_pfnVectors:
.word _estack
.word Reset_Handler
// ...
.word BootRAM
Trong C, tương đương với một mảng các con trỏ hàm:
typedef void (*InterruptHandlerPtr_TypeDef)(void);
__attribute__((used, section(".isr_vector"))) const InterruptHandlerPtr_TypeDef g_pfnVectors[] = {
/* Pointer to the top of the stack */
(InterruptHandlerPtr_TypeDef)(uintptr_t)_estack,
/* Các ngoại lệ hệ thống */
Reset_Handler,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
NULL,
NULL,
NULL,
NULL,
SVC_Handler,
DebugMon_Handler,
NULL,
PendSV_Handler,
SysTick_Handler,
/* Các ngoại lệ ngoại vi */
WWDG_IRQHandler,
PVD_IRQHandler,
TAMPER_IRQHandler,
RTC_IRQHandler,
FLASH_IRQHandler,
RCC_IRQHandler,
EXTI0_IRQHandler,
EXTI1_IRQHandler,
EXTI2_IRQHandler,
EXTI3_IRQHandler,
EXTI4_IRQHandler,
DMA1_Channel1_IRQHandler,
DMA1_Channel2_IRQHandler,
DMA1_Channel3_IRQHandler,
DMA1_Channel4_IRQHandler,
DMA1_Channel5_IRQHandler,
DMA1_Channel6_IRQHandler,
DMA1_Channel7_IRQHandler,
ADC1_2_IRQHandler,
USB_HP_CAN1_TX_IRQHandler,
USB_LP_CAN1_RX0_IRQHandler,
CAN1_RX1_IRQHandler,
CAN1_SCE_IRQHandler,
EXTI9_5_IRQHandler,
TIM1_BRK_IRQHandler,
TIM1_UP_IRQHandler,
TIM1_TRG_COM_IRQHandler,
TIM1_CC_IRQHandler,
TIM2_IRQHandler,
TIM3_IRQHandler,
TIM4_IRQHandler,
I2C1_EV_IRQHandler,
I2C1_ER_IRQHandler,
I2C2_EV_IRQHandler,
I2C2_ER_IRQHandler,
SPI1_IRQHandler,
SPI2_IRQHandler,
USART1_IRQHandler,
USART2_IRQHandler,
USART3_IRQHandler,
EXTI15_10_IRQHandler,
RTC_Alarm_IRQHandler,
USBWakeUp_IRQHandler,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
(InterruptHandlerPtr_TypeDef)BootRAM,
};
Hàm xử lý ngoại lệ mặc định
Default_Handler:
Infinite_Loop:
b Infinite_Loop
Trong C, hàm này được hiện thực như một vòng lặp vô hạn:
void Default_Handler(void)
{
while (1)
{
/* Vòng lặp vô hạn */
}
}
Phụ lục
STM32F103 MD C startup file
#include <stddef.h>
#include <stdint.h>
/* Các biến toàn cục được khai báo trong script liên kết */
extern uint8_t _estack[]; /** Top of Stack Pointer */
extern uint8_t _sidata[]; /**< Địa chỉ bắt đầu của dữ liệu khởi tạo trong FLASH */
extern uint8_t _sdata[]; /**< Địa chỉ bắt đầu của dữ liệu đã khởi tạo trong RAM */
extern uint8_t _edata[]; /**< Địa chỉ kết thúc của dữ liệu đã khởi tạo trong RAM */
extern uint8_t _sbss[]; /**< Địa chỉ bắt đầu của dữ liệu未 khởi tạo trong RAM */
extern uint8_t _ebss[]; /**< Địa chỉ kết thúc của dữ liệu未 khởi tạo trong RAM */
/** Giá trị đặc biệt cho chế độ boot từ RAM */
#define BootRAM 0xF108F85F
/** Định nghĩa loại con trỏ hàm xử lý ngoại lệ */
typedef void (*InterruptHandlerPtr_TypeDef)(void);
/* Khai báo các hàm.extern */
extern void SystemInit(void); /**< Định nghĩa trong system_stm32f1xx.c */
extern int main(void); /**< Định nghĩa trong main.c */
extern void __libc_init_array(void); /**< Hàm khởi tạo thư viện Newlib */
/* Prototype các hàm */
void Default_Handler(void);
__attribute__((weak)) void Reset_Handler(void); /**< Hàm reset sẽ không trả về */
/* Cung cấp các hàm xử lý ngoại lệ mặc định */
__attribute__((weak, alias("Default_Handler"))) void NMI_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void HardFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void MemManage_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void BusFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void UsageFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void SVC_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void DebugMon_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void PendSV_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void SysTick_Handler(void);
/* Các handler ngoại vi */
__attribute__((weak, alias("Default_Handler"))) void WWDG_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void PVD_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TAMPER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RTC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void FLASH_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RCC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI0_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel5_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel6_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel7_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void ADC1_2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USB_HP_CAN1_TX_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USB_LP_CAN1_RX0_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void CAN1_RX1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void CAN1_SCE_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI9_5_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_BRK_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_UP_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_TRG_COM_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_CC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C1_EV_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C1_ER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C2_EV_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C2_ER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void SPI1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void SPI2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI15_10_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RTC_Alarm_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USBWakeUp_IRQHandler(void);
/* Vector Table */
__attribute__((used, section(".isr_vector"))) const InterruptHandlerPtr_TypeDef g_pfnVectors[] = {
/* Pointer to the top of the stack */
(InterruptHandlerPtr_TypeDef)(uintptr_t)_estack,
/* Các ngoại lệ hệ thống */
Reset_Handler,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
NULL,
NULL,
NULL,
NULL,
SVC_Handler,
DebugMon_Handler,
NULL,
PendSV_Handler,
SysTick_Handler,
/* Các ngoại lệ ngoại vi */
WWDG_IRQHandler,
PVD_IRQHandler,
TAMPER_IRQHandler,
RTC_IRQHandler,
FLASH_IRQHandler,
RCC_IRQHandler,
EXTI0_IRQHandler,
EXTI1_IRQHandler,
EXTI2_IRQHandler,
EXTI3_IRQHandler,
EXTI4_IRQHandler,
DMA1_Channel1_IRQHandler,
DMA1_Channel2_IRQHandler,
DMA1_Channel3_IRQHandler,
DMA1_Channel4_IRQHandler,
DMA1_Channel5_IRQHandler,
DMA1_Channel6_IRQHandler,
DMA1_Channel7_IRQHandler,
ADC1_2_IRQHandler,
USB_HP_CAN1_TX_IRQHandler,
USB_LP_CAN1_RX0_IRQHandler,
CAN1_RX1_IRQHandler,
CAN1_SCE_IRQHandler,
EXTI9_5_IRQHandler,
TIM1_BRK_IRQHandler,
TIM1_UP_IRQHandler,
TIM1_TRG_COM_IRQHandler,
TIM1_CC_IRQHandler,
TIM2_IRQHandler,
TIM3_IRQHandler,
TIM4_IRQHandler,
I2C1_EV_IRQHandler,
I2C1_ER_IRQHandler,
I2C2_EV_IRQHandler,
I2C2_ER_IRQHandler,
SPI1_IRQHandler,
SPI2_IRQHandler,
USART1_IRQHandler,
USART2_IRQHandler,
USART3_IRQHandler,
EXTI15_10_IRQHandler,
RTC_Alarm_IRQHandler,
USBWakeUp_IRQHandler,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
(InterruptHandlerPtr_TypeDef)BootRAM,
};
STM32F103 MD script liên kết
/* Entry Point */
ENTRY(Reset_Handler)
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.ARM.attributes : { *(.ARM.attributes) } > FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
STM32F103 MD startup file
/**
******************************************************************************
* @file startup_stm32f10x_md.s
* @author MCD Application Team
* @version V3.5.1
* @date 08-September-2021
* @brief Vector table for STM32F10x Medium Density Devices using Atollic toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Configure the clock system
* - Jumps to main in the C library (which eventually
* calls main()).
* @param None
* @retval : None
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* Copy data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief Hàm xử lý ngoại lệ mặc định.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* Bảng vector ngoại lệ tối thiểu cho Cortex M3. Ghi chú rằng các cấu trúc phù hợp
* phải được đặt để đảm bảo rằng nó kết thúc ở địa chỉ vật lý 0x00000000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* @0x108. Cho các thiết bị STM32F10x Medium Density boot từ RAM */
/*******************************************************************************
*
* Cung cấp các hàm xử lý ngoại lệ mặc định cho các ngoại lệ chưa được xử lý.
* Do chúng được khai báo là weak, bất kỳ hàm nào có cùng tên sẽ override các định nghĩa này.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****/