GD32F103使用串口DMA收+发 信息(无中断)

GD32F103使用串口DMA收发信息(无中断)


前言

对于信息无实时性响应,采用DMA模式对串口数据进行处理。这里没有用到收发中断。在收数据过程中,我们要保证读取数据的速率,否则,收到的数据还没读到,就有被后面的数据覆盖了。


一、GPIO+USART1+DMA基本设置

具体的usart1连接到哪个DMA,哪个ch,需要看user_manual手册---- DMA request mapping

void com_init(uint32_t com)
{
    uint32_t com_id = 0U;
    if(EVAL_COM0 == com){
        com_id = 0U;
    }else if(EVAL_COM1 == com){
        com_id = 1U;
    }
    
    /* enable GPIO clock */
    rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);

    /* enable USART clock */
    rcu_periph_clock_enable(COM_CLK[com_id]);

    /* connect port to USARTx_Tx */
    gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);

    /* connect port to USARTx_Rx */
    gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);

    /* USART configure */
    usart_deinit(com);
    usart_baudrate_set(com, 115200U);
    usart_word_length_set(com, USART_WL_8BIT);
    usart_stop_bit_set(com, USART_STB_1BIT);
    usart_parity_config(com, USART_PM_NONE);
    usart_hardware_flow_rts_config(com, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(com, USART_CTS_DISABLE);
    usart_receive_config(com, USART_RECEIVE_ENABLE);
    usart_transmit_config(com, USART_TRANSMIT_ENABLE);
    usart_enable(com);
}


void usart_dma_config(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);
    /* initialize USART */
    com_init(EVAL_COM1);
    /* deinitialize DMA channel6(USART1 tx) */
    dma_deinit(DMA0, DMA_CH6);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)uart_data[1].DMA_TxBuf;//这个是DMA的数要存到哪个数组里,可根据自己需求替换
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = USART_TX_BUF_SIZE;//这个是数组的大小,可更改
    dma_init_struct.periph_addr = USART1_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH6, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH6);//将TX的DMA 循环发送disable,是因为我们需要自己控制如何发送数据。
    /* enable DMA channel3 */
    dma_channel_enable(DMA0, DMA_CH6);
    
    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USART1, USART_DENT_ENABLE);
    usart_dma_receive_config(USART1, USART_DENR_ENABLE);

    /* wait DMA Channel transfer complete */
//    while(RESET == dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF));
		
        /* deinitialize DMA channel5 (USART1 rx) */
        dma_deinit(DMA0, DMA_CH5);
        dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
        dma_init_struct.memory_addr = (uint32_t)uart_data[1].DMA_RxBuf;//这个是DMA的数要存到哪个数组里,可根据自己需求替换
        dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
        dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
        dma_init_struct.number = USART_RX_BUF_SIZE;//自己换
        dma_init_struct.periph_addr = USART1_DATA_ADDRESS;
        dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
        dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
        dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
        dma_init(DMA0, DMA_CH5, &dma_init_struct);
        /* configure DMA mode */
        dma_circulation_enable(DMA0, DMA_CH5);//将RX的循环接收开启,是因为我们不希望漏过所有的数据,当然这个前提是,你要及时处理DMA数组里面的数据
        /* enable DMA channel4 */
        dma_channel_enable(DMA0, DMA_CH5);

        /* wait DMA channel transfer complete */
//        while(RESET == dma_flag_get(DMA0, DMA_CH5, DMA_FLAG_FTF));		
		
}

通过以上的设置,基本上,我们就实现了串口的DMA收发。但是,我们需要对这个发到的数据进行处理。由于我们关闭了循环发送,所以需要我们手动开启DMA发送。

二、处理收到的数据RX

代码如下(示例):

dma_transfer_number_get(DMA0, DMA_CH5)

这里我只说一下思路:1、将DMA数据存入环形缓存区,2、通过高于写入速度的速率去读环形缓存区的数据,使数据不会溢出。ps:在取数据之前,需用通过上面这个dma_transfer_number_get(DMA0, DMA_CH5)函数去查DMA写到哪个位置。

二、处理发送的数据TX

代码如下(示例):

