4. DMA与MDMA在图像搬运中的实战
在STM32N6的图像处理链路中,CPU不应承担大块像素搬运工作。真正高效的做法是让DMA2D负责2D图形加速与格式转换,让MDMA负责高带宽、带步长的线性搬运,两者配合形成“搬运—转换—再搬运”的数据通路。本节围绕这两类引擎的实际配置展开,重点讲清2D寻址、行偏移、突发传输以及双缓冲/乒乓缓冲的实现方式。
一、DMA2D与MDMA的分工
DMA2D是专为2D图形设计的加速器,支持前景层、背景层和输出层的独立地址与偏移配置,能完成ARGB8888、RGB888、RGB565、L8等格式之间的转换、Alpha混合和矩形填充。它的核心参数是每层的起始地址、行偏移(Line Offset)、像素格式和区域尺寸。MDMA则是通用多维DMA,支持源/目的地址递增、固定或2D步进模式,适合把摄像头DCMI输出的行数据、DMA2D输出的大块RGB数据搬到外部PSRAM或从PSRAM搬到内部SRAM。
典型分工是:DCMI → MDMA(按行搬运,带行步进)→ 内部SRAM帧缓冲 → DMA2D(格式转换/缩放/混合)→ MDMA(搬回PSRAM或送LCD)。这样CPU只做配置和中断响应,不参与逐像素操作。
二、2D寻址与行偏移的本质
图像在内存中是按行连续存放的,但一行像素数往往不等于缓冲区宽度。例如一幅320×240的RGB565图像,若缓冲区按320像素对齐,则每行字节数为320×2=640字节;若为了对齐到32字节边界,实际行跨度可能被填充为672字节。此时行偏移就是相邻两行起始地址之差,而不是图像宽度本身。
DMA2D的Line Offset寄存器(如DMA2D_FGOR、DMA2D_BGOR、DMA2D_OOR)以像素为单位填写,硬件会自动乘以像素字节数。MDMA的2D模式则通过Source/Destination Increment Offset和Block Repeat实现类似效果:每搬完一行,地址跳转到下一行起点,而不是简单累加。
三、突发传输与带宽匹配
MDMA和DMA2D都支持突发(Burst)传输。突发长度决定了一次总线请求搬运多少数据,常见配置为4、8、16个节拍。突发越长,总线利用率越高,但延迟也越大。对于图像搬运,建议:
- 源端和目的端都支持突发时,优先使用INCR16或INCR8;
- 若目的端是外部PSRAM,突发长度不宜过大,避免占用总线过久影响其他主设备;
- DMA2D输出到LCD时,可配合LTDC的FIFO阈值,使用中等突发(INCR4/INCR8)平衡实时性。
此外,MDMA的SWRQ软件请求和Channel优先级需要与DCMI、LTDC等外设协调,避免高优先级通道长期占用总线导致摄像头丢行。
四、双缓冲与乒乓缓冲的实现
双缓冲的核心是准备两块帧缓冲A和B,DMA2D或MDMA写其中一块时,另一块可被读取或显示。乒乓缓冲则进一步用两个指针交替切换,配合传输完成中断实现无缝衔接。
以DMA2D为例,配置输出到缓冲A,启动传输;在DMA2D_IRQHandler中判断TCIF标志,切换输出地址到缓冲B,再次启动。同时,LTDC或后续处理读取另一块缓冲。关键点是:切换地址必须在传输完成中断中完成,且切换前要确保旧缓冲已被消费。
// 乒乓缓冲切换示意(伪代码)
volatile uint8_t buf_idx = 0;
uint32_t fb_addr[2] = {FB0_ADDR, FB1_ADDR};
void DMA2D_IRQHandler(void) {
if (DMA2D->ISR & DMA2D_ISR_TCIF) {
DMA2D->IFCR = DMA2D_IFCR_CTCIF;
buf_idx ^= 1;
DMA2D->OOR = LINE_OFFSET;
DMA2D->OMAR = fb_addr[buf_idx];
DMA2D->CR |= DMA2D_CR_START;
}
}
若使用MDMA做搬运,则利用MDMA_CxBRUR和MDMA_CxSAR/DAR在中断中重载地址,或使用MDMA的链表(Linked List)模式自动切换描述符,减少CPU干预。
五、配置检查与常见问题
实际调试时,建议按以下顺序核对:先确认源/目的地址是否按像素格式对齐(RGB565需2字节对齐,ARGB8888需4字节对齐);再核对行偏移是否等于实际行跨度;然后检查突发长度与总线位宽是否匹配;最后确认乒乓切换是否在TC中断中完成,且切换前旧缓冲已被消费。
常见现象与判断:图像整体偏移 → 行偏移错误;图像出现横向撕裂 → 乒乓切换时机不对或未等待VSYNC;传输速度不达标 → 突发长度过小或MDMA优先级被抢占;颜色异常 → DMA2D像素格式或Alpha模式配置错误。把这些检查点固化到初始化函数中,可以显著减少图像搬运类问题的排查时间。