4. DMA 控制器原理

在 Bootloader 升级场景中,大量数据需要从通信接口(如 CAN、UART、SPI)搬运到 Flash 或 RAM。传统 CPU 轮询或中断方式会占用大量内核时间,导致升级速度下降。DMA(Direct Memory Access,直接存储器访问)控制器允许外设与存储器之间直接传输数据,无需 CPU 干预,是提升 Bootloader 升级性能的核心硬件基础。

核心收益: 使用 DMA 传输后,CPU 可以在数据搬运期间继续执行擦除、校验或协议解析任务,整体升级吞吐量可提升 30%~50%。

4.1 DMA 基本概念

DMA 控制器是一个独立的总线主机,拥有自己的地址总线和控制逻辑。一次典型的 DMA 传输涉及以下要素:

要素 说明 Bootloader 场景示例
源地址 数据读取的起始位置 CAN 模块的接收 FIFO 地址
目的地址 数据写入的目标位置 SRAM 中的临时缓冲区
传输长度 本次传输的字节/半字/字数 256 字节(一个 CAN 报文数据段)
触发源 启动 DMA 传输的硬件事件 CAN 接收完成中断请求
通道 DMA 控制器内部的独立传输路径 S32K3 支持 64 个 DMA 通道

S32K3 系列基于 Arm Cortex-M7 内核,集成了恩智浦增强型 eDMA(Enhanced Direct Memory Access)控制器,支持最多 64 个独立通道、16 个可编程优先级等级,以及灵活的通道链接能力。

关键寄存器: 每个 DMA 通道包含 TCD(Transfer Control Descriptor),其中保存了源地址、目的地址、传输计数、偏移量等完整配置。配置 TCD 即完成一次 DMA 传输的初始化。

4.2 传输模式

eDMA 支持三种核心传输模式,分别适用于不同的 Bootloader 升级子阶段:

4.2.1 单次传输模式

每次触发完成一个固定长度的数据传输后,通道自动关闭或等待重新使能。适用于一次性数据块搬运,如将单个 CAN 报文数据从接收寄存器搬入 RAM。

  • 特点: 配置简单,一次触发一次完成。
  • 适用场景: 小数据包、非连续传输。
  • Bootloader 示例: 读取单个升级命令帧(8 字节)。

4.2.2 循环传输模式

传输完成后,源地址、目的地址和计数自动重置为初始值,通道保持使能状态,等待下一次触发。适用于周期性数据搬运,如持续从 ADC 或通信 FIFO 读取数据流。

  • 特点: 无需 CPU 重新配置,自动循环。
  • 适用场景: 连续数据流、环形缓冲区。
  • Bootloader 示例: 持续从 CAN FIFO 搬运升级数据到 RAM 缓冲区。

4.2.3 链式传输模式

一个通道传输完成后,自动加载下一个 TCD(即下一个传输描述符),实现多个传输任务的串联执行。链式模式是 Bootloader 升级中最强大的 DMA 特性。

  • 特点: 多段传输自动衔接,CPU 零干预。
  • 适用场景: 复杂传输序列、多缓冲区切换。
  • Bootloader 示例: 先搬运数据到 RAM,再触发 CRC 计算,最后搬运到 Flash 写入缓冲区。
DMA 三种传输模式对比 单次传输模式 触发 → 传输 N 字节 传输完成 → 通道关闭 需 CPU 重新使能 一次触发一次完成 适用:单帧命令、小数据包 循环传输模式 触发 → 传输 N 字节 自动重置地址/计数 通道保持使能 自动循环无需干预 适用:连续数据流、环形缓冲 链式传输模式 TCD1 完成 → 自动加载 TCD2 TCD2 完成 → 自动加载 TCD3 多段传输无缝衔接 多任务自动串联 适用:复杂传输序列、多缓冲

4.3 传输粒度

传输粒度决定了每次 DMA 总线访问操作的数据宽度。S32K3 eDMA 支持三种粒度配置,需根据源和目的设备的位宽匹配选择:

粒度 数据宽度 典型外设 Bootloader 应用建议
字节(8-bit) 1 字节 UART、SPI、I2C 串口升级时逐字节搬运
半字(16-bit) 2 字节 定时器、部分 ADC 较少用于 Bootloader 主数据流
字(32-bit) 4 字节 CAN、FlexRay、内部 SRAM CAN 升级时推荐使用,提升总线利用率
粒度匹配规则: 源粒度和目的粒度可以不同,但必须满足对齐要求。例如,源为 8-bit(UART)、目的为 32-bit(SRAM)时,eDMA 会自动进行数据组装,但会降低传输效率。Bootloader 中建议源和目的粒度保持一致,以获得最佳性能。

4.4 eDMA 传输流程与 TCD 结构

理解 TCD(Transfer Control Descriptor)是掌握 eDMA 编程的关键。每个 DMA 通道对应一个 TCD,TCD 中保存了完整的传输上下文:

/* S32K3 eDMA TCD 主要字段(简化结构) */
typedef struct {
    uint32_t SADDR;      /* 源地址 */
    uint16_t SOFF;       /* 源地址每次传输后偏移量 */
    uint16_t NBYTES;     /* 每次传输的字节数(minor loop) */
    uint32_t DADDR;      /* 目的地址 */
    uint16_t DOFF;       /* 目的地址每次传输后偏移量 */
    uint16_t CITER;      /* 当前主循环计数(major loop) */
    uint32_t DLAST_SGA;  /* 主循环完成后目的地址调整量 */
    uint16_t BITER;      /* 起始主循环计数 */
    uint8_t  CHANNEL_CTRL; /* 通道控制:模式、中断使能等 */
} eDMA_TCD_t;

一次完整的 eDMA 传输由两层循环构成:

  • Minor Loop(小循环): 每次触发完成 NBYTES 字节的传输,源地址和目的地址按 SOFF/DOFF 递增。
  • Major Loop(主循环): 完成 CITER 次小循环后,触发主循环完成事件,可产生中断或启动链式传输。
eDMA 双层循环传输模型 Major Loop(主循环) CITER = 4,每次完成 1 次 Minor Loop Minor Loop 1 NBYTES=64 Minor Loop 2 NBYTES=64 Minor Loop 3 NBYTES=64 Minor Loop 4 NBYTES=64 Major Loop 完成 → 中断 / 链式启动

4.5 Bootloader 中的 DMA 配置要点

在 Bootloader 升级场景中配置 DMA 时,需重点关注以下参数:

  1. 通道优先级: 升级数据通道应设置为高优先级,避免被其他外设 DMA 请求阻塞。
  2. 中断使能: 仅在 Major Loop 完成时产生中断,避免 Minor Loop 频繁中断 CPU。
  3. 地址递增模式: 源地址(外设 FIFO)通常固定不变,目的地址(RAM 缓冲区)递增。
  4. 传输完成回调: 在中断服务函数中启动下一段传输或通知 Bootloader 主状态机。
性能优化提示: 对于 CAN 升级,建议将 DMA 粒度配置为 32-bit(字),每次 Minor Loop 传输 4 字节,Major Loop 计数设为 8(即每次触发传输 32 字节,对应一个标准 CAN 数据帧)。这样可将总线利用率提升至接近 100%。