MSP430 DMA传输模式深度解析:单次、块与突发块实战指南
1. 项目概述与DMA核心价值
在嵌入式系统开发中,尤其是面对实时数据流处理、高速数据采集或者低功耗应用场景时,我们常常会遇到一个核心矛盾:CPU的算力是宝贵的,如果让它频繁地陷入到简单、重复的数据搬运工作中,比如从ADC的采样寄存器里读取一个值,再存放到内存的某个数组里,那无疑是巨大的浪费。这就好比让一个博士去当快递员,专门负责在两个房间之间传递纸条,他的核心研究能力完全被埋没了。DMA(Direct Memory Access,直接内存访问)技术,就是为了解决这个矛盾而生的“专用快递员”。
简单来说,DMA允许外设(如ADC、UART、SPI)和内存之间,或者内存的不同区域之间,直接进行数据交换,而无需CPU的持续介入。CPU只需要在开始时告诉DMA控制器:“从A地址开始,搬运N个数据到B地址,搬完告诉我一声”,然后就可以去处理其他更重要的计算任务,或者干脆进入低功耗模式睡觉。当DMA完成搬运后,通过一个中断通知CPU:“活儿干完了,数据已经就位,您可以处理了”。这个过程极大地解放了CPU,提升了系统的整体效率和实时性。
本文将以德州仪器(TI)MSP430系列微控制器中的DMA控制器为蓝本,深入剖析其三种核心数据传输模式:单次传输、块传输和突发块传输。很多开发者初次接触DMA时,可能只停留在“启用DMA搬运数据”的层面,但对于不同模式下的行为细节、对CPU的影响以及如何根据应用场景选择最佳模式,往往缺乏深刻理解。我将结合多年的嵌入式开发经验,不仅解读官方手册中的状态图和寄存器配置,更会分享在实际项目中如何权衡选择、如何避开常见陷阱,以及如何通过配置让DMA发挥最大效能。无论你是正在学习DMA的新手,还是希望优化现有代码的资深工程师,相信这些从实战中提炼的细节都能给你带来启发。
2. DMA传输模式深度解析:从单次到突发块
DMA控制器的灵活性很大程度上体现在其可配置的传输模式上。在MSP430的DMA控制器中,通过DMADT(DMA Data Transfer Mode)位域(位于DMAxCTL寄存器)可以配置多达7种模式,但其核心可归纳为三大类:单次传输、块传输和突发块传输,以及它们的“重复”版本。理解这三者的区别,是高效使用DMA的第一步。
2.1 单次传输模式:精细控制的基石
单次传输模式(DMADT = 000b)是DMA最基础的工作方式。在这种模式下,每一次数据传输都需要一个独立的触发信号。你可以把它想象成一个极其听话但“懒散”的搬运工:每收到一个“搬”的指令(触发信号),他才起身搬运一件货物(一个字节或一个字),然后立刻坐下等待下一个指令。
2.1.1 工作流程与寄存器行为
当DMAEN位被置1使能通道后,DMA控制器进入空闲状态,等待触发。一旦触发事件发生(例如ADC转换完成标志置位),DMA控制器会执行以下操作:
- 锁定现场:立即将当前配置的源地址(
DMAxSA)、目的地址(DMAxDA)和传输大小(DMAxSZ)复制到内部的临时寄存器中。这是一个关键细节,意味着后续的地址增减和计数都是基于这些临时副本进行的,原始配置寄存器DMAxSA和DMAxDA的值保持不变。这保证了传输任务的可重复性。 - 执行搬运:从源地址读取一个数据单元(字节或字,由
DMASRCBYTE决定),写入目的地址(由DMADSTBYTE决定)。 - 更新指针:根据
DMASRCINCR和DMADSTINCR的设置,增加或减少内部临时源地址和目的地址寄存器的值。 - 更新计数器:将内部临时传输大小计数器(初始值为
DMAxSZ)减1。 - 检查完成:如果计数器减到0,则设置对应的
DMAIFG中断标志。在单次传输模式下(非重复),DMAEN位会被硬件自动清零,通道停止,等待软件再次使能。如果计数器未到0,则通道返回空闲状态,等待下一个触发。
这个过程清晰地体现在其状态图中:从“Idle”到“Hold CPU, Transfer one word/byte”,再回到“Idle”,形成一个循环,直到DMAxSZ耗尽。
2.1.2 重复单次传输模式:自动续杯
重复单次传输模式(DMADT = 100b)是单次传输的“自动续杯”版本。其核心区别在于:当DMAxSZ递减到0时,DMAEN位不会被清零。硬件会自动将DMAxSZ从临时寄存器中重新加载,通道继续保持使能状态,等待下一个触发信号到来,开启新一轮的DMAxSZ次单次传输。
这个模式非常适合处理周期性但非连续的数据流。例如,一个低频采样的温度传感器,每秒钟产生一个数据。你可以配置DMAxSZ=1,并选择重复单次模式。这样,每次传感器就绪(触发)时,DMA自动搬运一个数据,并且通道永不关闭,无需软件反复初始化。
实操心得:地址递增模式的选择
DMASRCINCR/DMADSTINCR设置为“不变”(00b或01b)时,常用于访问固定地址的外设寄存器,如从ADC结果寄存器(固定地址)读取数据到内存数组(递增地址)。设置为“递增”(11b)是最常见的,用于顺序填充或读取数组。而“递减”(10b)则有其妙用,例如实现内存区域的倒序拷贝,或者在栈操作、某些特定算法中非常方便。不要忽视这个配置,它能让你的数据布局更加灵活。
2.2 块传输模式:一气呵成的数据搬运
当需要搬运一连串连续数据时,单次传输模式效率低下,因为每个数据单元都要等待触发并经历完整的“请求-响应”流程。块传输模式(DMADT = 001b)就是为了解决这个问题而生。在此模式下,一次触发信号可以启动整个数据块的传输。
2.2.1 工作流程与CPU抢占
一旦触发,DMA控制器会“霸占”总线,连续不断地进行数据传输,直到DMAxSZ计数到零。在此期间,CPU被完全挂起,无法执行任何指令。整个块的传输时间是固定的:2 × MCLK × DMAxSZ个时钟周期。传输结束后,CPU恢复执行,DMAEN位被清零(非重复模式下),DMAIFG标志置位。
这就像那个搬运工收到指令后,不再休息,一口气把指定数量的货物全部搬完,期间不允许任何人(CPU)打扰。这种模式的优点是传输效率极高,数据连续性好,没有中间间隔。但代价是会造成CPU停顿,停顿时间与块大小成正比。对于一个需要快速响应的系统,一个过大的DMA块传输可能导致错过其他中断或破坏实时性。
2.2.2 重复块传输模式
类似地,重复块传输模式(DMADT = 101b)在块传输完成后保持DMAEN有效。下一次触发到来时,会自动开始新一轮的整个数据块传输。这适用于需要周期性搬运大量数据的场景,例如定时从内存缓冲区向DAC发送一整段波形数据。
注意事项:块传输期间的触发忽略官方手册明确提到:在块传输或突发块传输开始后,传输过程中发生的后续触发信号会被忽略。这是一个非常重要的行为!假设你配置了ADC每1ms触发一次DMA块传输(块大小为10),但一次块传输需要20个MCLK周期(假设MCLK=1MHz,则为20us)。如果在第5us时又一个ADC触发到来,这个触发是无效的。这意味着触发源的速度必须慢于DMA块传输完成的速度,否则会丢失数据。在设计时,必须计算最坏情况下块传输的耗时,并确保触发间隔大于它。
2.3 突发块传输模式:在效率与响应间走钢丝
突发块传输模式(DMADT = 010b或011b)是DMA设计中最精妙的一种折衷方案。它试图在块传输的高效率和单次传输的CPU可响应性之间找到平衡。
2.3.1 核心机制:交织执行
在这种模式下,DMA并不是一口气搬完整个块。它的策略是:每传输四个数据单元(字节或字)后,主动释放总线,让CPU执行两个MCLK周期。然后DMA再夺回总线,传输下一个“四数据单元”的突发,如此循环,直到整个数据块传输完毕。
官方手册给出了一个关键数据:这导致了20%的CPU执行能力。如何理解这个20%?我们可以算一下:一个周期包含4个传输周期 + 2个CPU周期。CPU周期占比为 2 / (4+2) ≈ 33.3%。但注意,这2个CPU周期是“可用的”,而DMA传输的4个周期里CPU是被挂起的。所以从时间片角度看,CPU获得了约33%的时间片。但手册强调20%的执行能力,可能是考虑了DMA控制器的同步、状态切换等额外开销后的净效率。无论如何,这比块传输的0% CPU可用性强太多了。
2.3.2 应用场景与重复模式
突发块传输非常适合那些数据量较大,但又要求系统不能长时间无响应的场景。例如,在传输一个来自SD卡的大文件到内存时,使用突发块模式可以保证系统仍然能够处理按键扫描、通信协议栈等实时性要求不高但需要定期维护的任务。
重复突发块传输模式(DMADT = 110b或111b)的行为更为特殊:一个突发块传输结束后,DMAEN保持置位,并且无需等待新的触发,下一个突发块传输会立即开始。这实际上创建了一个近乎连续的数据流,CPU持续以20%的能力执行。要停止这种传输,必须由软件主动清除DMAEN位,或者由使能的NMI(不可屏蔽中断)来打断。这种模式可用于创建“后台”数据流,比如持续刷新一个显示缓冲区,而前台CPU仍然可以处理用户交互。
踩坑实录:突发块传输的“四数据单元”边界这个“每四个数据单元”的边界是硬件固定的。如果你的
DMAxSZ不是4的整数倍会怎样?假设DMAxSZ=10。DMA会先传输4个,释放CPU 2周期,再传输4个,释放CPU 2周期,此时还剩2个数据。对于最后这2个,DMA会作为一个“小尾巴”一次性传输完成,然后结束整个块。这意味着最后一个“突发”可能小于4。在计算总时间和评估CPU占用时,需要考虑非对齐的情况。最坏情况下(如DMAxSZ=5),CPU获得的可用周期比例可能会高于20%。
3. 核心寄存器配置与实战编程要点
理解了模式,下一步就是如何通过寄存器配置来实现它们。MSP430的DMA控制器寄存器看似繁多,但结构清晰,每个通道都有自己独立的一套控制寄存器。
3.1 通道控制寄存器DMAxCTL:模式与行为的指挥棒
DMAxCTL是每个DMA通道的“大脑”,其每一位都至关重要。我们结合表格来详细解读:
| 位域 | 名称 | 功能描述 | 配置心得 |
|---|---|---|---|
| 14-12 | DMADT | 传输模式选择。这是本文的核心。000=单次,001=块,010/011=突发块,1xx为对应的重复模式。 | 选择时首要考虑数据连续性、块大小和对CPU响应的要求。小数据、低频触发用单次;大数据块、可接受CPU停顿用块;需兼顾二者用突发块。 |
| 11-10 | DMADSTINCR | 目的地址增减控制。00/01=不变,10=递减,11=递增。 | 通常目的地址(如内存数组)设为递增。若目的地址是外设数据寄存器(如UART发送寄存器),则设为不变。递减可用于反向填充。 |
| 9-8 | DMASRCINCR | 源地址增减控制。配置同DMADSTINCR。 | 通常源地址(如外设ADC结果寄存器)设为不变。若源地址是内存(如向DAC发送波形表),则设为递增。 |
| 7 | DMADSTBYTE | 目的数据宽度。0=字(16位),1=字节(8位)。 | 必须与目的外设或内存访问宽度匹配。向8位外设(如某些DAC低8位)写数据时需设为字节。 |
| 6 | DMASRCBYTE | 源数据宽度。0=字,1=字节。 | 必须与源外设数据宽度匹配。从8位ADC读取时需设为字节。源和目的宽度可以不同,但需谨慎,可能涉及数据对齐和符号扩展问题(需查具体器件手册)。 |
| 5 | DMALEVEL | 触发信号类型。0=边沿触发(上升沿),1=电平触发(高电平)。 | 绝大多数情况使用边沿触发,更可靠。电平触发仅在与特定外部信号DMAE0配合时使用,且要求信号在块/突发块传输期间保持高电平,设计复杂,容易出错。 |
| 4 | DMAEN | DMA通道使能。1=使能。 | 黄金法则:在修改除DMAIFG和DMAREQ之外的任何通道配置寄存器(如DMAxSA,DMAxDA,DMAxSZ,DMAxCTL中的模式、地址增减等)之前,必须确保DMAEN=0。否则可能导致不可预测的触发或传输错误。 |
| 0 | DMAREQ | 软件触发请求。写1启动一次传输。 | 这是一个非常有用的功能。当你需要手动启动一次DMA传输,而不是等待外设触发时,可以将DMAREQ置1。该位会在传输开始后被硬件自动清零。常用于测试或由软件事件触发DMA。 |
3.1.1 地址指针与传输大小寄存器
DMAxSA(Source Address) &DMAxDA(Destination Address):这两个寄存器存放的是传输的起始源地址和目的地址。如前所述,在传输开始时,它们的值会被拷贝到内部临时寄存器,实际的地址增减操作发生在临时寄存器上。这意味着,一次传输任务完成后,DMAxSA和DMAxDA寄存器本身的值又回到了初始设置,为下一次传输(如果是重复模式)做好了准备。这是一个非常巧妙的设计,简化了循环传输的编程。DMAxSZ(Transfer Size):定义了一次传输任务中要搬运的数据单元数量。重要提示:如果DMAxSZ设置为0,则不会发生任何传输,无论触发多少次。在重复模式下,当计数到0时,DMAIFG会置位,同时DMAxSZ会从临时寄存器中自动重载初始值,从而实现连续循环。
3.2 全局控制寄存器与触发配置
除了每个通道的控制寄存器,还有几个全局寄存器控制着DMA控制器的整体行为。
3.2.1 触发源选择寄存器DMACTL0-DMACTL3
每个DMA通道的触发源是独立配置的,通过DMACTL0到DMACTL3中的DMAxTSEL位域选择。触发源可以是定时器的比较匹配事件、ADC转换完成、UART收发缓冲区就绪、甚至是另一个DMA通道完成中断等。关键点:必须在DMAEN=0时修改DMAxTSEL,否则可能产生不可预测的触发。
3.2.2 高级控制寄存器DMACTL4
DMACTL4寄存器包含几个高级控制位:
DMARMWDIS(Read-Modify-Write Disable):此位控制DMA传输是否会打断CPU的“读-修改-写”操作(如BIS.B,BIC.B指令)。当DMARMWDIS=0(默认),DMA传输可能插入到这类指令的中间,可能导致对同一寄存器的原子操作被破坏。当DMARMWDIS=1时,DMA控制器会等待CPU完成当前的读-修改-写操作再开始传输,保证了这类操作的原子性,但可能引入微小延迟。在对关键位域进行操作时,建议置位此位。ROUNDROBIN:轮询优先级使能。默认情况下,DMA通道优先级是固定的(DMA0最高,DMA7最低)。当此位置1时,优先级变为轮询式:刚完成传输的通道会变为最低优先级。这有助于在所有通道都有传输需求时实现公平调度,避免低优先级通道“饿死”。ENNMI:使能NMI中断打断DMA传输。当此位置1时,一个不可屏蔽中断可以中止正在进行的DMA传输(单次、块或突发块)。传输被中止后,DMAABORT标志位会置1。这在需要最高优先级响应紧急事件时非常有用。
4. 实战场景:模式选择与配置案例
理论需要结合实践。下面通过几个典型的嵌入式应用场景,来具体分析如何选择和配置DMA传输模式。
4.1 场景一:低速传感器数据采集(单次传输模式)
需求:使用MSP430的ADC12模块采集一个温度传感器信号,采样率较低,约10Hz(每100ms一次)。需要将每次的采样结果存入一个长度为100的循环缓冲区中。
分析与配置:
- 模式选择:采样率低,数据离散。适合使用重复单次传输模式(
DMADT=100b)。这样只需初始化一次,每次ADC转换完成(触发)就自动搬运一个数据。 - 关键配置:
DMAxSZ = 1:每次触发只搬一个数据。DMASRCINCR = 00b:源地址为ADC12MEM0(固定寄存器地址),不变。DMADSTINCR = 11b:目的地址为内存数组,递增。- 触发源
DMAxTSEL选择ADC12IFG(ADC转换完成中断标志)。 - 使能DMA中断(
DMAIE=1),当目的地址递增100次后(实际由DMAxSZ从1减到0再重载99次,取决于实现),DMAIFG置位,在中断服务程序中可以处理已满的缓冲区。
代码片段示意:
// 假设使用DMA通道0 #define BUFFER_SIZE 100 uint16_t adc_buffer[BUFFER_SIZE]; uint16_t buffer_index = 0; // 用于在中断中跟踪,或使用DMA自动回绕 void init_DMA_for_ADC(void) { __disable_interrupt(); DMA0CTL &= ~DMAEN; // 确保DMA禁用 before configuration DMA0SA = (uint16_t)&ADC12MEM0; // ADC结果寄存器地址 DMA0DA = (uint16_t)&adc_buffer[0]; // 内存缓冲区地址 DMA0SZ = 1; // 每次搬一个字 // 配置控制字:重复单次模式,源地址不变,目的地址递增,字传输,边沿触发 DMA0CTL = DMADT_4 | DMASRCINCR_0 | DMADSTINCR_3 | DMASRCBYTE_0 | DMADSTBYTE_0 | DMALEVEL_0; // 选择ADC12IFG.0作为触发源,具体值需查数据手册,例如可能是 DMA0TSEL_24 DMACTL0 = DMA0TSEL_24; DMA0CTL |= DMAIE; // 使能DMA中断 DMA0CTL |= DMAEN; // 使能DMA通道 __enable_interrupt(); } // DMA中断服务例程 #pragma vector=DMA_VECTOR __interrupt void DMA_ISR(void) { switch(__even_in_range(DMAIV, DMAIV_DMA2IFG)) { case DMAIV_DMA0IFG: // DMA通道0中断 buffer_index = (buffer_index + 1) % BUFFER_SIZE; // 可以在这里处理缓冲区,例如计算平均值、发送数据等 // 注意:DMA0DA寄存器值未变,但内部指针已递增。若需处理,可重新指向缓冲区起始或使用双缓冲区。 break; default: break; } }4.2 场景二:音频数据流播放(块传输模式)
需求:从SPI Flash中读取一段预存的音频PCM数据,通过I2S接口发送给音频编解码器。音频数据是连续的,需要高带宽、低延迟。
分析与配置:
- 模式选择:数据是连续的块,且对传输的连续性要求高,不希望被频繁打断。适合使用块传输模式(
DMADT=001b) 或重复块传输模式(DMADT=101b)。使用重复块模式,配合一个定时器触发,可以形成稳定的数据流。 - 关键配置:
DMAxSZ = 128(示例值,通常为音频缓冲区的一半,配合双缓冲区)。DMASRCINCR = 11b:源地址为内存中的音频数据缓冲区,递增。DMADSTINCR = 00b:目的地址为I2S数据发送寄存器,固定不变。- 触发源
DMAxTSEL选择一个定时器(如TA0CCR0 CCIFG),定时器周期设置为音频采样间隔。 - 注意CPU占用:计算块传输时间
2 * MCLK * DMAxSZ。如果MCLK=8MHz,DMAxSZ=128,则传输时间为2 * (1/8us) * 128 = 32us。在此期间CPU完全停止。如果音频采样率为44.1kHz,周期约为22.7us。这意味着一次DMA传输时间(32us)已经超过了采样周期(22.7us),会导致数据流无法跟上,产生卡顿。此时必须降低DMAxSZ(如改为64),或者提高MCLK频率。
- 双缓冲区技巧:为了避免处理数据时影响播放,常使用双缓冲区(Ping-Pong Buffer)。配置两个DMA通道,或一个通道在中断中切换源地址。当DMA正在从缓冲区A向I2S发送数据时,CPU可以填充缓冲区B。传输完成后触发中断,在中断中切换DMA源地址到缓冲区B,同时CPU填充缓冲区A。
4.3 场景三:实时数据采集与处理(突发块传输模式)
需求:系统需要以1MHz的速率通过ADC连续采集数据,并实时进行简单的滤波运算(如移动平均)。采集不能停顿,同时系统还需要响应一些低速外设(如UART命令、按键扫描)。
分析与配置:
- 模式选择:这是突发块传输模式的典型应用场景。高速连续采集需要DMA高效搬运,但CPU也需要留出时间进行实时处理。突发块传输模式(
DMADT=010b) 是最佳选择。 - 关键配置:
DMAxSZ = 256(较大的块,提高传输效率)。DMASRCINCR = 00b:源地址为ADC结果寄存器,固定。DMADSTINCR = 11b:目的地址为内存中的采集缓冲区,递增。- 触发源选择ADC12IFG(每次转换完成触发)。
- 理解交织过程:DMA每搬运4个ADC样本(假设每个样本2字节,共8字节),就会释放总线2个MCLK周期给CPU。在这短暂的2个周期内,CPU可以执行几条指令。虽然不足以完成复杂的滤波,但可以更新一些状态变量、检查标志位。主要的处理任务(如滤波)应该在DMA传输完成中断(
DMAIFG)中进行,此时CPU拥有100%的控制权,可以处理刚刚采集完的整个数据块(256个样本)。
- 性能估算:假设MCLK=16MHz。传输256个字(512字节)的突发块。总传输周期数大致为:每个“4字突发+2CPU周期”的单元耗时
4字 * 2周期/字 + 2周期 = 10周期。共有256/4=64个这样的单元,总周期约640个。耗时约640 / 16MHz = 40us。在这40us内,CPU获得了64单元 * 2周期/单元 = 128周期的执行时间,约128 / 16MHz = 8us。虽然占比不高,但足以维持系统心跳、处理标志位等。主要的计算负载集中在传输完成后的中断服务程序中。
实操心得:突发块传输的缓冲区管理在突发块传输中,由于传输和CPU执行是交织的,必须特别注意数据一致性。当CPU在DMA释放的间隙访问DMA正在写入的目的缓冲区时,可能读到“半新半旧”的数据。安全的做法是使用“双缓冲区”或“环形缓冲区”,并确保CPU只读取那些已经被DMA完整写入且通过某种机制(如索引、标志位)宣告“就绪”的数据区域。一种常见策略是:DMA向缓冲区A写数据,CPU处理缓冲区B的数据。在DMA传输完成中断中,交换A和B的角色。这需要两个大小相等的缓冲区。
5. 高级话题与疑难问题排查
即使理解了基本模式和配置,在实际项目中依然会遇到各种棘手问题。下面分享一些高级话题和排查经验。
5.1 DMA传输的停止与中止
有时我们需要在传输完成前主动停止DMA。手册提供了两种方法:
- 通过NMI中止:如果
ENNMI位置1,则发生NMI时,会中止当前正在进行的任何传输(单次、块、突发块)。传输被中止后,DMAABORT标志会置1。软件可以检查此标志。注意:被中止的传输是“正常完成当前传输”后停止,还是立即停止,需查具体型号手册,通常是指完成当前正在传输的那个数据单元后停止。 - 通过软件清除DMAEN:对于突发块传输,可以通过软件将
DMAEN位清零来停止传输。但对于单次和块传输,在传输过程中清除DMAEN可能无法立即停止,需要参考具体状态图。最可靠的方式是结合DMAABORT和检查传输状态。
排查技巧:DMA不触发或只触发一次
- 检查
DMAEN位:在非重复模式下,传输完成后DMAEN会被自动清零。如果你期望持续触发,需要检查代码是否在中断或主循环中重新置位了DMAEN。- 检查触发源:确认你选择的触发源(
DMAxTSEL)确实能产生预期的信号。例如,如果你选择定时器CCIFG作为触发,要确保定时器已正确配置并运行,且相应的CCIE位没有被置位(因为如果中断使能,标志可能不会触发DMA)。- 检查
DMALEVEL:如果你使用的是边沿触发(默认),确保触发信号是上升沿。如果是电平触发,确保信号在传输期间保持高电平(对于块/突发块传输尤其重要)。- 检查
DMAxSZ:确认DMAxSZ不为0。
5.2 DMA与中断的优先级及互斥
DMA传输的优先级高于普通系统中断。这意味着:
- DMA传输不可被普通中断打断:一个正在进行的DMA传输会阻塞所有系统中断,直到传输结束。这些中断会保持挂起状态。
- 中断服务程序可能被DMA传输打断:如果你的中断服务程序执行时间较长,可能会被DMA传输插入打断。如果ISR和DMA访问了共享资源(如全局变量、缓冲区),需要小心竞态条件。
建议:对于时间关键且不能被DMA打断的代码段(临界区),可以在进入前禁用DMA(清除DMAEN位),退出后再使能。或者,利用DMARMWDIS位来保护读-修改-写操作。
5.3 低功耗模式下的DMA
DMA的一大优势是支持低功耗运行。即使CPU处于LPM3/LPM4等深度睡眠模式(MCLK关闭),DMA控制器在收到触发信号后,可以临时唤醒DCOCLK(或使用可用时钟)来完成一次传输,然后系统再次进入睡眠。这在电池供电的传感器应用中极其有用,CPU可以长时间睡眠,仅由DMA响应外设事件搬运数据。
配置要点:确保DMA的触发源在低功耗模式下仍然有效(例如,使用低频ACLK驱动的定时器作为触发源)。同时,注意表7-3中提到的,在LPM3/4模式下,如果MCLK源是关闭的,DMA启动需要额外的约5µs来唤醒DCOCLK,这会在第一次传输时增加延迟。
5.4 多通道DMA与优先级
当多个DMA通道同时被触发时,需要优先级仲裁。默认是固定优先级(DMA0最高)。ROUNDROBIN位可以启用轮询优先级,更公平。关键行为:如果一个低优先级通道的传输已经开始,此时一个高优先级通道被触发,高优先级通道必须等待低优先级通道的当前整个传输(单次、块或突发块)完成后,才能开始。它不会抢占正在进行的传输。这在设计多通道系统时需要考虑时序。
6. 与常见外设的协同工作示例
DMA的真正威力在于和外设的无缝配合。这里简要提两个最常用的组合。
6.1 DMA + ADC12这是最经典的组合。ADC连续采样,每个采样完成产生一个ADC12IFG,触发DMA将数据从ADC12MEMx搬移到内存。可以配置为单次模式(每次采样搬一次)或块传输模式(采样多个点后统一搬运)。在重复模式下,可以实现“采集-搬运”的无限循环,极大减轻CPU负担。
6.2 DMA + DAC12用于信号生成。将一段波形数据(如正弦表)存放在内存中,配置DMA为重复块传输模式,由一个定时器定期触发。DMA自动将波形数据逐个搬移到DAC12_xDAT寄存器,从而在无需CPU干预的情况下产生连续的模拟波形。这是实现低功耗波形发生的绝佳方法。
理解DMA控制器的单次、块和突发块传输模式,是掌握高效嵌入式数据搬运的关键。从精细控制的单次触发,到一气呵成的块传输,再到平衡效率与响应性的突发块传输,每种模式都有其独特的适用场景。成功的DMA应用离不开对寄存器细节的精准把握、对时序的周密计算以及对系统整体架构(如缓冲区管理、中断协同)的深思熟虑。希望本文的深入解析和实战经验,能帮助你在下一个嵌入式项目中,游刃有余地驾驭DMA这把利剑,打造出更高性能、更低功耗的系统。