Basics of Embedded Programming | Configuration of Serial Port DMA for APM32E030

Basics of Embedded Programming | Configuration of Serial Port DMA for APM32E030Basics of Embedded Programming | Configuration of Serial Port DMA for APM32E03001Introduction:

The industrial-grade basic expansion MCU, based on the performance of APM32F030, achieves higher main frequency, lower power consumption, and more advanced analog and communication interfaces. It is also equipped with rich on-chip resources to meet the application upgrade needs of various industries, especially for cost-sensitive applications. It can be widely used in industrial control, smart homes, instrumentation, wearable devices, medical and handheld devices, small appliances, lighting, and other fields.

Additionally, it has been observed that many microcontrollers now have the function of automatically recognizing baud rates, which saves a lot of development time.

Basics of Embedded Programming | Configuration of Serial Port DMA for APM32E030

The baud rate of this MCU can reach 6Mbit/s, which is also a highlight. Without further ado, let’s get straight to the code.

02Driver and Application Code

1. Header File Definitions

/* Serial Port 1 */
#define UART_INS        (USART1) 
#define UART_RX_LEN     (512)
uint8_t rx_buf[UART_RX_LEN];
uint16_t rx_len;
uint16_t rx_complete;
uint16_t tx_index;
uint16_t tx_len;
uint8_t *tx_buf;

2. Serial Port and DMA Initialization Function

void bsp_uart_init(void)
{
    GPIO_Config_T gpioConfig;
    USART_Config_T configStruct;
    DMA_Config_T dmaConfig;    

    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);
    GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
    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);
    /* Transfer Complete Interrupt */
    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);
    /* Transfer Complete Interrupt */
    DMA_EnableInterrupt(DMA1_CHANNEL_2, DMA_INT_TFIE);
    /* Enable Interrupt */
    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);
    /* Enable Idle Interrupt */
    USART_EnableInterrupt(UART_INS, USART_INT_IDLEIE);    
    /* Enable Interrupt */
    NVIC_SetPriority(USART1_IRQn, 0);
    NVIC_EnableIRQ(USART1_IRQn);    
    /* Enable Serial Port */
    USART_Enable(UART_INS);
    /* Receive Data */
    bsp_uart_recv();
}

3. Serial Port Interrupt Function

void USART1_IRQHandler(void)
{
    uint16_t num = 0;    
    /* Idle */
    if (USART_ReadIntFlag(UART_INS, USART_INT_FLAG_IDLE) != RESET) {
        USART_ClearIntFlag(UART_INS, USART_INT_FLAG_IDLE);
        /* Calculate the amount of data transmitted */
        num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
        if (num != 0) {
            rx_len = num;
            rx_complete = 1;
        }
        bsp_uart_recv();
    }
}

4. DMA Interrupt Function

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);
        /* Calculate the amount of data transmitted */
        num = sizeof(rx_buf) - DMA_ReadDataNumber(DMA1_CHANNEL_3);
        if (num != 0) {
            rx_len = num;
            rx_complete = 1;
        }
        bsp_uart_recv();
    }
}

5. Send and Receive Functions

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);
    }
}
void bsp_uart_recv(void)
{    
    DMA_Disable(DMA1_CHANNEL_3);
    DMA_SetDataNumber(DMA1_CHANNEL_3, sizeof(rx_buf));
    DMA_Enable(DMA1_CHANNEL_3);
}

6. Other Auxiliary Functions

/*
 * @brief       Receive Complete
 * @param       None
 * @retval      0: Not Complete; 1: Complete
 */
uint8_t bsp_is_rx_complete(void)
{
    uint8_t ret = rx_complete;    
    rx_complete = 0;
    return ret;
}
/*
 * @brief       Get Receive Length
 * @param       None
 * @retval      Length of Received Data
 */
uint16_t bsp_get_rx_len(void)
{
    uint16_t ret = rx_len;    
    rx_len = 0;
    return ret;
}
/*
 * @brief       Get Receive Buffer
 * @param       None
 * @retval      Receive Buffer
 */
uint8_t *bsp_get_rx_buf(void)
{
    return rx_buf;
}

7. Application Test Function

int main(void)
{
    bsp_init();
    app_init();    
    while (1)
    {
        app_task();
    }
}

03Conclusion: If anyone needs hardware solutions or PCBA, contact Lao Liu.

Leave a Comment