2. 嵌入式系统基础

做嵌入式移植,第一件事不是看代码,而是看芯片。我见过太多工程师拿到开发板就开干,结果发现外设地址映射不对、中断控制器不兼容,回头再翻手册,白白浪费两周。这一章,咱们就把硬件平台这件事聊透。

一、主流嵌入式处理器架构对比

先看一张总览图,把几个主流架构的定位搞清楚。

嵌入式处理器架构图谱 ARM Cortex 家族 ● Cortex-M:微控制器 M0/M0+:超低功耗 M3/M4:通用控制 M7:高性能控制 ● Cortex-R:实时控制 ● Cortex-A:应用处理器 RISC-V ● 开源指令集架构 ● 模块化设计 RV32I/RV64I 基础 M/A/F/D 扩展 ● 无历史包袱 ● 生态快速成长 MIPS ● 经典 RISC 架构 ● 延迟槽特性 ● 龙芯早期采用 ● 网络设备常见 ● 生态逐渐萎缩 关键维度对比 维度 ARM Cortex RISC-V MIPS 生态成熟度 ★★★★★ ★★★☆☆ ★★☆☆☆ 工具链 ARMCC/IAR/GCC GCC/LLVM GCC 授权费用 高 免费 中等 实时性 M:硬实时/R:硬实时/A:软实时 可配置 硬实时 说明:ARM Cortex-M 系列在 MCU 领域占据绝对主导,RISC-V 正在 IoT 和 AI 边缘侧快速渗透

二、ARM Cortex-M/A/R 三兄弟

ARM 的 Cortex 系列分三条线,每条线的定位完全不同。我刚开始做移植时,以为 Cortex-M 和 Cortex-A 只是性能差异,后来发现中断模型、内存管理、启动流程完全是两套东西。

系列 典型场景 中断延迟 MMU/MPU 操作系统
Cortex-M 传感器、电机控制、IoT 终端 12~15 个时钟周期 MPU(可选) RTOS(FreeRTOS/RT-Thread)
Cortex-R 汽车制动、基站控制、硬盘控制器 8~10 个时钟周期 MPU(硬实时) 实时 Linux / 裸机
Cortex-A 智能手机、网关、HMI 显示 50~100 个时钟周期 MMU(虚拟内存) Linux / Android
个人经验:选型时别只看主频。Cortex-M7 跑到 400MHz 也不一定能替代 Cortex-A35 跑 200MHz,因为 M 系列没有 MMU,跑不了 Linux。我有个项目把 M7 当主控,结果客户要跑 TCP/IP 协议栈 + Web 界面,最后硬生生加了个 A 核芯片。

三、RISC-V:开源架构的机遇与坑

RISC-V 这几年很火,但说实话,生态还没完全成熟。我去年帮客户移植过一个 RISC-V 内核的 BSP,踩了不少坑。

RISC-V 的核心优势:

  • 指令集开源,没有授权费,适合定制化芯片
  • 模块化设计:RV32I 是基础,M 扩展做乘法,F/D 做浮点,A 做原子操作
  • 没有历史兼容性包袱,指令编码干净

实际移植中要注意的问题:

  • 不同厂商的 RISC-V 核,CSR(控制状态寄存器)地址可能不同
  • 中断控制器没有统一标准,CLIC、PLIC、CLINT 各有各的玩法
  • 调试接口(JTAG)的扫描链实现差异大
避坑指南:我曾经遇到一个 RISC-V 芯片,手册说支持 RV32IMAC,结果实际跑浮点运算时发现 F 扩展没完全实现,编译器生成的浮点指令直接触发非法指令异常。后来只能加软浮点库,性能掉了 40%。所以选 RISC-V 芯片时,一定要确认扩展指令集的实际实现情况。

四、芯片选型原则:别只看数据手册

选芯片这件事,我总结了五个维度,按优先级排序:

  1. 功能匹配:外设接口够不够?UART、SPI、I2C、CAN、Ethernet 数量是否满足?
  2. 性能余量:CPU 利用率留 30%~50% 余量,RAM 留 20% 以上
  3. 功耗约束:工作模式、休眠模式、唤醒时间是否达标
  4. 供货稳定:交期、第二供应商、生命周期状态
  5. 工具链支持:IDE、调试器、RTOS 移植难度、社区活跃度

我的习惯:选型时先列一个「必须满足」清单和一个「加分项」清单。比如必须要有双 CAN 接口,加分项是支持低功耗触摸唤醒。然后拿着清单去对比,而不是被厂商的「主频 1GHz」这种参数带偏。

五、开发板硬件资源分析:以 STM32MP157 为例

STM32MP157 是 ST 推出的双核异构处理器,一个 Cortex-A7(跑 Linux)加一个 Cortex-M4(跑 RTOS)。这种架构在工业 HMI、边缘网关里很常见。

咱们拆开看看这块板子的硬件资源:

资源类别 具体配置 用途说明
CPU 1×Cortex-A7 @ 650MHz
1×Cortex-M4 @ 209MHz
A7 跑 Linux 应用层
M4 做实时控制
内存 DDR3L 512MB(板载) Linux 系统运行空间
存储 SD 卡 / eMMC / NAND 根文件系统存放
显示 MIPI-DSI / RGB-LCD / HDMI HMI 界面输出
网络 1×Gigabit Ethernet 工业以太网通信
外设 UART×8, SPI×5, I2C×5, CAN×2, USB×2 传感器、执行器、通信模块
调试 ST-LINK/V2-1 集成 板载调试器,无需外接

异构通信机制:

A7 和 M4 之间通过共享内存(IPCC)和硬件信号量(HSEM)通信。我调试时发现,很多人把数据放在共享内存里,但没做缓存一致性处理,导致 A7 写的数据 M4 读不到。解决办法是在共享内存区域关闭 MMU 的 cache 属性,或者用 DMA 搬运。

实战建议:拿到 STM32MP157 开发板后,先做三件事:
1. 用 STM32CubeProgrammer 读一下 OTP 区域,确认芯片版本
2. 用 TF-A(Trusted Firmware-A)启动,检查 DDR 初始化时序
3. 跑一个简单的 M4 裸机程序,验证 IPCC 中断通路
这三步走完,基本能排除 80% 的硬件问题。

六、开发板资源分析流程

不管拿到什么开发板,我建议按这个流程走一遍:

  1. 读原理图:找到电源树、时钟树、复位电路,确认各模块供电电压
  2. 看数据手册:重点关注 memory map、中断向量表、启动模式选择
  3. 测基础外设:GPIO 点灯、UART 回环、定时器中断
  4. 验证内存:跑 memtest 检查 DDR/SRAM 的读写稳定性
  5. 确认调试接口:SWD/JTAG 信号是否正常,调试器能否识别芯片
我曾经踩过的坑:有一次拿到一块新板子,原理图上看电源都正常,但 UART 就是不出数据。查了两天,发现是板子上的 RS232 电平转换芯片的使能引脚被拉低了。所以,别只盯着主芯片,板级的外围电路也要仔细看。