
01Introduction:
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.

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.