GD32E230F6p6的串口DMA中断收发及printf

[复制链接]
2664|14
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:16 | 显示全部楼层 |阅读模式
简介
通过DMA中断的方式实现USART0串口数据收发可以尽量少的占用mcu,提高系统的实时性,同时,printf也可以用DMA方式实现!

一、初始化配置
选择DMA通道
根据GD32的用户手册确定使用DMA-CH1发送USART0-TX数据,DMA-CH2接收USART-RT数据,如下图:、、

307136518037b67a41.png


 楼主| 我爱台妹mmd 发表于 2023-9-30 19:16 | 显示全部楼层
头文件
  1. #define ARRAYNUM(arr_nanme)      (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
  2. #define USART0_TDATA_ADDRESS      ((uint32_t)0x40013828)  
  3. #define USART0_RDATA_ADDRESS      ((uint32_t)0x40013824)


  4. /* 串口IO初始化 */
  5. void com_gpio_init(void);
  6. /* 串口初始化 */
  7. void com_usart_init(void);
  8. /* 串口DMA初始化 */
  9. void com_dma_init(void);

  10. /* 串口DMA发送 */
  11. void com_dma_send_data(uint8_t *buffter, uint8_t length);

  12. /* 串口DMA方式printf */
  13. void dma_printf(const char *format,...);
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:16 | 显示全部楼层
串口&DMA初始化
  1. //串口发送buffer
  2. uint8_t txbuffer[128] = {0};
  3. //串口接收buffer
  4. uint8_t rxbuffer[4] = {0};

  5. extern uint8_t com_recv_STA;//串口DMA接收状态                1=数据接收完成
  6. extern uint8_t        com_recv_num;//串口接收字节数               

  7. /* 串口IO初始化 */
  8. void com_gpio_init(void)
  9. {
  10.    
  11.     rcu_periph_clock_enable(RCU_GPIOA);
  12.     gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
  13.         gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
  14.    
  15.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
  16.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);
  17.    
  18.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
  19.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
  20. }

  21. /* 串口初始化 */
  22. void com_usart_init(void)
  23. {
  24.     /* enable USART clock */
  25.     rcu_periph_clock_enable(RCU_USART0);

  26.     /* USART configure */
  27.     usart_deinit(USART0);
  28.     usart_baudrate_set(USART0, 115200U);
  29.     usart_receive_config(USART0, USART_RECEIVE_ENABLE);
  30.     usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

  31.     usart_enable(USART0);
  32. }

  33. void com_nvic_config(void)
  34. {
  35.         nvic_irq_enable(DMA_Channel1_2_IRQn, 0);
  36. }

  37. /* 串口DMA初始化 */
  38. void com_dma_init(void)
  39. {
  40.         dma_parameter_struct dma_init_struct;
  41.     /* enable DMA clock */
  42.     rcu_periph_clock_enable(RCU_DMA);

  43.     /* initilize the com */
  44.     com_gpio_init();
  45.     com_usart_init();
  46.         com_nvic_config();
  47.        
  48.        
  49. /* initialize DMA channel1 */
  50.     dma_deinit(DMA_CH1);
  51.     dma_struct_para_init(&dma_init_struct);
  52.     dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
  53.     dma_init_struct.memory_addr = (uint32_t)txbuffer;
  54.     dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  55.     dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
  56.     dma_init_struct.number = ARRAYNUM(txbuffer);
  57.     dma_init_struct.periph_addr = USART0_TDATA_ADDRESS;
  58.     dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  59.     dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
  60.     dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  61.     dma_init(DMA_CH1, &dma_init_struct);
  62.     /* initialize DMA channel2 */
  63.     dma_deinit(DMA_CH2);
  64.     dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
  65.     dma_init_struct.memory_addr = (uint32_t)rxbuffer;
  66.     dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  67.     dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
  68.     dma_init_struct.number = ARRAYNUM(rxbuffer);
  69.     dma_init_struct.periph_addr = USART0_RDATA_ADDRESS;
  70.     dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  71.     dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
  72.     dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  73.     dma_init(DMA_CH2, &dma_init_struct);
  74.     /* configure DMA mode */
  75.     dma_circulation_disable(DMA_CH1);
  76.     dma_memory_to_memory_disable(DMA_CH1);
  77.     dma_circulation_disable(DMA_CH2);
  78.     dma_memory_to_memory_disable(DMA_CH2);
  79.     /* USART DMA enable for reception */
  80.     usart_dma_receive_config(USART0, USART_DENR_ENABLE);
  81.     /* enable DMA channel2 transfer complete interrupt */
  82.     dma_interrupt_enable(DMA_CH2, DMA_INT_FTF);
  83.     /* enable DMA channel2 */
  84.     dma_channel_enable(DMA_CH2);
  85.     /* USART DMA enable for transmission */
  86.     usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
  87.     /* enable DMA channel1 transfer complete interrupt */
  88.     dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
  89.     /* enable DMA channel1 */
  90.     dma_channel_enable(DMA_CH1);
  91. }
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:17 | 显示全部楼层
串口DMA收发及printf
DMA发送
  1. void com_dma_send_data(uint8_t *buffter, uint8_t length)
  2. {                //串口DMA发送函数
  3.         uint8_t i;//txbuffer[128];
  4.         dma_parameter_struct dma_init_struct;
  5.         for (i = 0; i < length; i ++)
  6.         {
  7.                 txbuffer[i] = buffter[i];
  8.         }
  9.         dma_channel_disable(DMA_CH1);
  10.         dma_memory_address_config(DMA_CH1, (uint32_t)txbuffer);

  11.         dma_transfer_number_config(DMA_CH1, (uint32_t)length);
  12.         /* enable DMA channel1 */
  13.         dma_channel_enable(DMA_CH1);
  14.         /* USART DMA enable for transmission */
  15.         usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
  16. }
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:17 | 显示全部楼层
DMA收发中断处理
  1. void DMA_Channel1_2_IRQHandler(void)//DMA串口发送接收中断
  2. {
  3.     if(RESET != dma_interrupt_flag_get(DMA_CH1, DMA_INT_FLAG_FTF))
  4.         {//DMA串口发送触发中断
  5.         dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_G);
  6.     }
  7.     if(RESET != dma_interrupt_flag_get(DMA_CH2, DMA_INT_FLAG_FTF))
  8.         {//DMA串口接收触发中断
  9.                 dma_channel_disable(DMA_CH2);
  10.         dma_interrupt_flag_clear(DMA_CH2, DMA_INT_FLAG_G);
  11.                 dma_flag_clear(DMA_CH2, DMA_FLAG_G);
  12.                 com_recv_num = 4;//获取字节数
  13.                 com_recv_STA = 1;//接收数据就绪
  14.                 dma_transfer_number_config(DMA_CH2,ARRAYNUM(rxbuffer));
  15.                 dma_channel_enable(DMA_CH2);
  16.                
  17.     }
  18. }
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:17 | 显示全部楼层
DMA方式printf

  1. /* DMA方式printf */
  2. void dma_printf(const char *format,...)
  3. {
  4.         uint32_t length;
  5.         va_list args;

  6.         va_start(args, format);
  7.         length = vsnprintf((char*)txbuffer, sizeof(txbuffer), (char*)format, args);
  8.         va_end(args);
  9.         com_dma_send_data(txbuffer,length);

  10. }
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:17 | 显示全部楼层
实际效果
这里我发送FANR读取转速的命令给mcu,mcu通过串口DMA方式printf当前值(这里我直接将转速检测的IO接的3.3V,实际最高1.1W转,而不是75W)。测试完成,串口DMA中断收发正常,自定义的prinf也可以使用。
 楼主| 我爱台妹mmd 发表于 2023-9-30 19:17 | 显示全部楼层
