GD32F4串口dma接收问题解决

1、问题描述

在使用gd32f450时,由于之前没有使用过,所以不太熟悉。板子拿到首先要调试下串口收发,串口接收采用dma。

但是遇到这样的问题,第一次接收正常,但是后面就接收不到了。经过调试,串口空闲中断是可以进入。但是得到的数据长度全部是0

void USART1_IRQHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	uint16_t usart1_rx_len = 0;
	uint8_t data = 0;
	if (RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) //空闲中断
    {
		usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);  // 清除空闲中断标志位
		data = (uint8_t)usart_data_receive(USART1);
		dma_channel_disable(DMA0, DMA_CH5);                     // 关闭DMA传输 
		
		usart1_rx_len = sizeof(uart1_rx_buf) - dma_transfer_number_get(DMA0, DMA_CH5);

//		dma_interrupt_flag_clear(DMA0,DMA_CH5,DMA_INT_FLAG_FTF);
//		dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
//		dma_memory_address_config(DMA0, DMA_CH5,DMA_MEMORY_0, (uint32_t)uart1_rx_buf);
//		dma_transfer_number_config(DMA0, DMA_CH5, sizeof(uart1_rx_buf));
//		usart_dma_receive_config(USART1, USART_DENR_ENABLE); 
		dma_channel_enable(DMA0, DMA_CH5); // 开启DMA传输 
	}
}

代码如上,进入串口中断后,先关闭dma,等数据处理完毕后,再打开dma。就出现了上述描述的现象。

2、问题排查

初步考虑到可能是重新打开dma后要重新初始化部分寄存器于是加入了如下的代码:

dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
dma_memory_address_config(DMA0, DMA_CH5,DMA_MEMORY_0, (uint32_t)uart1_rx_buf);
dma_transfer_number_config(DMA0, DMA_CH5, sizeof(uart1_rx_buf));
usart_dma_receive_config(USART1, USART_DENR_ENABLE);

发现问题依旧,用串口助手发送0xd1
在这里插入图片描述
只有第一次能收到0xd1数据,后面每次就会出现读取到的接收数据长度为0的情况。

既然问题可能是由于重新开启了dma造成的,直接在中断中将
dma_channel_disable(DMA0, DMA_CH5); // 关闭DMA传输
dma_channel_enable(DMA0, DMA_CH5); // 开启DMA传输
全部注释掉。再继续调试。发现依然是第一次收到的数据是正常的,后面每次一次都收不到。

接下来直接看寄存器值的变化,可能是第一次接收后,寄存器的值发生了变化。

查找gd32f4的说明书,发现dma0的地址为0x40046000。dma寄存器最大拍偏移地址为0x114,所有重点要观察0x40046000~0x40046114之间寄存器的值。
在这里插入图片描述
打开硬件调试,初始化串口后,dma所有寄存器的值如下
在这里插入图片描述
第一次发送0xd1,此时进入串口中断后,寄存器的值如下图
在这里插入图片描述
发现只有一个值发生了变化,就是从0x80变成了0x7f,对应的十进制分别是128和127。这几本就确定是接收计数器,默认值是128刚好是设置的dmabuffer长度。

代码再次全速运行,发现偏移地址为5的寄存器数值从0变成0A。
在这里插入图片描述

也就是说从,接收到0xd1这个数据的前后,只有偏移地址为5的寄存器数值从0变成0A。所以接下来需要查这个偏移地址的作用是啥。

在这里插入图片描述
经过查找这个寄存器实际上是中断寄存器,0x0a表示FTFIF5 =1;TAEIF5=1
到这里基本上就有结论了。

中断中没有给dma中断标志位清0

3、问题解决

找出了问题原因那就好办了。直接在在中断中加入清零的函数。
dma_interrupt_flag_clear(DMA0,DMA_CH5,DMA_INT_FLAG_FTF);
经过测试只需要加入清除FTFIF5的函数即可正常运行。

void USART1_IRQHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	uint16_t usart1_rx_len = 0;
	uint8_t data = 0;
	if (RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) //空闲中断
    {
		usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);  // 清除空闲中断标志位
		data = (uint8_t)usart_data_receive(USART1);
		dma_channel_disable(DMA0, DMA_CH5);                     // 关闭DMA传输 
		
		usart1_rx_len = sizeof(uart1_rx_buf) - dma_transfer_number_get(DMA0, DMA_CH5);
		for(int i = 0; i<usart1_rx_len;i++)
		{
		  xQueueSendFromISR(xRxedChars, &uart1_rx_buf[i], &xHigherPriorityTaskWoken);	
		  portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );			
		
		}
dma_interrupt_flag_clear(DMA0,DMA_CH5,DMA_INT_FLAG_FTF);
dma_channel_enable(DMA0, DMA_CH5); 
	}

进入中断后,正常关闭dma,待数据处理完成后,清零dma中断及标志位,然后再打开dma。

  • 15
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
gd32f4是华大基于ARM Cortex-M4核心开发的一款微控制器系列,串口DMA收发是指使用DMA(直接内存访问)功能实现串口通讯数据的接收和发送。 gd32f4系列微控制器内部拥有多个UART串口,配有DMA控制器用于数据的传输。使用串口DMA收发的好处是能够实现高效率的数据传输,减轻CPU的负担,提高系统的实时性。 首先,要使用串口DMA收发,需要先配置UART串口DMA的相关寄存器。通过设置串口的波特率、数据位、停止位等参数,以及使能DMA收发功能,使得串口能够通过DMA控制器进行数据的传输。 在接收数据时,可以通过DMA设置接收缓冲区的地址和大小,并配置正确的接收模式(循环模式或单次模式)。当串口接收到数据时,DMA控制器会将数据直接传输到指定的接收缓冲区,无需CPU的干预。 在发送数据时,同样需要设置DMA发送缓冲区的地址和大小,并配置正确的发送模式。通过设置发送缓冲区的地址和大小,DMA控制器能够直接从指定的发送缓冲区读取数据,并通过串口发送出去,也无需CPU的干预。 当DMA传输完成后,可以通过相应的中断或状态位检测传输的结果,以便做出相应的操作,比如继续发送或接收数据。 串口DMA收发能够大大提高系统的数据传输效率,减少CPU的负担,提高系统的实时性。在使用gd32f4进行串口DMA收发时,需要正确配置相关寄存器和检测传输的状态,以确保数据的可靠传输。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值