25、DMA错误处理:DMA传输超时、总线错误、描述符错误等异常情况的检测与恢复机制,编写健壮的DMA错误处理代码

发布时间:2026/10/7 15:20:57
25、DMA错误处理:DMA传输超时、总线错误、描述符错误等异常情况的检测与恢复机制,编写健壮的DMA错误处理代码 疼的问题之一。我记得有一次调试摄像头数据流DMA传着传着就停了查了两天才发现是描述符链的最后一个节点没有正确设置「链结束标志」。来看一个健壮的描述符初始化代码// 初始化DMA描述符链// 返回0成功-1失败int32_t dma_desc_chain_init(DMA_Channel_t *chan,DMA_Desc_t *desc_array,uint32_t desc_count){uint32_t i;// 参数检查——别嫌啰嗦这是血的教训if (desc_array NULL || desc_count 0) {DMA_ERR(描述符参数无效\n);return -1;}// 检查描述符地址对齐MTK要求32字节对齐if ((uint32_t)desc_array 0x1F) {DMA_ERR(描述符未对齐: addr0x%x\n, desc_array);return -1;}// 逐个初始化描述符for (i 0; i desc_count; i) {// 清空描述符memset(desc_array[i], 0, sizeof(DMA_Desc_t));// 配置传输参数desc_array[i].src_addr chan-src_addr i * chan-blk_size;desc_array[i].dst_addr chan-dst_addr i * chan-blk_size;desc_array[i].blk_size chan-blk_size;// 链接到下一个描述符if (i desc_count - 1) {desc_array[i].next_desc desc_array[i 1];desc_array[i].flags | DMA_DESC_FLAG_CHAIN;} else {// 最后一个描述符设置结束标志desc_array[i].next_desc NULL;desc_array[i].flags | DMA_DESC_FLAG_LAST;}}// 保存描述符链信息chan-desc_head desc_array[0];chan-desc_tail desc_array[desc_count - 1];chan-desc_count desc_count;return 0;}注意 描述符链一旦建立就不要在DMA传输过程中修改它。我曾经试过动态添加描述符结果DMA读到一半指针变了直接总线错误。如果要动态管理请确保DMA处于停止状态。六、总线错误地址问题要「防患于未然」总线错误十有八九是地址问题。要么是源地址不可访问要么是目的地址写保护了。我在MTK平台上遇到过最奇葩的情况——DMA访问了SRAM的保留区域直接触发总线错误。所以我建议在启动DMA之前先做一次地址合法性检查// DMA地址合法性检查// 返回0合法-1非法int32_t dma_addr_check(uint32_t addr, uint32_t size, uint32_t dir){// 检查地址是否在有效内存范围内if (dir DMA_DIR_MEM_TO_MEM) {// 源地址和目的地址都必须在DRAM/SRAM范围内if (!is_valid_mem_range(addr, size)) {DMA_ERR(DMA地址越界: addr0x%x, size%d\n, addr, size);return -1;}} else if (dir DMA_DIR_PERIPH_TO_MEM) {// 外设到内存目的地址必须在内存范围if (!is_valid_mem_range(addr, size)) {DMA_ERR(DMA目的地址无效: addr0x%x\n, addr);return -1;}// 源地址检查外设是否使能if (!is_periph_enabled(addr)) {DMA_ERR(外设未使能: addr0x%x\n, addr);return -1;}}// 检查地址对齐MTK要求4字节对齐if (addr 0x3) {DMA_ERR(DMA地址未对齐: addr0x%x\n, addr);return -1;}return 0;}你想想看这个检查函数虽然增加了启动前的开销但能避免90%的总线错误。这笔账怎么算都划算。七、总结健壮DMA错误处理的「三板斧」好了说了这么多我总结一下DMA错误处理的核心思路第一板斧检测要全面——打开所有错误中断定期轮询状态寄存器第二板斧恢复要温和——先软复位再硬复位别一上来就放大招第三板斧预防要到位——启动前检查地址、对齐、描述符链完整性说白了DMA错误处理就像开车——你不能等撞了才打方向盘得提前预判。把错误检测和恢复机制写进代码里让系统自己会「刹车」和「修车」这才是嵌入式工程师该有的素养。