网站首页 > 文章精选 正文
ARM Cortex-M的程序映像从地址0开始,起始处是向量表,其中的每个向量占用4个字节,除了第一个向量保存主栈针MSP初始地址外,其他向量保存的是各种异常处理的跳转地址,例如外部中断IRQ#0的编号是16(从0开始),故IRQ#0的向量地址为16*4=0x40处。Cortex-M0的向量表如下图所示:
程序映像与启动过程密切相关,当处理器复位后,首先将向量表中的第一个字,加载到MSP寄存器中。MSP寄存器的数值是处理器的主栈存储的位置;栈空间用于临时数据的存储,相当于与一个先入先出的缓存,每次执行PUSH(压栈)和POP(出栈)操作时,自动调整MSP寄存器的值。PUSH和POP操作一般用在函数的开始和结尾处,在函数开始时,调用程序使用的寄存器的值被PUSH到栈中,在函数结尾处,栈中的数据被POP恢复回来。Cortex-M处理器的栈操作是基于“满递减”的栈模型:栈指针总是指向最后一个填充到栈空间中的数据,每次PUSH 新的数据后,栈指针的数据会减小,如下图所示:
MSP寄存器地址加载完成后,处理器取出第二个字(复位向量)的数值加载到PC寄存器,即跳转到复位程序执行。程序映像和启动加载过程如下图所示:
对应STM32F030芯片,这一过程是在startup_stm32f030x8.s里面实现,使用的是汇编语言,从代码里面了解整个过程更清晰:
1 分配栈和堆的空间:
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
代码中,Stack_Size和Heap_Size分别指定了栈和堆的空间大小,当程序的栈/堆不够用时,可以修改这里的值,STM32F0默认设置堆空间为0,故malloc调用不能成功;另外将初始栈顶地址命名为__initial_sp,将在向量表中使用。
2 建立向量表
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD 0 ; Reserved
DCD RTC_IRQHandler ; RTC through EXTI Line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_IRQHandler ; RCC
DCD EXTI0_1_IRQHandler ; EXTI Line 0 and 1
DCD EXTI2_3_IRQHandler ; EXTI Line 2 and 3
DCD EXTI4_15_IRQHandler ; EXTI Line 4 to 15
DCD 0 ; Reserved
DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1
DCD DMA1_Channel2_3_IRQHandler ; DMA1 Channel 2 and Channel 3
DCD DMA1_Channel4_5_IRQHandler ; DMA1 Channel 4 and Channel 5
DCD ADC1_IRQHandler ; ADC1
DCD TIM1_BRK_UP_TRG_COM_IRQHandler ; TIM1 Break, Update, Trigger and Commutation
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
DCD 0 ; Reserved
DCD TIM3_IRQHandler ; TIM3
DCD TIM6_IRQHandler ; TIM6
DCD 0 ; Reserved
DCD TIM14_IRQHandler ; TIM14
DCD TIM15_IRQHandler ; TIM15
DCD TIM16_IRQHandler ; TIM16
DCD TIM17_IRQHandler ; TIM17
DCD I2C1_IRQHandler ; I2C1
DCD I2C2_IRQHandler ; I2C2
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
__Vectors_End
正如前面的介绍,向量表第1个向量保存的是初始栈顶地址__initial_sp, 芯片复位后将该值加载到MSP寄存器;第2~16个向量是ARM Cortex-M定义异常处理函数地址,第17个向量开始是外部中断处理函数地址,由微控制器厂商定义,上述代码可以看到STM32F0支持的外部中断。
3 将复位向量地址加载到PC寄存器,跳转到程序起始地址(Reset_Handler)开始执行
; Reset handler routine
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reset_Handler函数先跳转到SystemInit(位于system_stm32f0xx.c)执行,然后在跳转到__main函数。
4 __main函数由C编译器生成,负责初始化C程序执行所需的运行环境,其中一个工作就是初始化栈/堆空间,调用startup_stm32f030x8.s定义的__user_initial_stackheap函数获取栈/堆空间的地址和大小:
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
完成C程序执行环境初始化后,就进入到程序员熟悉的main函数执行了。
- 上一篇: C语言程序概念学习、了解自动化流程以及程序的执行特点
- 下一篇: “空中多面手”歼-10的进化史
猜你喜欢
- 2025-05-23 从0到1:新人如何设计第一款B端产品?
- 2025-05-23 PLC 编程一定要学会FB 块和 FC 块的区别
- 2025-05-23 苹果发布iPadOS 17.7.8,适用于2017款iPad Pro及2018款iPad
- 2025-05-23 如何优化PLC程序的执行效率?
- 2025-05-23 一篇文章掌握整个JVM,JVM超详细解析!!!
- 2025-05-23 MySQL源码学习系列(一)-- 环境准备及常用命令
- 2025-05-23 从入门到放弃,芯片的详细制造流程!
- 2025-05-23 C++ 第一个程序、注释、常量
- 2025-05-23 我国境内捕获银狐木马病毒变种
- 2025-05-23 C 语言—基础命令
- 05-24一文了解工业以太网交换机的作用和工作原理
- 05-24集线器,交换机,路由器工作层次的区别
- 05-24POE交换机供电原理及工作过程介绍
- 05-24如何检查交换机电源的工作状态和健康状况?
- 05-24新手必学!1分钟Get交换机工作原理
- 05-24什么是交换机?交换机工作原理
- 05-24交换机工作原理的直观解释
- 05-24一图搞懂交换机的工作原理
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)