单片机启动流程以STM32举例

文章目录

BOOT引脚选择

0x00000000~0x0007FFFF这段空间属于重映射区,根据BOOT的不同选择映射到不同的内存区域

模式 启动地址 说明
主 Flash(正常情况) 0x08000000 正常用户程序
System Memory 0x1FFF0000 内置 BootLoader(不能修改)
SRAM 0x20000000 调试/特殊用途

向量表加载

假设我们现在选择了主flash模式,内存映射到0x08000000开始执行,首先进行的就是读取加载向量表

对于向量表我们必须要知道的是

  1. 每个占 4 字节(32位)(一个函数指针)
  2. 数组[中断号] = 函数地址
  3. 发生中断 → 查表 → 跳转函数

系统异常向量表

地址(Flash) 偏移 向量名 功能
0x08000000 0x00 Initial MSP 主栈初始值
0x08000004 0x04 Reset_Handler 复位入口(程序起点)
0x08000008 0x08 NMI_Handler 不可屏蔽中断
0x0800000C 0x0C HardFault_Handler 硬Fault异常
0x08000010 0x10 MemManage_Handler 内存管理异常
0x08000014 0x14 BusFault_Handler 总线错误
0x08000018 0x18 UsageFault_Handler 使用错误
0x0800001C 0x1C Reserved 保留
0x08000020 0x20 Reserved 保留
0x08000024 0x24 Reserved 保留
0x08000028 0x28 Reserved 保留
0x0800002C 0x2C SVC_Handler 系统服务调用
0x08000030 0x30 DebugMon_Handler 调试监视
0x08000034 0x34 Reserved 保留
0x08000038 0x38 PendSV_Handler 上下文切换(RTOS关键)
0x0800003C 0x3C SysTick_Handler 系统滴答定时器

外设中断向量表

地址(Flash) 偏移 向量名 功能
0x08000040 0x40 WWDG_IRQHandler 窗口看门狗
0x08000044 0x44 PVD_IRQHandler 电压检测
0x08000048 0x48 TAMPER_IRQHandler 篡改检测
0x0800004C 0x4C RTC_IRQHandler RTC
0x08000050 0x50 FLASH_IRQHandler Flash 操作
0x08000054 0x54 RCC_IRQHandler 时钟控制
0x08000058 0x58 EXTI0_IRQHandler 外部中断0
0x0800005C 0x5C EXTI1_IRQHandler 外部中断1
0x08000060 0x60 EXTI2_IRQHandler 外部中断2
0x08000064 0x64 EXTI3_IRQHandler 外部中断3
0x08000068 0x68 EXTI4_IRQHandler 外部中断4
0x0800006C 0x6C DMA1_Channel1_IRQHandler DMA1通道1
0x08000070 0x70 DMA1_Channel2_IRQHandler DMA1通道2
0x08000074 0x74 DMA1_Channel3_IRQHandler DMA1通道3
0x08000078 0x78 DMA1_Channel4_IRQHandler DMA1通道4
0x0800007C 0x7C DMA1_Channel5_IRQHandler DMA1通道5
0x08000080 0x80 DMA1_Channel6_IRQHandler DMA1通道6
0x08000084 0x84 DMA1_Channel7_IRQHandler DMA1通道7
0x08000088 0x88 ADC1_2_IRQHandler ADC
0x0800008C 0x8C USB_HP_CAN1_TX_IRQHandler USB/CAN发送
0x08000090 0x90 USB_LP_CAN1_RX0_IRQHandler USB/CAN接收
0x08000094 0x94 CAN1_RX1_IRQHandler CAN RX1
0x08000098 0x98 CAN1_SCE_IRQHandler CAN状态
0x0800009C 0x9C EXTI9_5_IRQHandler 外部中断5~9
0x080000A0 0xA0 TIM1_BRK_IRQHandler 定时器1
0x080000A4 0xA4 TIM1_UP_IRQHandler 定时器1更新
0x080000A8 0xA8 TIM1_TRG_COM_IRQHandler 定时器1触发
0x080000AC 0xAC TIM1_CC_IRQHandler 定时器1捕获比较
0x080000B0 0xB0 TIM2_IRQHandler 定时器2
0x080000B4 0xB4 TIM3_IRQHandler 定时器3
0x080000B8 0xB8 TIM4_IRQHandler 定时器4
0x080000BC 0xBC I2C1_EV_IRQHandler I2C1事件
0x080000C0 0xC0 I2C1_ER_IRQHandler I2C1错误
0x080000C4 0xC4 I2C2_EV_IRQHandler I2C2事件
0x080000C8 0xC8 I2C2_ER_IRQHandler I2C2错误
0x080000CC 0xCC SPI1_IRQHandler SPI1
0x080000D0 0xD0 SPI2_IRQHandler SPI2
0x080000D4 0xD4 USART1_IRQHandler 串口1
0x080000D8 0xD8 USART2_IRQHandler 串口2
0x080000DC 0xDC USART3_IRQHandler 串口3
0x080000E0 0xE0 EXTI15_10_IRQHandler 外部中断10~15
0x080000E4 0xE4 RTCAlarm_IRQHandler RTC闹钟
0x080000E8 0xE8 USBWakeUp_IRQHandler USB唤醒

