GD32F4xx串口收发,DMA+空闲中断

GD32F4xx系列的串口收发DMA+空闲中断基础配置:(这里主要是以DMA+空闲中断为例)
原理就不赘述了,网上资料很多,这里直接进行配置和测试。

1,首先添加GD32F4xx的dma外设库函数文件到工程中。
在这里插入图片描述
2,新建一个uart_dma.c文件并添加到工程中。
在这里插入图片描述
3,配置串口的DMA传输。
这里以USART1为例进行配置,配置不同的串口需要通过GD32F4xx用户手册找到对应的DMA编号和通道
在这里插入图片描述
在这里插入图片描述
代码编写:

uart_dma.c文件

//通过上面的表格可以发现USART1  Tx对应DMA0 的通道6,rx对应DMA0的通道5,因此在进行DMA配置的时候可以按照表格进行配置
uint8_t g_send_data[256];//发送数据
uint8_t g_recv_data[256];//接收数据


int32_t uart_dma_init(void)
{
	usart_deinit(USART1);
	usart_disable(USART1);
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_USART1);
	gpio_af_set(GPIOA,GPIO_AF_7,GPIO_PIN_2|GPIO_PIN_3);
	gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2|GPIO_PIN_3);
	gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2|GPIO_PIN_3);
	nvic_irq_enable(USART1_IRQn,5,0);
		
	usart_baudrate_set(USART1,9600);
	usart_parity_config(USART1,USART_PM_NONE);
	usart_word_length_set(USART1,USART_WL_8BIT);
	usart_stop_bit_set(USART1,USART_STB_1BIT);
	usart_hardware_flow_coherence_config(USART1,USART_HCM_NONE);
	usart_data_first_config(USART1,USART_MSBF_LSB);
	
	usart_enable(USART1);
	
	usart_transmit_config(USART1,USART_TRANSMIT_ENABLE);
	usart_receive_config(USART1,USART_RECEIVE_ENABLE);
	
	usart_dma_transmit_config(USART1, USART_DENT_ENABLE);//打开串口DMA发送
	usart_dma_receive_config(USART1, USART_DENR_ENABLE);//打开串口DMA接收
	
	usart_flag_clear(USART1, USART_FLAG_TC);
	usart_interrupt_enable(USART1,USART_INT_IDLE);//使用串口空闲中断
	
    return 0;
}

int32_t usart_dma_tx_init(void)
{
	dma_single_data_parameter_struct dma_init_struct;
    /* enable DMA0 */

	rcu_periph_clock_enable(RCU_DMA0);

    /* deinitialize DMA channel6(USART1 tx) */
    dma_deinit(DMA0, DMA_CH6);//Tx对应DMA0 通道6
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr = (uint32_t)g_send_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = sizeof(g_send_data);
    dma_init_struct.periph_addr = (uint32_t)(&USART_DATA(USART1));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_struct);
    dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI4);
    //configure DMA mode 
    dma_circulation_disable(DMA0, DMA_CH6);
	return 0;
}

int32_t usart_dma_rx_init(void)
{
	dma_single_data_parameter_struct dma_parameter;
    /* enable DMA0 */
	rcu_periph_clock_enable(RCU_DMA0);


    /* 接收 dm0 channel5(USART1 rx) */
    dma_deinit(DMA0, DMA_CH5);//rx对应DMA0通道5
    dma_parameter.direction = DMA_PERIPH_TO_MEMORY;
    dma_parameter.periph_addr = (uint32_t)(&USART_DATA(USART1));
    dma_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_parameter.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_parameter.memory0_addr = (uint32_t)g_recv_data;
    dma_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_parameter.number = sizeof(g_recv_data);
    dma_parameter.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_parameter.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_single_data_mode_init(DMA0, DMA_CH5, &dma_parameter);

    /* configure DMA mode */
    dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
    dma_channel_enable(DMA0, DMA_CH5);
	return 0;
}

/**
  * @brief  调试信息发送接口
  * @param  data:调试数据指针;\
  *	        len:调试数据的数据长度
  * @retval 0或其他错误代码
 **/
