完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
从大学时期,使用的第一块ARM单片机——飞思卡尔K60起,到后面参加工作 STM32,I.MX RT系列,Infineon 的 TLE984等等。从当初啥外设都不知,只会在main函数里写个 printf,到现在对ARM架构略知一二。接下来笔者来重点说明下,我们常常见到的startup.s文件。也就是常说的启动文件
若连一个单片机是怎么启动都不知道,只知道在while(1)里写代码,这就常说的只会敲代码的码农,还不算一个完整的嵌入式工程师吧。这里笔者就拿最近在用的 i.MX RT1052来讲,cortex M7 一款性价比贼高的跨界处理器。下面的描述都是笔者通过相关书籍或网络整理后的笔记内容: ;--------------------------------------------------------------------------------------------------------------- ; 第一部分: ; ; 1.启动代码最重要的工作是把异常&中断向量表放到正确的Flash地址上(也有可能是RAM上) ; 2.把向量表定义为只读数据段,并导出向量表符号(Symbol),让链接器识别此符号并根据分散加载文件正确的放置向量表(链接部分就不讲了) ; 3.__Vector***标号以及|Image$$ARM_LIB_STACK$$ZI$$Limit|标号需要与分散加载文件合起来看,才会明白其真正的功能 ; ;--------------------------------------------------------------------------------------------------------------- PRESERVE8 ; 8 字节对齐 THUMB ; THUMB指令集 ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY ; 声明权限为"READONLY" 名称为"RESET"的数据段 EXPORT __Vectors ; 导出"__Vectors"标号,理解为向量表收地址,分散加载描述文件中会用到 EXPORT __Vectors_End EXPORT __Vectors_Size IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit| ; 导入"|Image$$ARM_LIB_STACK$$ZI$$Limit|" ;--------------------------------------------------------------------------------------------------------------- ; 第二部分: ; ; |Image$$ARM_LIB_STACK$$ZI$$Limit| : ; 1.栈顶指针地址,此语法跟MDK编译器的底层相关,是ARMCC编译器才能识别的语法,GCC与IAR的底层编译器ICCARM编译器 ; 不能识别 ; 2.|Image$$ARM_LIB_STACK$$ZI$$Limit| 是一个链接器 Image Symbol ; 3.此处|Image$$ARM_LIB_STACK$$ZI$$Limit|相当于栈顶地址,或者理解为直接将栈顶地址写到此处也行 ; ; Reset_Handler : ; 1.Reset_Handler函数地址,此处相当于把Reset_Handler函数地址赋值给PC,即调用Reset_Handler函数 ; ; 重要关键节点: ; 1.绝大多数Cortex-M微控制器(M0 M3 M4 M7都是这样)复位后先进入厂商BOOTROM,此时所有用户行为均无法介入处理器 ; 2.厂商BOOTROM(有些厂商会有其他称呼)主要负责处理一些芯片最基本的初始化、加密(RT1052就是这样)以及一些对MCU ; 的差异化设置等工作 ; 3.BOOTROM顺利完成后,MCU控制权会交给用户,即启动代码 ; 4.启动代码(运行汇编语言则不需要此启动代码),最重要的工作在于设置MSP(主堆栈指针)以及PC(程序计数器)的值 ; 5.Cortex-M微控制器会默认把0x00000000地址里面的值设置为MSP的值,0x00000004地址里面的值设置为PC的值 ; ; 关于External(异常)与 Interrupts(中断)的区别说明 ; 1.External(异常)与 Interrupts(中断)是不同的,是两个不同的概念 ; 2.External(异常)是向量表的前16个向量,其优先级为负数,高于所有中断,而且不可调整优先级也不可以关闭,可以 ; 打断正常程序与Interrupts(中断)的运行 ; 3.从第16个向量以后才是Interrupts(中断),可以设置优先级,不用时可以关闭,但优先级一般低于External(异常) ; ; ;--------------------------------------------------------------------------------------------------------------- __Vectors DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| ; 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 ;操作系统会用到的异常向量 DCD SysTick_Handler ;操作系统会用到的滴答定时器异常向量(没有操作系统时可以用作普通定时器中断,这里强烈建议这么用) ;External Interrupts ;--------------------------------------------------------------------------------------------------------------- ; 第三部分: ; ; 1.这里开始是中断向量表 ; 2.各个向量的顺序是芯片设计的时候就定义好的,不能更改 ; ;--------------------------------------------------------------------------------------------------------------- DCD DMA0_DMA16_IRQHandler ;DMA channel 0/16 transfer complete DCD DMA1_DMA17_IRQHandler ;DMA channel 1/17 transfer complete DCD DMA2_DMA18_IRQHandler ;DMA channel 2/18 transfer complete DCD DMA3_DMA19_IRQHandler ;DMA channel 3/19 transfer complete DCD DMA4_DMA20_IRQHandler ;DMA channel 4/20 transfer complete DCD DMA5_DMA21_IRQHandler ;DMA channel 5/21 transfer complete ...... DCD DefaultISR ;251 DCD DefaultISR ;252 DCD DefaultISR ;253 DCD DefaultISR ;254 DCD 0xFFFFFFFF ; Reserved for user TRIM value __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors ;--------------------------------------------------------------------------------------------------------------- ; 第四部分: ; ; 这部分开始可以称作Reset Handler实体,芯片上电后,经过BOOTROM后进入的用户可控最开始处的地方 ; 1.如果想让MCU正常使用C语言,务必在此处调用__main函数 ; 2.__main()不是main()两者有着本质的区别 ; 3.__main()是C Library中的函数,keil开发环境中自带的C Library ; 4.main()是被__main()调用的,__main()工作完成最后一步就是调用main() ; 5.__main()被调用之前,可以根据需要插入一个或多个其他功能函数 ; ;--------------------------------------------------------------------------------------------------------------- AREA RES_HANDLER, CODE, READONLY ; Reset Handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main CPSID I ; Mask interrupts LDR R0, =0xE000ED08 ; LDR R1, =__Vectors STR R1, [R0] LDR R2, [R1] MSR MSP, R2 ;Config OCRAM,DTCM,ITCM LDR R0,=0x400AC038 LDR R1,=0x00AA0000 STR R1,[R0] LDR R0,=0x400AC040 LDR R1,=0x00200007 STR R1,[R0] LDR R0,=0x400AC044 LDR R1,=0xFFFFAAA9 ;OCRAM = 32KB, DTCM = 224KB ,ITCM = 256KB 这里定义RAM分配,不是每个MCU都是这样的 STR R1,[R0] LDR R0, =SystemInit BLX R0 CPSIE i ; Unmask interrupts LDR R0, =__main ;__main 不是我们所理解的 main函数 BX R0 ENDP AREA OTHER_HANDLER, CODE, READONLY ;--------------------------------------------------------------------------------------------------------------- ; 第五部分: ; ; 1.[WEAK]指定了这个函数为“若函数” (具体怎么用,问问度娘就知道了) ; 2.这些中断服务函数定义成弱函数的意义是,当中断出现时,需要有一个中断服务函数予以响应,但真实的用户程序往往只 ; 会使用一部分中断,甚至不使用中断,所以以下这些函数给出了异常/中断服务函数的默认实现(死循环,汇编中的'B.' ; 语句,相当于while(1)),因为不知道用户是否会用到多少中断,但这些服务函数又很重要,所以就把这些函数都实现并 ; 声明为若函数 ; 3.在C语言中声明弱函数是在函数后加"__attribute((weak))" ; ;--------------------------------------------------------------------------------------------------------------- ; Dummy Exception Handlers (infinite loops which can be modified) NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ;这里实现死循环 类似 while(1) ENDP HardFault_Handler PROC EXPORT HardFault_Handler [WEAK] B . ENDP ...... ENET_1588_Timer_IRQHandler PROC EXPORT ENET_1588_Timer_IRQHandler [WEAK] LDR R0, =ENET_1588_Timer_DriverIRQHandler BX R0 ENDP Default_Handler PROC EXPORT DMA0_DMA16_DriverIRQHandler [WEAK] EXPORT DMA1_DMA17_DriverIRQHandler [WEAK] EXPORT DMA2_DMA18_DriverIRQHandler [WEAK] ...... PWM4_1_IRQHandler PWM4_2_IRQHandler PWM4_3_IRQHandler PWM4_FAULT_IRQHandler Reserved168_IRQHandler Reserved169_IRQHandler Reserved170_IRQHandler Reserved171_IRQHandler Reserved172_IRQHandler Reserved173_IRQHandler SJC_ARM_DEBUG_IRQHandler NMI_WAKEUP_IRQHandler DefaultISR LDR R0, =DefaultISR BX R0 ENDP ALIGN END |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 21:04 , Processed in 0.902035 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号