硬件加载动作

c 复制代码
MSP = *(0x00000000);
PC  = *(0x00000004);

从 0x00000000 (已经被映射为0x08000000)读出一个值 → 放进 MSP(主栈指针)

MSP 指向主栈的栈顶,在 SRAM 的高地址处

SRAM 0x20000000 ~ 0x20004FFF(20KB)

MSP 初始值为 0x20005000

从 0x00000004(已经被映射为0x08000004[Reset_Handler]) 读出一个值 → 放进 PC(程序入口)

Reset_Handler

这段程序在startup_stm32f103xx.s启动文件当中存储

c 复制代码
; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

; 

先执行 SystemInit()

再跳到 __main

由 __main 完成C运行时初始化

最后进入 main()

SystemInit()

以F4芯片举例,这个函数的位置在system_stm32f4xx.c,SystemInit 负责最早期的系统级初始化,具体内容由芯片和工程模板决定

c 复制代码
/**
  * @brief  Setup the microcontroller system
  *         Initialize the FPU setting, vector table location and External memory 
  *         configuration.
  * @param  None
  * @retval None
  */
void SystemInit(void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif

#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */

  /* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
}
  1. 浮点单元配置
  2. 外部内存配置,如果有就把外部内存控制器配好;
  3. 如果用户指定了新的向量表地址,就把 CPU 的向量表基址改过去。

__main

MDK/ARM 编译器运行库当中,这个函数的具体运行流程如下

.data 拷贝

.bss 清零

调用 __rt_entry

.data 拷贝

把"有初值的全局/静态变量"从 Flash 的 .data初始化区 搬到 SRAM的 .data区

.bss 清零

把"未初始化的全局/静态变量"在 RAM的 .bss区 中全部清零

__rt_entry

__rt_entry 做的事:

  1. 给程序准备好栈和堆
  2. 把C库准备好(printf这些能用)
  3. 如果是C++,把全局对象构造好
  4. 最后调用 main()

main()

开始执行main函数

如果启用RTOS,之前步骤都不变,在main函数当中才进行RTOS的初始化

相关推荐
WeeJot嵌入式2 小时前
【串口】STM32串口DMA模式与收发不定长数据
stm32·单片机·嵌入式硬件
LCG元2 小时前
STM32实战:基于STM32F103的看门狗(IWDG/WWDG)应用与系统复位
stm32·单片机·嵌入式硬件
ytttr8732 小时前
STM32 USB HID 源码方案
stm32·单片机·嵌入式硬件
lularible2 小时前
PTP协议精讲(2.17):追踪光速的脚步——White Rabbit与亚纳秒同步
网络·网络协议·开源·嵌入式·ptp
C语言小火车2 小时前
嵌入式实习面试问题:那个动态内存是怎么样分配的?
c语言·开发语言·c++·嵌入式硬件·面试
cici158742 小时前
最简单的51单片机舵机控制器DIY
单片机·嵌入式硬件·51单片机
KWTXX2 小时前
两种方式实现51单片机五路循迹,经测试可实现
单片机·嵌入式硬件·51单片机
0南城逆流03 小时前
【STM32】知识点介绍九:看门狗功能
stm32·单片机·嵌入式硬件
VBsemi-专注于MOSFET研发定制3 小时前
面向高端汽车暖风系统控制器的功率MOSFET选型策略与器件适配手册
单片机·嵌入式硬件