打印
[研电赛技术支持]

GD32F427 串口空闲中断+DMA 遇BUG

[复制链接]
124|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-12-3 16:43 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
近期移植GD32F1到GD32F4,测试DMA串口空闲中断,F1可以运行但F4发现存在BUG。
问题:第一次串口助手发送数据,助手能正常显示接收长度和回显发送的字符;但是第二次发送数据的时候,助手异常显示长度为0,且回显不了字符。
现象如下:



附上中断代码:


// USART0 中断处理函数
void USART0_IRQHandler(void) {
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) != 0) {  // 读空闲中断标志
                                usart_flag_get(USART0, USART_FLAG_IDLE);                                                                        // 先读STAT0
        usart_data_receive(USART0);                                                                                                              // 再读DATA寄存器-这两个操作目的是:清除空闲标志位
                               
                                //当前接收长度: 总的长度 - dma剩余的长度
                                U0CB.URxCounter += (U0_RX_MAX+1) - dma_transfer_number_get(DMA1,DMA_CH5);
                       
                                //IN指针的end 指向 当前缓冲区的已有值末尾的位置
                                U0CB.URxDataIN->end = &U0_RXBuff[U0CB.URxCounter - 1];

                       
                                if(U0CB.URxDataIN == U0CB.URxDataEND){                //如果IN指针指向了END 代表缓冲区已满
                                         U0CB.URxDataIN = &U0CB.URxDataPtr[0];        //回到缓冲区开头
                                }else{
                                                //IN指针指向下一组
                                                U0CB.URxDataIN++;
                                }
                               
                                if(U0_RX_SIZE - U0CB.URxCounter >= U0_RX_MAX){ //如果当前缓存区的位置还能存下一次数据的最大长度
                                                U0CB.URxDataIN->start = &U0_RXBuff[U0CB.URxCounter]; //start指向当前缓冲区的下一次数据首
                                }else{
                                                U0CB.URxDataIN->start = U0_RXBuff; //如果不够,就回卷到缓冲区开头
                                          U0CB.URxCounter = 0;  //计数值也跟着回卷
                                }       
                               
                                //重新配置DMA
        dma_channel_disable(DMA1, DMA_CH5);   // 禁用 DMA 通道
                                dma_transfer_number_config(DMA1, DMA_CH5,U0_RX_MAX+1);
                                dma_memory_address_config(DMA1, DMA_CH5, DMA_MEMORY_0, (uint32_t)U0CB.URxDataIN->start);//地址是下一次数据位置
                                dma_channel_enable(DMA1, DMA_CH5);    // 重新启用 DMA 通道
                                  

    }
}

解决方案:
添加“清除DMA完成标志”
dma_flag_clear(DMA1, DMA_CH5, DMA_FLAG_FTF);            // 清除DMA完成标志

                dma_channel_disable(DMA1, DMA_CH5);                                           // 禁用 DMA 通道
                dma_flag_clear(DMA1, DMA_CH5, DMA_FLAG_FTF);                        // 清除DMA完成标志
                dma_transfer_number_config(DMA1, DMA_CH5,U0_RX_MAX+1);        // 重配置dma大小
                dma_memory_address_config(DMA1, DMA_CH5, DMA_MEMORY_0, (uint32_t)U0CB.URxDataIN->start);//地址是下一次数据位置
                dma_channel_enable(DMA1, DMA_CH5);                                            // 重新启用 DMA 通道
附上效果图



————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/cccmjjj/article/details/144154911

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1981

主题

15794

帖子

12

粉丝