口天土立口 发表于 2025-9-13 11:57

APM32E030的USART驱动(DMA)



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

USART驱动代码如下:
/* 串口 */
#define UART_INS      (USART1)
/* 接收数据大小 */
#define UART_RX_LEN   (512)
/* 接收缓存 */
uint8_t rx_buf;
/* 接收长度 */
uint16_t rx_len;
/* 接收完成 */
uint16_t rx_complete;

/* 发送索引 */
uint16_t tx_index;
/* 发送长度 */
uint16_t tx_len;
/* 发送缓存 */
uint8_t *tx_buf;/*
* @brief       初始化
*
* @param       None
*
* @retval      None
*
*/
void bsp_uart_init(void)
{
    GPIO_Config_T gpioConfig;
    USART_Config_T configStruct;
    DMA_Config_T dmaConfig;
   
    /* GPIO */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOB);
    GPIO_ConfigStructInit(&gpioConfig);
    gpioConfig.pin   = GPIO_PIN_6 | GPIO_PIN_7;
    gpioConfig.mode    = GPIO_MODE_AF;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.speed   = GPIO_SPEED_50MHz;
    gpioConfig.pupd    = GPIO_PUPD_NO;
    GPIO_Config(GPIOB, &gpioConfig);
   
    /* TX */
    GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
    /* RX */
    GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);
   
    /* DMA */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
    DMA_ConfigStructInit(&dmaConfig);
    /* DMA -> USART_RX */
    dmaConfig.direction = DMA_DIR_PERIPHERAL;
    dmaConfig.circular = DMA_CIRCULAR_DISABLE;
    dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
    dmaConfig.priority = DMA_PRIORITY_LEVEL_LOW;
    dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
    dmaConfig.bufferSize = sizeof(rx_buf);
    dmaConfig.memoryAddress = (uint32_t)rx_buf;
    dmaConfig.peripheralAddress = (uint32_t)&UART_INS->RXDATA;
    DMA_Config(DMA1_CHANNEL_3, &dmaConfig);
    /* 传输完成中断 */
    DMA_EnableInterrupt(DMA1_CHANNEL_3, DMA_INT_TFIE);
    /* DMA -> USART_TX */
    dmaConfig.direction = DMA_DIR_MEMORY;
    dmaConfig.circular = DMA_CIRCULAR_DISABLE;
    dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
    dmaConfig.priority = DMA_PRIORITY_LEVEL_LOW;
    dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
    dmaConfig.bufferSize = sizeof(rx_buf);
    dmaConfig.memoryAddress = 0;
    dmaConfig.peripheralAddress = (uint32_t)&UART_INS->TXDATA;
    DMA_Config(DMA1_CHANNEL_2, &dmaConfig);
    /* 传输完成中断 */
    DMA_EnableInterrupt(DMA1_CHANNEL_2, DMA_INT_TFIE);
    /* 使能中断 */
    NVIC_SetPriority(DMA1_CH2_3_IRQn, 0);
    NVIC_EnableIRQ(DMA1_CH2_3_IRQn);
   
    /* USART */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
    USART_Reset(UART_INS);
    USART_ConfigStructInit(&configStruct);
    configStruct.baudRate = 115200;
    configStruct.wordLength = USART_WORD_LEN_8B;
    configStruct.stopBits = USART_STOP_BIT_1;
    configStruct.parity = USART_PARITY_NONE ;
    configStruct.mode = USART_MODE_TX_RX;
    configStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
    USART_Config(UART_INS, &configStruct);
    USART_EnableDMA(UART_INS, USART_DMA_REQUEST_RX);
    USART_EnableDMA(UART_INS, USART_DMA_REQUEST_TX);
    /* 使能空闲中断 */
    USART_EnableInterrupt(UART_INS, USART_INT_IDLEIE);   
    /* 使能中断 */
    NVIC_SetPriority(USART1_IRQn, 0);
    NVIC_EnableIRQ(USART1_IRQn);   
    /* 使能串口 */
    USART_Enable(UART_INS);
    /* 接收数据 */
    bsp_uart_recv();
}/*
* @brief       串口中断
*
* @param       None
*
* @retval      None
*
*/
void USART1_IRQHandler(void)
{
    uint16_t num = 0;
   
    /* 空闲 */
    if (USART_ReadIntFlag(UART_INS, USART_INT_FLAG_IDLE) != RESET) {
      USART_ClearIntFlag(UART_INS, USART_INT_FLAG_IDLE);
      /* 计算已经传输的数据量 */
      num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
      if (num != 0) {
            rx_len = num;
            rx_complete = 1;
      }
      bsp_uart_recv();
    }
}/*
* @brief       DMA中断
*
* @param       None
*
* @retval      None
*
*/
void DMA1_CH2_3_IRQHandler(void)
{
    uint16_t num = 0;
   
    /* USART TX */
    if (DMA_ReadIntFlag(DMA1_INT_FLAG_TF2) != RESET) {
      DMA_ClearIntFlag(DMA1_INT_FLAG_TF2);
    }
    /* USART RX */
    if (DMA_ReadIntFlag(DMA1_INT_FLAG_TF3) != RESET) {
      DMA_ClearIntFlag(DMA1_INT_FLAG_TF3);
      /* 计算已经传输的数据量 */
      num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
      if (num != 0) {
            rx_len = num;
            rx_complete = 1;
      }
      bsp_uart_recv();
    }
}/*
* @brief       接收数据
*
* @param       None
*
* @retval      None
*
*/
void bsp_uart_recv(void)
{   
    DMA_Disable(DMA1_CHANNEL_3);
    DMA_SetDataNumber(DMA1_CHANNEL_3, sizeof(rx_buf));
    DMA_Enable(DMA1_CHANNEL_3);
}/*
* @brief       发送数据
*
* @param       buf: 数据缓存
*            buf_len: 缓存大小
*
* @retval      None
*
*/
void bsp_uart_send(uint8_t *buf, uint16_t buf_len)
{   
    if ((buf != NULL) && (buf_len > 0)) {
      DMA_Disable(DMA1_CHANNEL_2);
      DMA_SetDataNumber(DMA1_CHANNEL_2, buf_len);
      DMA1_CHANNEL_2->CHMADDR = (uint32_t)buf;
      DMA_Enable(DMA1_CHANNEL_2);
    }
}/*
* @brief       接收完成
*
* @param       None
*
* @retval      0: 未完成; 1: 完成
*
*/
uint8_t bsp_is_rx_complete(void)
{
    uint8_t ret = rx_complete;
   
    rx_complete = 0;
    return ret;
}/*
* @brief       获取接收长度
*
* @param       None
*
* @retval      接收数据长度
*
*/
uint16_t bsp_get_rx_len(void)
{
    uint16_t ret = rx_len;
   
    rx_len = 0;
    return ret;
}/*
* @brief       获取接收缓存
*
* @param       None
*
* @retval      接收缓存
*
*/
uint8_t *bsp_get_rx_buf(void)
{
    return rx_buf;
}

测试代码如下:
// 应用初始化
void app_init(void)
{
    bsp_uart_init();
}

// 应用任务
void app_task(void)
{
    /* 接收完成再发出来 */
    if (bsp_is_rx_complete() != 0) {
      bsp_uart_send(bsp_get_rx_buf(), bsp_get_rx_len());
    }
}详细代码,请查看附件:


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接收估计是唯一解
页: [1]
查看完整版本: APM32E030的USART驱动(DMA)