求职笔记 . Cortex-M 简述

链接脚本

链接脚本指定了各个段的位置

Cortex-M启动

连接脚本与启动 - 各种固件库中都会提供类似startup_<device>.s的汇编文件,称为启动脚本,里面包含中断向量表和复位代码 - 链接脚本中设置了各个代码段的位置,中断向量表被设置在ROM的开头(0x08000000),使得硬件复位后正确加载

硬件自动加载:复位后,硬件直接从向量表(固定地址,如 0x08000000)读取前两个值:

  1. 初始栈指针(SP):第一个条目,由硬件自动加载到主栈指针(MSP)。
  2. 复位向量(PC):第二个条目,指向 Reset_Handler 函数,硬件跳转执行。

执行初始化代码Reset_Handler的定义往往在启动脚本中,内部实现了:系统初始化、复制.data数据段、清零.bss段,最终跳转main函数的功能。详见 《Cortex-M 启动脚本分析》

Cortex-M 中断触发过程

plaintext
外设触发 → NVIC 仲裁优先级 → 硬件自动保存上下文 → 跳转 ISR → 中断结束与恢复
  1. 中断信号触发
  • 外设或异常源:
    外设(如定时器、GPIO)通过物理信号线向 嵌套向量中断控制器(NVIC) 发送中断请求。
    • 例如:定时器溢出时,硬件自动拉高中断请求线电平。

  1. 中断优先级判定
  • NVIC 硬件仲裁:
    NVIC 根据中断的优先级(数值越小优先级越高)自动判断是否响应当前中断。
    • 抢占优先级:高优先级中断可抢占正在执行的低优先级中断。
    • 优先级分组:通过 SCB->AIRCR 寄存器配置优先级分组(如抢占位与子优先级的划分)。

  1. 硬件自动保存上下文

    触发中断硬件自动压栈,无FPU时压栈顺序如下: PC → LR → xPSR → R0 → R1 → R2 → R3 → R12 其他被ISR使用的寄存器,会由编译器在ISR的代码段中生成压栈出栈代码

    1. PC(程序计数器):保存被中断程序的返回地址。
    2. LR(链接寄存器):保存异常返回码(EXC_RETURN),用于指示返回模式和栈类型。
    3. xPSR(程序状态寄存器):包含当前程序的状态标志(如 NZCV、中断使能位等)。
    4. R0-R3:通用寄存器,用于传递函数参数或临时数据。
    5. R12:通用寄存器,常用于中间运算或调用约定。

    之所以只保存这些寄存器是AAPCS(ARM Architecture Procedure Call Standard)规定的:

    • 参数传递:R0-R3 用于传递前4个函数参数,超过部分通过栈传递;返回值通过 R0 返回。
    • 寄存器保存:R4-R11 由被调用函数保存(需压栈保护),R0-R3、R12 由调用者保存。
    • 浮点寄存器:若有浮点单元(FPU),S0-S15 由调用者保存,S16-S31 由被调用者保存。

    将一部分寄存器交由编译器控制,可以提高响应速度


  1. 跳转至中断服务函数
  • 中断向量表查询:
    硬件根据中断号(如 TIM2_IRQn)从中断向量表中获取对应的 中断服务函数(ISR)入口地址,并跳转执行。
    • 向量表地址默认在 Flash 起始位置,可通过 SCB->VTOR 重定位。

  1. 中断结束与恢复
  • 硬件自动恢复上下文:
    当 ISR 执行 BX LRPOP {PC} 后,硬件自动弹栈恢复寄存器值,返回被中断的程序。
    • 末尾连锁优化:若存在挂起的中断,硬件会直接跳转至新中断,减少压栈/弹栈开销。

求职笔记 . MCU . Cortex-M启动脚本分析
求职笔记 . 操作系统 . 内存管理