[AT32F437] AT32F437串口DMA发送

[复制链接]
1824|0
天鹅绒星星 发表于 2025-10-21 17:03 | 显示全部楼层 |阅读模式

串口发送在项目中多采用两种典型方式:一、阻塞式串口发送,如printf()(参考官方usart/printf示例);二、非阻塞式串口发送,如中断发送,DMA发送。

本次测试为非阻塞式的DMA方式。一是系统主要任务是电源控制,非串口通讯;另一方面,串口的中断总打断系统运行也没有好处,打印个日志也仅需要在空闲时完成即可。

还有一个需求,我也计划将串口波特率提升到500kbps,高波特率下如果使用中断,对整体性能的影响也较大。

硬件测试环境继续使用AT-START-F437开发板,测试过程使用板载的AT-Link中的虚拟串口与PC机通讯,查看原理图例,配置AT32F437的Usart1外设,引脚为PA9和PA10。初始化代码如下:

static void usart1_init(void)
{
  gpio_init_type gpio_init_struct;
  dma_init_type dma_init_struct;
  crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);

  dma_reset(DMA1_CHANNEL1);
  dma_default_para_init(&dma_init_struct);
  dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  dma_init_struct.memory_inc_enable = TRUE;
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_LOW;
  dma_init_struct.loop_mode_enable = FALSE;
  dma_init(DMA1_CHANNEL1, &dma_init_struct);

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

  DMA1_CHANNEL1->dtcnt = 0;
  DMA1_CHANNEL1->paddr = (uint32_t)&USART1->dt;
  DMA1_CHANNEL1->maddr = (uint32_t)uart_tx_buf;
  dma_channel_enable(DMA1_CHANNEL1, FALSE);
  /* dmamux function enable */
  dmamux_enable(DMA1, TRUE);
  dmamux_init(DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_USART1_TX);

  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_9 | GPIO_PINS_10;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_7);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_7);

  usart_init(USART1, 1000000, USART_DATA_8BITS, USART_STOP_1_BIT);
  usart_parity_selection_config(USART1, USART_PARITY_NONE);
  usart_transmitter_enable(USART1, TRUE);
  usart_receiver_enable(USART1, TRUE);
  usart_hardware_flow_control_set(USART1, USART_HARDWARE_FLOW_NONE);

  usart_dma_transmitter_enable(USART1, TRUE);
  usart_enable(USART1, TRUE);
}

我还在实验中实现了DMA的完成中断,通过状态机的状态切换来达到串口数据的完整与及时输出。

typedef enum usart_state_e
{
  uart_tx_idle = 0,
  uart_tx_sending,
  uart_tx_send_done,
} usart_state_t;

在main函数中,我们通过循环查询usart的状态,当其为idle时,我们即开启DMA发送,待其DMA发送完成后,在中断中将其状态再更新为idle。

int main(void)
{
  bsp_init();
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_3);
  usart1_init();
  usart_state = uart_tx_idle;
  while (1)
  {
    if (usart_state == uart_tx_idle)
    {
      usart_state = uart_tx_sending;
      usart1_dmasend(usart_test_str, sizeof(usart_test_str) - 1);
    }
    if (usart_state == uart_tx_send_done)
    {
      usart_state = uart_tx_idle;
    }
  }
}

效果上面也符合预期

AT32串口DMASend.jpg

最后,对于中断的配置我使用了3bit的方式,并将Usart1的DMA发送中断的优先级配置为较低。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

25

帖子

0

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