2. S32K3 DMA控制器架构:DMA模块框图、通道结构、传输引擎、请求与仲裁机制
S32K3 的 DMA(Direct Memory Access)控制器是一个高性能、多通道、可编程的数据搬运引擎。理解其内部架构是进行中断协同设计的前提。本节将深入剖析 DMA 模块的顶层框图、通道结构、传输引擎的工作模式以及请求与仲裁的完整流程。
2.1 DMA模块顶层框图
S32K3 DMA 控制器基于 Arm CoreLink DMA-330 架构,集成了多个关键子模块。下图展示了其内部核心组件与系统总线的连接关系。
2.2 通道结构(Channel Structure)
每个 DMA 通道对应一个独立的传输上下文。S32K3 支持多达 32 个 DMA 通道,每个通道的核心数据结构是 通道控制块(CCB, Channel Control Block)。CCB 存储在系统内存中,由 DMA 控制器通过描述符链表(Descriptor List)进行管理。
2.2.1 通道控制块(CCB)关键字段
| 字段 | 位宽 | 描述 |
|---|---|---|
| 源地址(SA) | 32-bit | 数据传输的源起始地址。支持递增、递减或固定模式。 |
| 目的地址(DA) | 32-bit | 数据传输的目的起始地址。支持递增、递减或固定模式。 |
| 传输计数(TC) | 24-bit | 本次传输需要搬运的数据单元数量(最大 16,777,215)。 |
| 传输宽度(TW) | 2-bit | 每次传输的数据宽度:8-bit(字节)、16-bit(半字)、32-bit(字)。 |
| 传输类型(TT) | 2-bit | 内存到内存、内存到外设、外设到内存、外设到外设。 |
| 中断使能(IE) | 1-bit | 传输完成或发生错误时是否产生中断。 |
| 下一描述符指针(NDP) | 32-bit | 指向链表中下一个 CCB 的地址,用于实现连续传输。 |
2.2.2 描述符链表(Descriptor Chain)
DMA 通道支持 链表传输模式。一个通道可以关联多个 CCB,形成一个单向链表。当当前 CCB 的传输计数归零后,DMA 控制器自动加载 NDP 指向的下一个 CCB,继续执行新的传输任务,无需 CPU 干预。
2.3 传输引擎(Transfer Engine)
传输引擎是 DMA 的实际执行单元,包含一个 微序列器(Micro-Sequencer)。它负责解析 CCB 中的配置,生成地址序列,并驱动 AHB/AXI 总线进行读写操作。
2.3.1 传输引擎工作流程
- 加载 CCB:从系统内存中读取当前通道的 CCB 到内部寄存器。
- 地址生成:根据源/目的地址模式(递增、递减、固定)计算下一次读/写地址。
- 总线请求:向总线仲裁器发起读/写请求。
- 数据搬运:执行一次读操作(源地址),然后执行一次写操作(目的地址)。
- 计数更新:递减传输计数(TC)。
- 循环判断:如果 TC 不为 0,重复步骤 2-5;如果 TC 为 0,检查 NDP 并加载下一个 CCB 或触发中断。
2.3.2 传输模式对比
| 模式 | 描述 | 典型应用场景 |
|---|---|---|
| 单次传输(Single Transfer) | 每次 DMA 请求只搬运一个数据单元(字节/半字/字)。 | 低速外设(如 UART 单字节收发)。 |
| 突发传输(Burst Transfer) | 一次 DMA 请求连续搬运多个数据单元(突发长度可配置,如 4/8/16 次)。 | 高速外设(如 ADC 多通道扫描、SPI FIFO 填充)。 |
| 链表传输(Linked Transfer) | 通过 NDP 指针自动加载下一个 CCB,实现连续多段传输。 | 多缓冲区循环采集、乒乓缓冲(Ping-Pong Buffer)。 |
2.4 请求与仲裁机制
DMA 传输的启动依赖于 DMA 请求。S32K3 通过 DMA 多路复用器(DMA Mux) 将外设的请求信号路由到指定的 DMA 通道。当多个通道同时请求传输时,仲裁器 根据优先级决定哪个通道获得总线使用权。
2.4.1 DMA 请求源
- 硬件请求:来自外设(ADC、SPI、UART、定时器等)的硬件触发信号。每个外设可以映射到任意一个 DMA 通道。
- 软件请求:通过设置 DMA 通道的软件触发寄存器(SSBR)启动传输,常用于内存到内存的拷贝。
- 链式请求:一个 DMA 通道传输完成后,可以自动触发另一个 DMA 通道(通过链式传输或中断联动)。
2.4.2 DMA 多路复用器(DMA Mux)
DMA Mux 是一个可编程的交叉开关,将外设的 DMA 请求信号连接到对应的 DMA 通道。每个 DMA 通道都有一个对应的 Mux 配置寄存器,用于选择请求源。
2.4.3 仲裁策略
S32K3 DMA 支持两种仲裁模式,可通过寄存器配置:
| 仲裁模式 | 工作原理 | 适用场景 |
|---|---|---|
| 固定优先级(Fixed Priority) | 通道 0 优先级最高,通道 31 优先级最低。高优先级通道总是优先获得总线。 | 需要严格实时响应的外设(如高速 ADC 数据流)。 |
| 轮询(Round-Robin) | 所有通道轮流获得总线使用权,避免低优先级通道被饿死。 | 多个中等速率外设同时工作,需要公平带宽分配。 |
| 混合模式 | 将通道分组,组内使用固定优先级,组间使用轮询。 | 既有高实时性需求,又有公平性需求的复杂系统。 |
2.5 中断协同设计要点
基于上述架构,在数据采集场景中进行中断协同设计时,需要关注以下关键点:
- 中断源选择:每个 DMA 通道可以独立配置传输完成中断、错误中断。在链表传输中,通常只在链表末尾的 CCB 使能中断,避免频繁中断。
- 中断优先级:DMA 中断在 NVIC 中的优先级应高于普通外设中断,但低于 CPU 的紧急任务(如系统时钟中断)。
- 数据一致性:在 DMA 传输完成后,CPU 读取数据前,需要执行数据同步指令(如
__DSB())或使用带缓存一致性的内存区域(如 TCM 或 SRAM 的特定区域)。 - 错误处理:DMA 传输错误(如总线错误、对齐错误)会触发错误中断。建议在中断服务函数中检查错误状态寄存器,并执行恢复操作(如复位 DMA 通道、重新初始化描述符链表)。
// 示例:DMA 传输完成中断服务函数(伪代码)
void DMA0_IRQHandler(void) {
uint32_t status = DMA->INT_STATUS; // 读取中断状态
uint32_t channel = (status & 0x1F); // 获取触发中断的通道号
if (status & DMA_INT_TC) { // 传输完成中断
// 1. 清除中断标志
DMA->INT_CLEAR = (1 << channel);
// 2. 读取数据(确保数据一致性)
__DSB();
process_data(channel);
// 3. 重新启动 DMA(如果是循环采集模式)
if (loop_mode) {
DMA->SSBR = (1 << channel); // 软件触发重新开始
}
}
if (status & DMA_INT_ERR) { // 错误中断
// 1. 清除错误标志
DMA->ERR_CLEAR = (1 << channel);
// 2. 读取错误类型
uint32_t err_type = DMA->ERR_STATUS;
// 3. 执行错误恢复
recover_dma_channel(channel);
}
}