void Usart_TxMan(INT8U Port)
{
	uint16_t idx,TxLen=0;
	INT8S tx_finish_flag = 0;
	
		if((dma_flag_get(DMA0,DMA_CH6,DMA_FLAG_FTF)!=RESET))//ÉÏÒ»´ÎµÄÊý¾ÝÍêÈ«·¢ËÍÍê
		{
			tx_finish_flag = 1;
		}

	if(tx_finish_flag) //ÉÏÒ»´Î´«ÊäÍê³É
	{

		  TxLen = (uart_data[Port].tx_write + USART_TX_BUF_SIZE - uart_data[Port].tx_read) % USART_TX_BUF_SIZE;
			if(TxLen>0)	 // ÓÐÐèÒª·¢Ë͵ÄÊý¾Ý
			{	
				for(idx = 0; idx < TxLen; idx++) 
				{
					uart_data[Port].DMA_TxBuf[idx]=uart_data[Port].TxBuf[uart_data[Port].tx_read];
					uart_data[Port].tx_read = (uart_data[Port].tx_read + 1) % USART_TX_BUF_SIZE;
				}	
				if(Port==1)
				{		
					dma_parameter_struct dma_init_struct;
					dma_deinit(DMA0, DMA_CH6);
					dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
					dma_init_struct.memory_addr = (uint32_t)uart_data[1].DMA_TxBuf;
					dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
					dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
					dma_init_struct.number = TxLen;
					dma_init_struct.periph_addr = USART1_DATA_ADDRESS;
					dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
					dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
					dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
					dma_init(DMA0, DMA_CH6, &dma_init_struct);
					/* configure DMA mode */
					dma_circulation_disable(DMA0, DMA_CH6);
					/* enable DMA channel3 */
					dma_channel_enable(DMA0, DMA_CH6);
					
					/* USART DMA enable for transmission and reception */
					usart_dma_transmit_config(USART1, USART_DENT_ENABLE);	
					
					dma_flag_clear(DMA0,DMA_CH6,DMA_FLAG_G);
				}
				else if(Port==0)
				{
				
				}
			}

		
	
	}
}

代码如上,思路是:在发送数据之前,看看dma_flag_get(DMA0,DMA_CH6,DMA_FLAG_FTF),也就是DMA写完成flag(不是中断,是标志)是否完成,若完成,代表上一次发送的数据发出去了,这时候才可以再写入,否则退出写入。
写入的办法就是重新设置一遍DMA,(在STM32中可以简单设置其中几个参数即可,我没有去测试GD中设置哪几个,所以全部重新设置了一遍)。这样就实现了tx。


总结

以上为DMA串口收发。

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好,关于 GD32F103 的串口 DMA,可以参考以下步骤: 1. 首先,需要配置串口DMA 的相关寄存器,例如串口的波特率、数据位数、停止位数、校验位等,以及 DMA 的通道、数据传输方向、传输数据类型等。 2. 然后,开启串口DMA 的时钟,并使能 DMA中断和传输完成中断。 3. 在串口中断中,将接到的数据存入缓冲区中,并设置 DMA 的传输数据长度和缓冲区地址,启动 DMA 传输。同时需要注意,每次接到数据后都要判断是否达到了缓冲区的最大长度,避免数据溢出。 4. 在 DMA 传输完成中断中,将接到的数据进行处理,例如解析数据、更新状态等。 下面是一个简单的示例代码,供参考: ```c #include "gd32f10x.h" #define BUFFER_SIZE 256 uint8_t buffer[BUFFER_SIZE]; uint16_t buffer_index = 0; void usart_config(void) { /* Enable USART clock */ rcu_periph_clock_enable(RCU_USART0); /* USART0 configuration */ usart_deinit(USART0); usart_baudrate_set(USART0, 115200U); usart_word_length_set(USART0, USART_WL_8BIT); usart_stop_bit_set(USART0, USART_STB_1BIT); usart_parity_config(USART0, USART_PM_NONE); usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE); usart_receive_config(USART0, USART_RECEIVE_ENABLE); usart_dma_receive_config(USART0, USART_DENR_ENABLE); /* Enable USART DMA requests */ usart_dma_request_enable(USART0, USART_DENR); /* Enable USART */ usart_enable(USART0); } void dma_config(void) { /* Enable DMA clock */ rcu_periph_clock_enable(RCU_DMA0); /* DMA0 channel4 configuration */ dma_deinit(DMA0, DMA_CH4); dma_periph_address_config(DMA0, DMA_CH4, (uint32_t)&USART_DATA(USART0)); dma_memory_address_config(DMA0, DMA_CH4, (uint32_t)buffer); dma_transfer_direction_config(DMA0, DMA_CH4, DMA_PERIPHERAL_TO_MEMORY); dma_transfer_size_config(DMA0, DMA_CH4, DMA_MEMORY_WIDTH_8BIT, DMA_PERIPHERAL_WIDTH_8BIT); dma_memory_increment_enable(DMA0, DMA_CH4); dma_circulation_enable(DMA0, DMA_CH4); dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF); dma_channel_enable(DMA0, DMA_CH4); } void nvic_config(void) { /* Enable DMA0 channel4 interrupt */ nvic_irq_enable(DMA0_Channel4_IRQn, 0, 0); } void DMA0_Channel4_IRQHandler(void) { if(dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FTF)) { dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FTF); /* Process received data */ buffer_index = (BUFFER_SIZE - dma_transfer_number_get(DMA0, DMA_CH4)) % BUFFER_SIZE; // ... /* Restart DMA transmission */ dma_transfer_number_config(DMA0, DMA_CH4, BUFFER_SIZE); dma_channel_enable(DMA0, DMA_CH4); } } int main(void) { /* Configure USART */ usart_config(); /* Configure DMA */ dma_config(); /* Configure NVIC */ nvic_config(); while(1); } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值