链接脚本
链接脚本指定了各个段的位置
Cortex-M启动
连接脚本与启动 - 各种固件库中都会提供类似startup_<device>.s
的汇编文件,称为启动脚本,里面包含中断向量表和复位代码 - 链接脚本中设置了各个代码段的位置,中断向量表被设置在ROM的开头(0x08000000),使得硬件复位后正确加载
硬件自动加载:复位后,硬件直接从向量表(固定地址,如 0x08000000
)读取前两个值:
- 初始栈指针(SP):第一个条目,由硬件自动加载到主栈指针(MSP)。
- 复位向量(PC):第二个条目,指向
Reset_Handler
函数,硬件跳转执行。
执行初始化代码Reset_Handler
的定义往往在启动脚本中,内部实现了:系统初始化、复制.data数据段、清零.bss段,最终跳转main函数的功能。详见 《Cortex-M 启动脚本分析》
Cortex-M 中断触发过程
plaintext
外设触发 → NVIC 仲裁优先级 → 硬件自动保存上下文 → 跳转 ISR → 中断结束与恢复
- 中断信号触发
- 外设或异常源:
外设(如定时器、GPIO)通过物理信号线向 嵌套向量中断控制器(NVIC) 发送中断请求。- 例如:定时器溢出时,硬件自动拉高中断请求线电平。
- 中断优先级判定
- NVIC 硬件仲裁:
NVIC 根据中断的优先级(数值越小优先级越高)自动判断是否响应当前中断。- 抢占优先级:高优先级中断可抢占正在执行的低优先级中断。
- 优先级分组:通过
SCB->AIRCR
寄存器配置优先级分组(如抢占位与子优先级的划分)。
硬件自动保存上下文
触发中断硬件自动压栈,无FPU时压栈顺序如下:
PC → LR → xPSR → R0 → R1 → R2 → R3 → R12
其他被ISR使用的寄存器,会由编译器在ISR的代码段中生成压栈出栈代码- PC(程序计数器):保存被中断程序的返回地址。
- LR(链接寄存器):保存异常返回码(EXC_RETURN),用于指示返回模式和栈类型。
- xPSR(程序状态寄存器):包含当前程序的状态标志(如 NZCV、中断使能位等)。
- R0-R3:通用寄存器,用于传递函数参数或临时数据。
- R12:通用寄存器,常用于中间运算或调用约定。
之所以只保存这些寄存器是AAPCS(ARM Architecture Procedure Call Standard)规定的:
- 参数传递:R0-R3 用于传递前4个函数参数,超过部分通过栈传递;返回值通过 R0 返回。
- 寄存器保存:R4-R11 由被调用函数保存(需压栈保护),R0-R3、R12 由调用者保存。
- 浮点寄存器:若有浮点单元(FPU),S0-S15 由调用者保存,S16-S31 由被调用者保存。
将一部分寄存器交由编译器控制,可以提高响应速度
- 跳转至中断服务函数
- 中断向量表查询:
硬件根据中断号(如 TIM2_IRQn)从中断向量表中获取对应的 中断服务函数(ISR)入口地址,并跳转执行。- 向量表地址默认在 Flash 起始位置,可通过
SCB->VTOR
重定位。
- 向量表地址默认在 Flash 起始位置,可通过
- 中断结束与恢复
- 硬件自动恢复上下文:
当 ISR 执行BX LR
或POP {PC}
后,硬件自动弹栈恢复寄存器值,返回被中断的程序。- 末尾连锁优化:若存在挂起的中断,硬件会直接跳转至新中断,减少压栈/弹栈开销。