STM32F103 MCU 上电启动流程分析实现
STM32F10x上电启动流程概述
STM32F10x上电后执行的第一条指令是存储在ROM中的,这部分ROM通常被称为系统存储器(System Memory)或引导存储器(Boot ROM)。这个区域包含了启动代码(Boot Code),其主要任务是初始化微控制器的基本功能,并且决定从哪里加载程序来执行。
系统存储器中的启动代码会执行以下操作:
- 电源和时钟系统初始化:设置内部时钟系统,确保微控制器以正确的频率运行。
- 外设初始化:对必要的外设进行基本配置,例如GPIO、复位外设等。
- 启动模式选择:根据BOOT0和BOOT1引脚的状态以及其他启动配置选项(如启动模式选择引脚),决定是从内部Flash、外部存储器还是通过其他接口(如串行通信)加载程序。
- 跳转到主程序:一旦系统初始化完成,启动代码会跳转到主程序的入口点,这个入口点通常是内部Flash中的中断向量表的起始地址。
若BOOT0和BOOT1引脚被配置为从系统存储器启动,那么启动代码会从系统存储器的固定地址(通常是0x1FFF0000)开始执行。
注:系统存储器区域是只读的,它在微控制器出厂时被编程,并且通常不会被用户修改。这个区域的代码是微控制器正常启动和运行的关键部分。
若BOOT0和BOOT1引脚被配置为从内部Flash启动,那么它会跳转到内部Flash的起始地址(通常是0x08000000)去执行第一条指令。
当调到主程序执行时,默认使用的是STM32F10x自带的时钟源(HSI:高速内部时钟,由内部RC振荡器产生),然而 HSI 精度较差,对时钟频率精度要求较高的场合,需要切换精度较高的高速外部时钟(HSE:高速外部时钟,由外部晶振或时钟源提供,常见的频率为8MHz)。
以下对HSE的时钟配置进行说明
HSE 时钟配置
当使用外部晶振(以8M晶振为例)作为时钟源时,对应的STM32F10x的时钟树配置如下图所示
主要由RCC_CR和RCC_CFGR寄存器进行控制
代码实现
主程序中断向量表实现
#include <stdint.h>
#define SRAM_START_ADDR (0x20000000U)
#define SRAM_SIZE (64U * 1024U)
#define SRAM_END_ADDR (SRAM_START_ADDR + SRAM_SIZE)
#define STACK_INIT_ADDR (SRAM_END_ADDR)
#define ISR_EXCEPTION_NUM 16
#define ISR_STM32_SPECIFIC_NUM 60
#define ISR_VECTOR_SIZE (ISR_EXCEPTION_NUM + ISR_STM32_SPECIFIC_NUM)
void reset_handler(void);
void default_handler(void);
// Cortex-M system exceptions
void nmi_handler(void) __attribute__((weak, alias("default_handler")));
void hard_fault_handler(void) __attribute__((weak, alias("default_handler")));
void mem_manage_handler(void) __attribute__((weak, alias("default_handler")));
void bus_fault_handler(void) __attribute__((weak, alias("default_handler")));
void usage_fault_handler(void) __attribute__((weak, alias("default_handler")));
void svc_handler(void) __attribute__((weak, alias("default_handler")));
void debug_mon_handler(void) __attribute__((weak, alias("default_handler")));
void pendsv_handler(void) __attribute__((weak, alias("default_handler")));
void systick_handler(void) __attribute__((weak, alias("default_handler")));
// STM32F103ZET interrupt handlers
void wwdg_handler(void) __attribute__((weak, alias("default_handler")));
void pvd_handler(void) __attribute__((weak, alias("default_handler")));
void tamper_handler(void) __attribute__((weak, alias("default_handler")));
void rtc_handler(void) __attribute__((weak, alias("default_handler")));
void flash_handler(void) __attribute__((weak, alias("default_handler")));
void rcc_handler(void) __attribute__((weak, alias("default_handler")));
void exti0_handler(void) __attribute__((weak, alias("default_handler")));
void exti1_handler(void) __attribute__((weak, alias("default_handler")));
void exti2_handler(void) __attribute__((weak, alias("default_handler")));
void exti3_handler(void) __attribute__((weak, alias("default_handler")));
void exti4_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel1_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel2_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel3_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel4_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel5_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel6_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel7_handler(void) __attribute__((weak, alias("default_handler")));
void adc1_2_handler(void) __attribute__((weak, alias("default_handler")));
void usb_hp_can1_tx_handler(void) __attribute__((weak, alias("default_handler")));
void usb_lp_can1_rx0_handler(void) __attribute__((weak, alias("default_handler")));
void can1_rx1_handler(void) __attribute__((weak, alias("default_handler")));
void can1_sce_handler(void) __attribute__((weak, alias("default_handler")));
void exti9_5_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_brk_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_up_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_trg_com_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_cc_handler(void) __attribute__((weak, alias("default_handler")));
void tim2_handler(void) __attribute__((weak, alias("default_handler")));
void tim3_handler(void) __attribute__((weak, alias("default_handler")));
void tim4_handler(void) __attribute__((weak, alias("default_handler")));
void i2c1_ev_handler(void) __attribute__((weak, alias("default_handler")));
void i2c1_er_handler(void) __attribute__((weak, alias("default_handler")));
void i2c2_ev_handler(void) __attribute__((weak, alias("default_handler")));
void i2c2_er_handler(void) __attribute__((weak, alias("default_handler")));
void spi1_handler(void) __attribute__((weak, alias("default_handler")));
void spi2_handler(void) __attribute__((weak, alias("default_handler")));
void usart1_handler(void) __attribute__((weak, alias("default_handler")));
void usart2_handler(void) __attribute__((weak, alias("default_handler")));
void usart3_handler(void) __attribute__((weak, alias("default_handler")));
void exti15_10_handler(void) __attribute__((weak, alias("default_handler")));
void rtc_alarm_handler(void) __attribute__((weak, alias("default_handler")));
void usbwakeup_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_brk_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_up_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_trg_com_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_cc_handler(void) __attribute__((weak, alias("default_handler")));
void adc3_handler(void) __attribute__((weak, alias("default_handler")));
void fsmc_handler(void) __attribute__((weak, alias("default_handler")));
void sdio_handler(void) __attribute__((weak, alias("default_handler")));
void tim5_handler(void) __attribute__((weak, alias("default_handler")));
void spi3_handler(void) __attribute__((weak, alias("default_handler")));
void uart4_handler(void) __attribute__((weak, alias("default_handler")));
void uart5_handler(void) __attribute__((weak, alias("default_handler")));
void tim6_handler(void) __attribute__((weak, alias("default_handler")));
void tim7_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel1_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel2_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel3_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel4_5_handler(void) __attribute__((weak, alias("default_handler")));
uint32_t isr_vector[ISR_VECTOR_SIZE] __attribute__((section(".isr_vector"))) = {
STACK_INIT_ADDR,
// Cortex-M3 Processor Exceptions
(uint32_t)&reset_handler, // Reset Handler
(uint32_t)&nmi_handler, // NMI Handler
(uint32_t)&hard_fault_handler, // Hard Fault Handler
(uint32_t)&mem_manage_handler, // MPU Fault Handler
(uint32_t)&bus_fault_handler, // Bus Fault Handler
(uint32_t)&usage_fault_handler, // Usage Fault Handler
(uint32_t)0, // Reserved
(uint32_t)0, // Reserved
(uint32_t)0, // Reserved
(uint32_t)0, // Reserved
(uint32_t)&svc_handler, // SVCall Handler
(uint32_t)&debug_mon_handler, // Debug Monitor Handler
(uint32_t)0, // Reserved
(uint32_t)&pendsv_handler, // PendSV Handler
(uint32_t)&systick_handler, // SysTick Handler
// external interrupts
(uint32_t)&wwdg_handler, // Window Watchdog
(uint32_t)&pvd_handler, // PVD through EXTI Line detect
(uint32_t)&tamper_handler, // Tamper
(uint32_t)&rtc_handler, // RTC
(uint32_t)&flash_handler, // Flash
(uint32_t)&rcc_handler, // RCC
(uint32_t)&exti0_handler, // EXTI Line 0
(uint32_t)&exti1_handler, // EXTI Line 1
(uint32_t)&exti2_handler, // EXTI Line 2
(uint32_t)&exti3_handler, // EXTI Line 3
(uint32_t)&exti4_handler, // EXTI Line 4
(uint32_t)&dma1_channel1_handler, // DMA1 Channel 1
(uint32_t)&dma1_channel2_handler, // DMA1 Channel 2
(uint32_t)&dma1_channel3_handler, // DMA1 Channel 3
(uint32_t)&dma1_channel4_handler, // DMA1 Channel 4
(uint32_t)&dma1_channel5_handler, // DMA1 Channel 5
(uint32_t)&dma1_channel6_handler, // DMA1 Channel 6
(uint32_t)&dma1_channel7_handler, // DMA1 Channel 7
(uint32_t)&adc1_2_handler, // ADC1 & ADC2
(uint32_t)&usb_hp_can1_tx_handler, // USB High Priority or CAN1 TX
(uint32_t)&usb_lp_can1_rx0_handler, // USB Low Priority or CAN1 RX0
(uint32_t)&can1_rx1_handler, // CAN1 RX1
(uint32_t)&can1_sce_handler, // CAN1 SCE
(uint32_t)&exti9_5_handler, // EXTI Line 9..5
(uint32_t)&tim1_brk_handler, // TIM1 Break
(uint32_t)&tim1_up_handler, // TIM1 Update
(uint32_t)&tim1_trg_com_handler, // TIM1 Trigger and Commutation
(uint32_t)&tim1_cc_handler, // TIM1 Capture Compare
(uint32_t)&tim2_handler, // TIM2
(uint32_t)&tim3_handler, // TIM3
(uint32_t)&tim4_handler, // TIM4
(uint32_t)&i2c1_ev_handler, // I2C1 Event
(uint32_t)&i2c1_er_handler, // I2C1 Error
(uint32_t)&i2c2_ev_handler, // I2C2 Event
(uint32_t)&i2c2_er_handler, // I2C2 Error
(uint32_t)&spi1_handler, // SPI1
(uint32_t)&spi2_handler, // SPI2
(uint32_t)&usart1_handler, // USART1
(uint32_t)&usart2_handler, // USART2
(uint32_t)&usart3_handler, // USART3
(uint32_t)&exti15_10_handler, // EXTI Line 15..10
(uint32_t)&rtc_alarm_handler, // RTC Alarm through EXTI Line
(uint32_t)&usbwakeup_handler, // USB Wakeup from suspend
(uint32_t)&tim8_brk_handler, // TIM8 Break
(uint32_t)&tim8_up_handler, // TIM8 Update
(uint32_t)&tim8_trg_com_handler, // TIM8 Trigger and Commutation
(uint32_t)&tim8_cc_handler, // TIM8 Capture Compare
(uint32_t)&adc3_handler, // ADC3
(uint32_t)&fsmc_handler, // FSMC
(uint32_t)&sdio_handler, // SDIO
(uint32_t)&tim5_handler, // TIM5
(uint32_t)&spi3_handler, // SPI3
(uint32_t)&uart4_handler, // UART4
(uint32_t)&uart5_handler, // UART5
(uint32_t)&tim6_handler, // TIM6
(uint32_t)&tim7_handler, // TIM7
(uint32_t)&dma2_channel1_handler, // DMA2 Channel1
(uint32_t)&dma2_channel2_handler, // DMA2 Channel2
(uint32_t)&dma2_channel3_handler, // DMA2 Channel3
(uint32_t)&dma2_channel4_5_handler, // DMA2 Channel4 & Channel5
};
extern uint32_t _etext, _sdata, _edata, _sbss, _ebss, _sidata;
void app_main(void);
void reset_handler(void)
{
// Copy .data from FLASH to SRAM
uint32_t data_size = (uint32_t)&_edata - (uint32_t)&_sdata;
uint8_t *flash_data = (uint8_t*)&_sidata; // Data load address (in flash)
uint8_t *sram_data = (uint8_t*)&_sdata; // Data virtual address (in sram)
for (uint32_t i = 0; i < data_size; i++) {
sram_data[i] = flash_data[i];
}
// Zero-fill .bss section in SRAM
uint32_t bss_size = (uint32_t)&_ebss - (uint32_t)&_sbss;
uint8_t *bss = (uint8_t*) &_sbss;
for (uint32_t i = 0; i < bss_size; i++) {
bss[i] = 0;
}
app_main();
}
void default_handler(void)
{
while(1);
}
HSE时钟配置代码
void system_clock_init(uint8_t PLL)
{
unsigned char temp=0;
rcc_deinit(); //复位并配置向量表
RCC->CR|=0x00010000; //外部高速时钟使能HSEON
while(!(RCC->CR>>17)); //等待外部时钟就绪
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
PLL-=2; //抵消2个单位(因为是从2开始的,设置0就是2)
RCC->CFGR|=PLL<<18; //设置PLL值 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2个延时周期
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25)); //等待PLL锁定
RCC->CFGR|=0x00000002; //PLL作为系统时钟
while(temp!=0x02) { //等待PLL作为系统时钟设置成功
temp=RCC->CFGR>>2;
temp&=0x03;
}
}