完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
基于stm32f103c8t6芯片的启动文件进行分析。
启动文件在嵌入式芯片开发是必不可少的,其文件后缀是.s,通常需要加入工程参与编译。它的的用包括一下几点:
1.启动文件使用到的汇编指令
2.启动文件代码分析 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp 上面代码定义了栈的大小为0x00000400(1KB),名称为STACK,NOINIT表示不初始化,REAWRITE表示可读可下,ALIGN = 3表示按照8(即2^3)字节对齐。还定义了标号__initial_sp(栈的结束地址)。利用SPACE关键字来申请空间,大小为Stack_Size,记作Stack_Mem。栈是由高向低生长的。 栈的空间用于局部变量、函数调用、函数形参等开销,栈的大小不能超过芯片内部SRAM大小;如果编写的程序局部变量比较多,占用内存比较大,会造成栈溢出,导致进入硬故障,这时候需要考虑增加栈空间大小。 Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit 上面的代码定义了堆大小为0x00000200(512字节),名称为HEAP,NOINIT表示不初始化,READWRITE表示可读可写,ALIGN = 3表示按照8(即2^3)字节对齐。还定义了标号:__heap_base(堆的起始地址)、__heap_limit(堆的结束地址)。利用SPACE关键字来申请空间,大小为Heap_Size,记作Heap_Mem。堆是由低向高生长的,与栈的生长方向相反。 堆的主要用于动态内存的分配,像malloc()函数申请的内存就在堆中。这个在STM32里面用得比较少。 PRESERVE8 THUMB 上面两个在前面的指令表格里已经说明。 ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size 上面代码定义了一个数据段,名称为RESET,仅可读,还声明了3个外部文件可以使用的标号:__Vectors(向量表起始地址)、__Vectors_End(向量表结束地址)、__Vectors_Size(向量表大小)。 向量表其实就是一个WORD(32bit整数)数组,每一个下标对应一种异常,该下标元素的值则是该ESR的入口地址。向量表在地址空间的位置是可以被设置的,同过NVIC中的一个重定位寄存器来指定向量表的地址。复位之后,该寄存器的值为0。因此,在地址0(即flash地址0)处必须包含一张向量表,用于初始化时的异常分配。 接下来的代码就是分配向量表的内存 __Vectors DCD __initial_sp ; Top of Stack(栈顶地址) DCD Reset_Handler ; Reset Handler(复位程序地址) DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved(保留) DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper ;(中间代码省略) DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors 上面代码利用DCD关键字以4字节对齐,分配了一堆内存,类似之前SPACE关键字的作用。利用__Vectors_End(堆结束地址)减去__Vectors(堆的起始地址)得到堆的大小__Vectors_Size。 向量表从flash的0地址开始放置,以4字节为一个单位,地址0存放的时栈顶地址,接着0x04存放的时复位程序的地址,以此类推。向量表中存放的都是中断函数的函数名,可我们知道C语言中函数名就是一个地址。 AREA |.text|, CODE, READONLY 上面代码表示是定义一个名称为.text的代码段,仅可读。 ; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP 复位子程序是系统上电第一个执行的程序,调用SystemInit函数(sysyem_stm32f4xx.c文件里定义的)初始化系统时钟等,然后调用C库函数_main(编译器自带的),在_main函数里最终会调用main函数转到C的世界。 LDR、BLX、BX是CM4内核的指令: LDR:从储存器中加载一个字到寄存器中。接下来的代码就是中断服务程序的实现,一般来说,我们会在外部的c文件实现中断函数,这里定义了只是备用,以防我们把某个中断使能了,但忘了实现它的中断函数或者函数名写错,那么系统就会执行下面的程序,并且下面的中断函数会进入无限循环,程序也就死在这里。 NMI_Handler PROC ;不可屏蔽的系统异常中断 EXPORT NMI_Handler [WEAK] B . ENDP HardFault_Handler ;所有类型错误的中断 PROC EXPORT HardFault_Handler [WEAK] B . ENDP (省略一部分代码) SysTick_Handler PROC ;系统滴答定时器中断 EXPORT SysTick_Handler [WEAK] B . ENDP Default_Handler PROC ;外设中断 EXPORT WWDG_IRQHandler [WEAK] EXPORT PVD_IRQHandler [WEAK] EXPORT TAMPER_IRQHandler [WEAK] (省略一部分代码) RTCAlarm_IRQHandler USBWakeUp_IRQHandler B . ENDP ALIGN B:跳转到一个标号,这里跳转到一个‘.’,表示无限循环。 ;******************************************************************************* ; User Stack and Heap initialization ;******************************************************************************* IF :DEF:__MICROLIB ;这个宏在KEIL里面开启 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 ALIGN ENDIF END 如果勾选【Options for Target】->【Target】->【Use MicroLIB】,那么就会定义宏__MICROLOB。 如果定义了__MICROLOB,那么把__initial_sp(栈起始地址)、__heap_base(堆开始地址)、__heap_limit(堆结束地址)标号赋予全局属性,那么在外部文件也可以使用,然后堆和栈的初始化就由C库函数__main来完成。 如果没有定义__MICROLOB,采用双段存储器模式,且声明标号__user_initial_stackheap具有全局性,让用户自己来初始化堆和栈。KEIL C库函数会调用__user_initial_stackheap,通过R0~R3将堆栈以参数形式传递给KEIL C库。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1844 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1645 浏览 1 评论
1112 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
744 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1700 浏览 2 评论
1957浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
765浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
591浏览 3评论
612浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
575浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-3 05:17 , Processed in 0.761793 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号