[APM32E0] APM32E030的USART驱动(DMA)

[复制链接]
550|4
口天土立口 发表于 2025-9-13 11:57 | 显示全部楼层 |阅读模式
6487668c4e42dc3156.png

USART 外设的通信速率最高为 6Mbit/s,同时支持DMA传输方式。

USART驱动代码如下:
  1. /* 串口 */
  2. #define UART_INS        (USART1)
  3. /* 接收数据大小 */
  4. #define UART_RX_LEN     (512)
  5. /* 接收缓存 */
  6. uint8_t rx_buf[UART_RX_LEN];
  7. /* 接收长度 */
  8. uint16_t rx_len;
  9. /* 接收完成 */
  10. uint16_t rx_complete;

  11. /* 发送索引 */
  12. uint16_t tx_index;
  13. /* 发送长度 */
  14. uint16_t tx_len;
  15. /* 发送缓存 */
  16. uint8_t *tx_buf;
  1. /*
  2. * [url=/u/brief]@brief[/url]       初始化
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void bsp_uart_init(void)
  10. {
  11.     GPIO_Config_T gpioConfig;
  12.     USART_Config_T configStruct;
  13.     DMA_Config_T dmaConfig;
  14.    
  15.     /* GPIO */
  16.     RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOB);
  17.     GPIO_ConfigStructInit(&gpioConfig);
  18.     gpioConfig.pin     = GPIO_PIN_6 | GPIO_PIN_7;
  19.     gpioConfig.mode    = GPIO_MODE_AF;
  20.     gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  21.     gpioConfig.speed   = GPIO_SPEED_50MHz;
  22.     gpioConfig.pupd    = GPIO_PUPD_NO;
  23.     GPIO_Config(GPIOB, &gpioConfig);
  24.    
  25.     /* TX */
  26.     GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
  27.     /* RX */
  28.     GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);
  29.    
  30.     /* DMA */
  31.     RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
  32.     DMA_ConfigStructInit(&dmaConfig);
  33.     /* DMA -> USART_RX */
  34.     dmaConfig.direction = DMA_DIR_PERIPHERAL;
  35.     dmaConfig.circular = DMA_CIRCULAR_DISABLE;
  36.     dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
  37.     dmaConfig.priority = DMA_PRIORITY_LEVEL_LOW;
  38.     dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
  39.     dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
  40.     dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
  41.     dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
  42.     dmaConfig.bufferSize = sizeof(rx_buf);
  43.     dmaConfig.memoryAddress = (uint32_t)rx_buf;
  44.     dmaConfig.peripheralAddress = (uint32_t)&UART_INS->RXDATA;
  45.     DMA_Config(DMA1_CHANNEL_3, &dmaConfig);
  46.     /* 传输完成中断 */
  47.     DMA_EnableInterrupt(DMA1_CHANNEL_3, DMA_INT_TFIE);
  48.     /* DMA -> USART_TX */
  49.     dmaConfig.direction = DMA_DIR_MEMORY;
  50.     dmaConfig.circular = DMA_CIRCULAR_DISABLE;
  51.     dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
  52.     dmaConfig.priority = DMA_PRIORITY_LEVEL_LOW;
  53.     dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
  54.     dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
  55.     dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
  56.     dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
  57.     dmaConfig.bufferSize = sizeof(rx_buf);
  58.     dmaConfig.memoryAddress = 0;
  59.     dmaConfig.peripheralAddress = (uint32_t)&UART_INS->TXDATA;
  60.     DMA_Config(DMA1_CHANNEL_2, &dmaConfig);
  61.     /* 传输完成中断 */
  62.     DMA_EnableInterrupt(DMA1_CHANNEL_2, DMA_INT_TFIE);
  63.     /* 使能中断 */
  64.     NVIC_SetPriority(DMA1_CH2_3_IRQn, 0);
  65.     NVIC_EnableIRQ(DMA1_CH2_3_IRQn);  
  66.    
  67.     /* USART */
  68.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
  69.     USART_Reset(UART_INS);
  70.     USART_ConfigStructInit(&configStruct);
  71.     configStruct.baudRate = 115200;
  72.     configStruct.wordLength = USART_WORD_LEN_8B;
  73.     configStruct.stopBits = USART_STOP_BIT_1;
  74.     configStruct.parity = USART_PARITY_NONE ;
  75.     configStruct.mode = USART_MODE_TX_RX;
  76.     configStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
  77.     USART_Config(UART_INS, &configStruct);
  78.     USART_EnableDMA(UART_INS, USART_DMA_REQUEST_RX);
  79.     USART_EnableDMA(UART_INS, USART_DMA_REQUEST_TX);
  80.     /* 使能空闲中断 */
  81.     USART_EnableInterrupt(UART_INS, USART_INT_IDLEIE);   
  82.     /* 使能中断 */
  83.     NVIC_SetPriority(USART1_IRQn, 0);
  84.     NVIC_EnableIRQ(USART1_IRQn);   
  85.     /* 使能串口 */
  86.     USART_Enable(UART_INS);
  87.     /* 接收数据 */
  88.     bsp_uart_recv();
  89. }
  1. /*
  2. * @brief       串口中断
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void USART1_IRQHandler(void)
  10. {
  11.     uint16_t num = 0;
  12.    
  13.     /* 空闲 */
  14.     if (USART_ReadIntFlag(UART_INS, USART_INT_FLAG_IDLE) != RESET) {
  15.         USART_ClearIntFlag(UART_INS, USART_INT_FLAG_IDLE);
  16.         /* 计算已经传输的数据量 */
  17.         num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
  18.         if (num != 0) {
  19.             rx_len = num;
  20.             rx_complete = 1;
  21.         }
  22.         bsp_uart_recv();
  23.     }
  24. }
  1. /*
  2. * @brief       DMA中断
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void DMA1_CH2_3_IRQHandler(void)
  10. {
  11.     uint16_t num = 0;
  12.    
  13.     /* USART TX */
  14.     if (DMA_ReadIntFlag(DMA1_INT_FLAG_TF2) != RESET) {
  15.         DMA_ClearIntFlag(DMA1_INT_FLAG_TF2);
  16.     }
  17.     /* USART RX */
  18.     if (DMA_ReadIntFlag(DMA1_INT_FLAG_TF3) != RESET) {
  19.         DMA_ClearIntFlag(DMA1_INT_FLAG_TF3);
  20.         /* 计算已经传输的数据量 */
  21.         num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
  22.         if (num != 0) {
  23.             rx_len = num;
  24.             rx_complete = 1;
  25.         }
  26.         bsp_uart_recv();
  27.     }
  28. }
  1. /*
  2. * @brief       接收数据
  3. *
  4. * @param       None
  5. *
  6. * @retval      None
  7. *
  8. */
  9. void bsp_uart_recv(void)
  10. {   
  11.     DMA_Disable(DMA1_CHANNEL_3);
  12.     DMA_SetDataNumber(DMA1_CHANNEL_3, sizeof(rx_buf));
  13.     DMA_Enable(DMA1_CHANNEL_3);
  14. }
  1. /*
  2. * @brief       发送数据
  3. *
  4. * @param       buf: 数据缓存
  5. *              buf_len: 缓存大小
  6. *
  7. * @retval      None
  8. *
  9. */
  10. void bsp_uart_send(uint8_t *buf, uint16_t buf_len)
  11. {   
  12.     if ((buf != NULL) && (buf_len > 0)) {
  13.         DMA_Disable(DMA1_CHANNEL_2);
  14.         DMA_SetDataNumber(DMA1_CHANNEL_2, buf_len);
  15.         DMA1_CHANNEL_2->CHMADDR = (uint32_t)buf;
  16.         DMA_Enable(DMA1_CHANNEL_2);
  17.     }
  18. }
  1. /*
  2. * @brief       接收完成
  3. *
  4. * @param       None
  5. *
  6. * @retval      0: 未完成; 1: 完成
  7. *
  8. */
  9. uint8_t bsp_is_rx_complete(void)
  10. {
  11.     uint8_t ret = rx_complete;
  12.    
  13.     rx_complete = 0;
  14.     return ret;
  15. }
  1. /*
  2. * @brief       获取接收长度
  3. *
  4. * @param       None
  5. *
  6. * @retval      接收数据长度
  7. *
  8. */
  9. uint16_t bsp_get_rx_len(void)
  10. {
  11.     uint16_t ret = rx_len;
  12.    
  13.     rx_len = 0;
  14.     return ret;
  15. }
  1. /*
  2. * @brief       获取接收缓存
  3. *
  4. * @param       None
  5. *
  6. * @retval      接收缓存
  7. *
  8. */
  9. uint8_t *bsp_get_rx_buf(void)
  10. {
  11.     return rx_buf;
  12. }