int32_t uart_dma_send(uint8_t *data,uint32_t len) 
{
	usart_flag_clear(USART1, USART_FLAG_TC);

	dma_channel_disable(DMA0, DMA_CH6);
	dma_flag_clear(DMA0, DMA_CH6, DMA_FLAG_FTF);
	dma_memory_address_config(DMA0, DMA_CH6, DMA_MEMORY_0, (uint32_t)data);
	dma_transfer_number_config(DMA0, DMA_CH6, len);
	dma_channel_enable(DMA0, DMA_CH6);
	while (usart_flag_get(USART1, USART_FLAG_TC)!=RESET);
	return 0;
}

int32_t uart_dma_stop(void)
{
    usart_disable(USART1);
    return 0;
}

gd32f4xx_it.c文件
extern uint32_t g_recv_data[256];

void USART1_IRQHandler(void)
{
	uint32_t recv_len=0;
	if(usart_interrupt_flag_get(USART1,USART_INT_FLAG_IDLE) != RESET)
	{
		usart_interrupt_flag_clear(USART1,USART_INT_FLAG_IDLE);
		USART_STAT0(USART1);
		USART_DATA(USART1);
		dma_channel_disable(DMA0, DMA_CH5);
		recv_len = sizeof(g_recv_data) - dma_transfer_number_get(DMA0, DMA_CH5);
		if(recv_len != 0 && recv_len < sizeof(g_recv_data))
		{
			//memcpy(g_serial_recv_buf,data_buffer,g_recv_positin); ///* 转存数据到待处理数据缓冲区
		
			// 重新设置DMA传输 
			dma_memory_address_config(DMA0, DMA_CH5,(uint32_t)g_recv_data,DMA_MEMORY_0);
			dma_transfer_number_config(DMA0, DMA_CH5,sizeof(g_recv_data));
			dma_flag_clear(DMA0, DMA_CH5, DMA_FLAG_FTF);
			dma_channel_enable(DMA0, DMA_CH5);		///* 开启DMA传输 
		}
		else
		{
			memset(g_recv_data,0,sizeof(g_recv_data));
		}
	}
	return ;
}

4,配置完成后,同样我们再main函数中调用初始化并进行串口数据发送
在这里插入图片描述
5,连接好串口和MCU,使用串口工具设置波特率9600 和相关配置与MCU串口初始化一致,打开串口工具可以接收到MCU发送过来的数据。
在这里插入图片描述
修改发送的数据内容,查看串口助手接收数据也变化成修改后的数据。
在这里插入图片描述
串口DMA发送数据正常
6,使用串口工具给MCU发送数据。
使用串口工具发送一个字节hex数据,使用调试模式查看MCU接收到的数据,对比串口发送的数据与MCU接收的数据一致。
在这里插入图片描述
使用串口发送多字节数据,查看MCU接收数据是否正确。
在这里插入图片描述
串口DMA接收数据正常。

串口发送测试:(这里做一下串口DMA模式连续发送数据所占用MCU时间的测试与之前的中断模式对比);
程序先运行到发送数据之前,当前的系统时钟大约运行7ms 左右
在这里插入图片描述
发送完成后当前的系统时间仍然是7ms,串口DMA发送数据是不占用MCU时间的,DMA相当于是二级缓存。所以当发送数据较多的时候使用DMA进行数据传输可以极大的减少MCU的开销。
(这里也要注意DMA发送虽然不占用MCU的开销,但是仍需要发送时间,若DMA数据未发送完成又继续调用DMA发送可能会导致数据丢包,解决办法就是可以设置DMA发送完成中断,在DMA发送完成中断后再进行下一次的DMA发送就可以了这里就没有示例了。)
在这里插入图片描述
使用DMA+空闲中断的话可以减少MCU接收数据中断的次数。正常接收中断模式我们每接收一个字节需要进入中断一次,而空闲中断的话接收一串字符只需要进入一次中断(即在串口空闲的时候触发中断)。也可以一定程度的减少MCU的开销。

  • 17
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 23
    评论
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收发时,需要正确配置相关寄存器和检测传输的状态,以确保数据的可靠传输。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吴同学啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值