DA14531启动过程详解,从boot到main(堆栈、startup)

好记性不如烂笔头,既然不够聪明,就乖乖的做笔记,温故而知新。

本文档用于本人对知识点的梳理和记录

目录

名词解释

常用名词解释

startup.S文件中涉及的汇编指令:

第一阶段:Boot启动

第二阶段:startup到main

栈-stack

堆-heap

中断向量表

复位

其他子程序

总结


名词解释

常用名词解释

Scatter文件用于将编译后的映像文件中的特定段加载到多个分散的指定内存区域
RW程序中已经初始化的变量所占空间(预定义变量)
RO常量所占空间大小
ZI未初始化的static变量和全局变量以及堆栈所占的空间
Code代码大小
THUMB表示后面指令兼容 THUMB 指令。THUBM 是ARM 以前的16bit指令集
THUMB-2ARM 32bit指令集,向下兼容
MSP主堆栈指针
NMI不可屏蔽中断

startup.S文件中涉及的汇编指令:

指令

作用

EQU

给数字常量取一个符号名,相当于 C 语言中的 define

AREA

汇编一个新的代码段或者数据段

SPACE

分配内存空间

PRESERVE8

当前文件堆栈需按照 8 字节对齐

EXPORT

声明一个标号具有全局属性,可被外部的文件使用

DCD

以字为单位分配内存,要求 4 字节对齐,并要求初始化这些内存

PROC

定义子程序,与 ENDP 成对使用,表示子程序结束

WEAK

弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不出错。

IMPORT

声明标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似

B

跳转到一个标号

ALIGN

编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即
数,缺省表示 4 字节对齐。要注意的是:这个不是 ARM 的指令,是编译器的,这里放在一起只是为了方便。

END

到达文件的末尾,文件结束

IF,ELSE,ENDIF

汇编条件分支语句,跟 C 语言的类似

LDR

从存储器中加载字到一个寄存器中

BL

跳转到由寄存器/标号给出的地址,并把跳转前的下条指令地址保存到 LR

BLX

跳转到由寄存器给出的地址,并根据寄存器的 LSE 确定处理器的状态,还要把跳转前的下条指令地址保存到 LR

BX

跳转到由寄存器/标号给出的地址,不用返回


我把DA14531启动启动分为两个阶段,第一个是Boot阶段,第二个是BoorROM之后startup到main的阶段;
搭载ARM核的MCU的启动流程大同小异,一直想把该流程梳理清楚,今天他来了;前言

第一阶段:Boot启动

DA14531内置32KB OTP,由interrupt Vectors、custom code、Configuration Script、OTP Header组成,为啥要介绍这段呢?因为BootROM会需要。

DA14531预置有BootROM,首先RC32K起振提供clock,BootROM启动后会判断Configuration Script、OTP Header的某些Flag,从而决定是从内置OTP中读取固件,还是从外设获取固件,并起振32M晶振(所以主时钟起振是判断芯片是否启动的重要特征)。

从外设获取固件的情况下,将依次轮询Boot Step1~Boot Step6,分别是(SPIM/UART-1/UART-2/UART/SPIS/I2C)。最终的结果是download code to SRAM,成功后,将SysRAM重新映射到地址0x0000。

至此第一阶段就完成了,需要注意的是,该过程不需要用户参与,保证硬件畅通,并正确烧录了固件核相关配置即可,如有疑问,欢迎邮件至jonesli@macnica.com。

第二阶段:startup到main

该过程从startup_da14531.S开始,首先S文件在单片机中的作用如下:

1. 初始化堆栈指针 SP

2. 初始化程序计数器指针 PC

3. 设置堆、栈的大小

4. 设置中断向量表的入口地址

5. 配置外部 SRAM 作为数据存储器

6. 调用 SystemInit() 函数配置 STM32 的系统时钟

7. 设置 C 库的分支入口 "__main” (最终用来调用 main 函数)

栈-stack

6f00bf2a1de04a5da3a1bca87735038b.png

AREA:汇编一个新的代码段或者数据段。STACK段名;NOINIT表示不初始化;READWRITE可读可写;ALIGN=3(2^3= 8字节对齐)。

__initial_sp紧挨了SPACE放置,表示栈的结束地址,栈是从高往低生长,结束地址就是栈顶地址。

栈:局部变量,函数形参等。栈的大小不能超过内部SRAM大小。栈属于 ZI-data。

栈遵循后入先出原则,就像网桶里叠衣服,后面放入的在上面,必须把上面的衣服先拿出来才能拿下面的衣服。

栈空间是系统在定义变量时自动分配的,不需要user特意申请,速度较块

堆-heap

1cddf094b1c6473193b96011d91f4a03.png

 

分配名为HEAP,不初始化,可读可写,8(2^3)字节对齐的512字节空间。

__heap_base堆的起始地址,__heap_limit堆的结束地址。堆由低向生长。动态分配内存用到堆。

堆的数据结构必须是完全二叉树

User可以自由操作堆空间的申请(malloc)和释放(freemalloc),自由度很高,堆空间的合理运用对内存管理非常重要,但是如果忘记释放,可能产生内存泄漏,速度较慢

中断向量表

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6buR6ImySFM=,size_20,color_FFFFFF,t_70,g_se,x_16

 向量表从 FLASH 的 0 地址开始放置,以 4 个字节为一个单位,如果地址 0 存放的是栈顶地址,0X04 存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都是中断服务函数的函数名,可我们知道 C 语言中的函数名就是一个地址。

需要注意的是栈顶地址即主堆栈指针MSP,一般MSP指向0x00+RW+ZI

复位

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6buR6ImySFM=,size_20,color_FFFFFF,t_70,g_se,x_16

 复位是上电后运行的第一个程序,SystemInit完成系统初始化后,进入main函数。

其他子程序

 其他子程序NMI、HardFault等在应用层都有对应的函数实体

编号       类型优先级介绍
1复位-3(最高级) 
2NMI-2不可屏蔽中断
3Hard Fault-1 
11SVC 执行系统服务调用指令(SVC)引起的异常
14PendSV可编程为系统设备而设的“可悬挂请求”(pendable request)
15SysTick可编程系统滴答定时器(周期性溢出的时定时器)


总结

至此,大致流程记录完毕,有更细节并且有必要,我会再更新该文档。

如有朋友需交流可邮件至 jonesli@macnica.com/495323976@qq.com

 

 

 

 

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑色HS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值