测试代码如下:
  1. // 应用初始化
  2. void app_init(void)
  3. {
  4.     bsp_uart_init();
  5. }

  6. // 应用任务
  7. void app_task(void)
  8. {
  9.     /* 接收完成再发出来 */
  10.     if (bsp_is_rx_complete() != 0) {
  11.         bsp_uart_send(bsp_get_rx_buf(), bsp_get_rx_len());
  12.     }
  13. }
详细代码,请查看附件:
DMA.zip (2.09 MB, 下载次数: 1)

DawnFervor 发表于 2025-9-13 14:40 | 显示全部楼层
楼主的串口的接收与发送都使用的是DMA的方式。
好强大啊
FrostShimmer 发表于 2025-9-14 19:54 | 显示全部楼层
学习到了,配置DMA发送的时候要先将DMAdisable,才能配置新的参数。
蚊子的噩梦 发表于 2025-10-1 11:37 | 显示全部楼层
代码中DMA的配置看起来是正确的,确保你的硬件连接也是正确的,这样才能保证通信正常。
梦塑者 发表于 2025-10-4 18:47 | 显示全部楼层
这要是6Mbps全部使用中断的方式接收,MCU的性能损耗应该也是蛮严重的。
DMA接收估计是唯一解
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

45

帖子

0

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