[AT32F437] 串口DMA发送

[复制链接]
479|1
寂静小夜曲 发表于 2025-11-30 16:24 | 显示全部楼层 |阅读模式
串口DMA发送特别适合MCU级别的数据传输。因为其确定性,长度与发送时间,所以是最简单的提升MCU通讯性能的方法之一。我以Usart1为例实现了Usart1的DMA发送。
  1. static void usart1_init(void)
  2. {
  3.   gpio_init_type gpio_init_struct;
  4.   dma_init_type dma_init_struct;
  5.   crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  6.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  7.   crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);

  8.   dma_reset(DMA1_CHANNEL1);
  9.   dma_default_para_init(&dma_init_struct);
  10.   dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  11.   dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  12.   dma_init_struct.memory_inc_enable = TRUE;
  13.   dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  14.   dma_init_struct.peripheral_inc_enable = FALSE;
  15.   dma_init_struct.priority = DMA_PRIORITY_LOW;
  16.   dma_init_struct.loop_mode_enable = FALSE;
  17.   dma_init(DMA1_CHANNEL1, &dma_init_struct);

  18.   dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
  19.   nvic_irq_enable(DMA1_Channel1_IRQn, 7, 0);

  20.   DMA1_CHANNEL1->dtcnt = 0;
  21.   DMA1_CHANNEL1->paddr = (uint32_t)&USART1->dt;
  22.   DMA1_CHANNEL1->maddr = (uint32_t)uart_tx_buf;
  23.   dma_channel_enable(DMA1_CHANNEL1, FALSE);
  24.   /* dmamux function enable */
  25.   dmamux_enable(DMA1, TRUE);
  26.   dmamux_init(DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_USART1_TX);

  27.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  28.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  29.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  30.   gpio_init_struct.gpio_pins = GPIO_PINS_9 | GPIO_PINS_10;
  31.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  32.   gpio_init(GPIOA, &gpio_init_struct);
  33.   gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_7);
  34.   gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_7);

  35.   usart_init(USART1, 1000000, USART_DATA_8BITS, USART_STOP_1_BIT);
  36.   usart_parity_selection_config(USART1, USART_PARITY_NONE);
  37.   usart_transmitter_enable(USART1, TRUE);
  38.   usart_receiver_enable(USART1, TRUE);
  39.   usart_hardware_flow_control_set(USART1, USART_HARDWARE_FLOW_NONE);

  40.   usart_dma_transmitter_enable(USART1, TRUE);
  41.   usart_enable(USART1, TRUE);
  42. }

  43. static void usart1_send_bin(uint8_t dat)
  44. {
  45.   while (usart_flag_get(USART1, USART_TDBE_FLAG) == RESET)
  46.   {
  47.     ;
  48.   }
  49.   usart_data_transmit(USART1, dat);
  50. }
  51. static int usart1_dmasend(uint8_t *buf, uint16_t len)
  52. {
  53.   int ret = 0;
  54.   uint32_t i;
  55.   while(dma_flag_get(DMA1_FDT1_FLAG) == RESET);
  56.   dma_channel_enable(DMA1_CHANNEL1, FALSE);
  57.   for (i = 0; i < len; i++)
  58.   {
  59.     uart_tx_buf[i] = buf[i];
  60.   }
  61.   DMA1_CHANNEL1->dtcnt = len;
  62.   dma_channel_enable(DMA1_CHANNEL1, TRUE);
  63.   return (ret);
  64. }
在上述代码实现里面, 第58行的usart1_dmasend()函数,我这里设计的为阻塞式实现。即下一次DMA发送一定要原地等待上一次发送完成。如果更新为非阻塞式实现,则在这里查询到FDT1标志位处于busy时,可以直接返回ret = 1;即可。



雾都浪漫 发表于 2026-2-12 16:02 | 显示全部楼层
串口 DMA 发送无需 CPU 逐字节干预,解放内核处理其他任务,降低 CPU 占用率,提升数据传输效率,尤其适合大流量、高实时性的串口通信场景。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

50

帖子

0

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