跳到正文

MCU 与体系结构

本文性质声明:本机没有开发板(用户环境的 Rockchip 交叉工具链在不可达的 Linux 开发机上),全部内容未实测,为手册级框架。站内对照:os-what-kernel-does(特权级与陷入的本机实测)、c-restricted-environment-and-volatile(受限环境的 C 写法)。

一、Cortex-M:寄存器与异常模型

Cortex-M(M0/M3/M4/M7/M33)的寄存器组小得可以背下来:

R0-R12   通用寄存器(R13=SP 栈指针,R14=LR 链接寄存器,R15=PC)
xPSR     程序状态寄存器(NZCV 标志 + 异常号 + IT 块)
两个 SP:  MSP(主栈,异常/内核用)和 PSP(进程栈,线程模式可用)

异常模型是全架构的核心:中断和异常走同一张向量表(本质是函数指针数组),发生时硬件自动:保存 8 个寄存器到栈(R0-R3/R12/LR/PC/xPSR)→ 取向量表对应入口 → 切到 MSP → 跳转。这套”硬件保存上下文”的机制意味着:裸机中断处理函数就是个普通 C 函数(编译器按 ABI 保存其余寄存器),void USART1_IRQHandler(void) 就能跑——和需要手动保存的架构(如某些 DSP)完全不同。

三个必须知道的点:

  1. 优先级是”数值越小优先级越高”,且优先级位数由芯片实现决定(M3 通常 8 位可配 4 位——NVIC_SetPriorityGrouping 分抢占/子优先级)。同一抢占优先级不嵌套——后到的等前一个处理完,这决定了临界区的写法。
  2. 中断延迟是可算的:硬件保存(12 周期)+ 向量取指 + 流水线填充,典型 12–16 周期;尾部连锁(tail-chaining)让连续中断不重新保存。
  3. HardFault 是兜底异常:跑了未实现的中断、取了错地址、栈溢出——HardFault_Handler 里读 SCB->HFSR/CFSR 是嵌入式调试的第一现场(本站 dbg-crash 讲 Windows 侧的终止码,这是 MCU 侧的对应物)。

二、存储映射:外设就是内存地址

Cortex-M 是统一地址空间——没有 x86 的 in/out 指令,外设寄存器就是普通内存地址:

0x00000000  代码区(Flash 别名或 SRAM,向量表在这)
0x20000000  SRAM(栈默认从顶端往下长)
0x40000000  外设区(APB 总线:GPIO/UART/I2C……)
0xE000E000  Cortex-M 系统级(NVIC 在 0xE000E100,SysTick 在 0xE000E010)

访问外设 = 往绝对地址读写:

#define GPIOC_ODR (*(volatile uint32_t*)0x40020814)
GPIOC_ODR |= (1 << 13);        // 点灯

volatile 不是可选项:编译器不知道”这个地址后面连着硬件”——不加 volatile,GPIOC_ODR = 1; GPIOC_ODR = 2; 会被优化成只写第二次(本站 c-restricted-environment 专节讲过 volatile 与 MMIO)。厂商的 CMSIS 头文件把这些地址包成结构体(GPIOA->ODR),但底层就是上面这行。

位带(bit-band,M3/M4 有):给每个 bit 一个 alias 地址,写 alias 就是原子地置位/清位——GPIOC_ODR_13 = 1 背后是它,多中断共享的寄存器用它做原子改位。

三、RISC-V:同一 ISA,不同生态

RISC-V 的卖点是开放指令集:基 integer 指令集(RV32I/RV64I)+ 可选扩展(M 乘除、A 原子、C 压缩、F/D 浮点、向量)。对嵌入式:

  1. 中断模型不标准化:ARM 有 NVIC 这个事实标准,RISC-V 只有**平台级中断控制器(PLIC)**的规范和各家自己的 CLINT/本地中断——每家的中断代码不一样,没有”一份中断代码到处跑”。
  2. 寄存器模型不同:32 个通用寄存器(x0 恒零)、mstatus/mie/mcause/mepc 一组 CSR(控制状态寄存器)做特权状态——异常处理要手写汇编入口(没有 Cortex-M 那种硬件自动保存全套的便利,虽然可以配快速 trap)。
  3. 生态现实:ESP32-C 系列(乐鑫)、GD32V、沁恒 CH32V、平头哥——国产 MCU 的主力 ISA;工具链(gcc/riscv、OpenOCD)和 RTOS 移植都成熟了,但外设库每家一套,没有 CMSIS 那种统一 HAL。

选型口径:Cortex-M 是”生态换封闭”,RISC-V 是”开放换自建”——量产成本敏感、怕授权风险的看 RISC-V;要开发速度、要 HAL 成熟的看 Cortex-M。

四、读数据手册的四步方法论

数据手册几百上千页,别通读。四步:

  1. 先看订购信息和框图:型号后缀(温度/封装/Flash 大小)、内核主频、外设清单——确认这颗芯片能不能干你要的事。
  2. pin 定义和复用:每个引脚默认功能、可复用外设、模拟功能——原理图设计阶段反复看的一章。
  3. 电气特性:绝对最大值、IO 驱动能力(推挽几 mA)、ADC 的 INL/DNL、功耗表——原理图和电源设计的依据。
  4. 外设寄存器手册(Reference Manual):用到哪个外设查哪章——每个寄存器的位定义、复位值、访问限制(只读/只写/write-1-to-clear)。写驱动时这章和你的代码对照着看。

工程习惯:寄存器操作写成”基址 + 偏移”的宏或 CMSIS 结构体,别在业务代码里裸写地址——数据手册改版(勘误!)时只改一处。勘误表(errata)必看:某些芯片的 DMA+ADC 组合有 bug,手册后面挂着。

五、排障索引

症状第一嫌疑
程序跑飞、随机复位栈溢出(MSP/PSP 撞了)、向量表错、时钟没配对
写外设没反应时钟没开(RCC 门控忘置位)、复用功能没配、volatile 漏了
HardFaultCFSR 的 PRECISERR/IBUSERR/UNSTKERR——分别对应数据访问/取指/出栈错误
中断只进一次标志位没清(write-1-to-clear 语义)、NVIC 没使能
功耗降不下来外设时钟没关、IO 状态浮空、调试器还挂着( emb-lowpower)

六、未实测清单

  • 本文所有架构细节与寄存器行为——无开发板,未测。
  • 具体型号的电气参数——以你芯片的数据手册为准。
  • 中断延迟、栈帧布局的实测——未测。
  • 用户 Linux 开发机上的 Rockchip RV1103 交叉工具链——该机不可达,未涉及。