2. TC3xx DMA模块架构:整体框图与关键模块详解

好,咱们进入正题。DMA这东西,说白了就是帮CPU干苦力的。CPU本来要一个个搬数据,有了DMA,它只需要说一声“开始搬”,然后就可以去忙别的了。TC3xx的DMA模块,我当年第一次看框图时,说实话有点懵——模块挺多,通道也不少。但拆开来看,其实就那几大块。

2.1 DMA模块整体框图

先看整体。TC3xx的DMA系统,核心是一个多通道、多传输引擎的架构。我习惯把它想象成一个“数据搬运调度中心”。

整个模块大致分三层:

  • 顶层控制:DMA控制器,负责全局配置、中断管理、错误处理。
  • 中间层:多个DMA通道,每个通道独立配置源地址、目的地址、传输大小等。
  • 底层执行:传输引擎,真正干活的——从源读数据,写到目的去。

嗯,这里要注意:TC3xx的DMA不是每个通道配一个传输引擎,而是多个通道共享几个传输引擎。为什么这么设计?说白了是为了节省硬件资源。你想想看,如果同时只有两三个通道在传输,配八个引擎就是浪费。

关键点:DMA控制器 + N个通道 + M个传输引擎(M通常小于N)。通道负责“规划”,引擎负责“执行”。

2.2 DMA控制器(DMA Controller)

DMA控制器是整个模块的大脑。它管三件事:

  1. 通道调度:决定哪个通道的请求先被处理。我记得TC3xx支持固定优先级和轮询两种模式。固定优先级适合紧急任务,轮询适合公平分配带宽。
  2. 中断管理:每个通道可以独立产生传输完成、错误等中断。我在项目中遇到过一个问题——多个通道同时触发中断,CPU处理不过来。后来我建议用中断合并,把多个通道的中断合并成一个,CPU压力小很多。
  3. 错误处理:比如源地址不对齐、总线错误等。控制器会记录错误状态,并可以配置是否重试或终止传输。

个人经验:我习惯在初始化时,先把所有通道的中断都关掉,等配置好了再逐个打开。这样可以避免配置过程中误触发中断。

2.3 DMA通道(DMA Channel)

每个通道就是一个“任务描述符”。你告诉它:从哪搬(源地址)、搬到哪(目的地址)、搬多少(传输长度)、怎么搬(传输模式)。

通道的配置寄存器,我列个表,大家一目了然:

寄存器 功能 我踩过的坑
SRC_ADDR 源地址 必须对齐到传输宽度,否则会触发错误
DST_ADDR 目的地址 同样要对齐,尤其是外设地址
CH_CTRL 通道控制(使能、中断、优先级等) 使能前一定要确认所有配置已完成
TRANS_LEN 传输长度(字节数) 我曾经设成0,结果DMA直接不干活
CH_STATUS 通道状态(忙、完成、错误) 轮询状态时记得加超时,防止死等

通道还有一个重要概念——传输模式。TC3xx支持单次传输、连续传输、链表传输等。我个人最常用的是链表传输,因为它可以一次配置多个传输任务,DMA自己按顺序执行,CPU完全不用管。

避坑指南:我曾经在链表传输时,忘记把最后一个节点的“下一跳”指针设为NULL,结果DMA跑飞了,一直读到非法地址。嗯,从那以后我每次都会检查链表结尾。

2.4 传输引擎(Transfer Engine)

传输引擎是真正的“苦力”。它从通道拿到任务,然后执行:

  • 从源地址读数据
  • 把数据写到目的地址
  • 更新地址指针和计数器
  • 如果传输完成,通知通道

TC3xx的传输引擎支持多种数据宽度:8位、16位、32位、64位。你想想看,如果源是8位的外设,目的是32位的内存,引擎会自动做数据拼接。这个功能很实用,我曾在采集ADC数据时用过——ADC输出16位,我直接配成32位传输,一次搬两个采样值,效率翻倍。

引擎还有一个特性叫突发传输(Burst Transfer)。说白了就是一次总线请求搬多个数据,而不是搬一个请求一次。突发传输能大幅提高总线利用率。我建议:如果传输长度较大(比如超过64字节),一定要开启突发模式。

核心总结:DMA控制器管调度,通道管配置,引擎管执行。三者配合,CPU就可以安心睡大觉了。

2.5 模块间的数据流

最后,我画个简单的数据流图(文字版):

外设/内存 → 请求信号 → DMA控制器(调度)
                              ↓
                        DMA通道(配置)
                              ↓
                       传输引擎(执行)
                              ↓
                       源地址 → 读数据 → 写数据 → 目的地址
                              ↓
                       传输完成 → 中断/轮询 → CPU

为什么会这样设计?说白了,就是为了解耦。通道只管“做什么”,引擎只管“怎么做”,控制器只管“谁先做”。每个模块职责单一,出了问题也好排查。

嗯,这一节就到这里。下一节我会讲DMA的传输模式,包括单次、连续、链表等,到时候我会结合一个实际项目中的例子来讲,大家敬请期待。