uiint 发表于 2023-10-5 21:30 | 显示全部楼层
在USART的DMA中断收发及printf的实现中,首先要定义串口接收和发送变量,然后初始化USART1,设置波特率、数据位、停止位、奇偶校验等参数,并使能DMA传输和接收。在主函数中,可以使用printf函数发送数据,然后通过DMA中断接收数据。
hudi008 发表于 2023-10-5 22:16 | 显示全部楼层
串口 DMA 中断收发是指通过 DMA 控制器实现串口数据的收发,从而减轻 CPU 的负担。在接收数据时,DMA 控制器会从串口接收数据,并将数据存储到指定的缓冲区。在发送数据时,DMA 控制器会从指定的缓冲区取出数据,并将数据发送到串口。
chenci2013 发表于 2023-10-8 21:09 | 显示全部楼层
串口DMA中断收发可以提高系统的数据传输效率和可靠性,降低CPU的负载。
averyleigh 发表于 2023-10-8 22:58 | 显示全部楼层
在使用 printf 进行串口输出时,也可以通过 DMA 实现更高效的数据传输。
jkl21 发表于 2023-10-10 21:15 | 显示全部楼层
可以使用DMA(直接内存访问)和USART(通用同步和异步接收发送器)来实现串口的中断收发。同时,也可以使用printf函数来进行数据的打印。
pl202 发表于 2023-10-11 21:47 | 显示全部楼层
使用 DMA 技术进行中断收发和 printf 输出,可以提高串口通信的效率和性能。
Heelo 发表于 2023-11-10 12:38 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

72

主题

648

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部