DMA+USART双缓冲区收发 波特率可达921600( 以GD32L233X为例)
基本配置
#define USART_DMA_TX_BUF_LEN (128)
#define USART1_RX_BUF_LEN (130)
void USART1_Init(uint32_t baudrate)
{
// initialize the com
com_usart_init(baudrate);
// configure DMA ch0 and ch1
dma_usart_init();
}
static void com_usart_init(uint32_t baudrate)
{
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART1);
/* enable COM GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* connect port to USART TX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
/* connect port to USART RX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);
/* configure USART TX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);
/* configure USART RX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);
/* USART configure */
usart_deinit(USART1);
usart_baudrate_set(USART1, baudrate);
usart_word_length_set(USART1, USART_WL_8BIT);
usart_parity_config(USART1, USART_PM_NONE);
usart_stop_bit_set(USART1, USART_STB_1BIT);
usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
usart_data_first_config(USART1, USART_MSBF_LSB);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
/*USART enable*/
usart_interrupt_enable(USART1, USART_INT_IDLE);
nvic_irq_enable(USART1_IRQn, 2);
usart_enable(USART1);
}
static void dma_usart_init(void)
{
dma_parameter_struct dma_init_struct;
/* initialize DMA channel 2 */
rcu_periph_clock_enable(RCU_DMA);
dma_deinit(DMA_CH2);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART1_TX;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = NULL;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = 0;
dma_init_struct.periph_addr = (uint32_t)USART1_TDATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH2, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH2);
dma_memory_to_memory_disable(DMA_CH2);
/* disable the DMAMUX_MUXCH2 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH2);
/* USART DMA enable for transmission and reception */
usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
/* initialize DMA channel 1 */
dma_deinit(DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART1_RX;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = NULL;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = 0;
dma_init_struct.periph_addr = (uint32_t)USART1_RDATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH1, &dma_init_struct);
/* configure DMA mode */
dma_circulation_enable(DMA_CH1);
dma_memory_to_memory_disable(DMA_CH1);
/* disable the DMAMUX_MUXCH1 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH1);
/* USART DMA enable for reception */
usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
nvic_irq_enable(DMA_Channel1_IRQn, 0);
}
自写printf debuglog
自己写了个类似printf的串口发送,在Xcom里换行尾部加 \ r\ n
void usart_dma_printf(char* fmt, ...)
{
char* str = (char*)malloc(200);
memset(str, 0, 200);
va_list ap;
va_start(ap, fmt);
vsprintf(str, fmt, ap);
va_end(ap);
uint8_t byte_size = 0;
while(str[byte_size] != '\0')byte_size++;
uart1_interface_send((uint8_t*)str, byte_size);
//free str
free(str);
str = NULL;
}
uint32_t uart1_interface_send(uint8_t* data, uint16_t len)
{
static volatile uint8_t uart1_lock = 0;
static uint8_t uart1_send_buf[USART_DMA_TX_BUF_LEN];
static uint16_t count, send_len;
while(uart1_lock)//多线程访问时会上锁
{
;
}
uart1_lock = 1;
count = 0;
while(count < len)//若len>USART_DMA_TX_BUF_LEN,进行多包发送
{
while(DMA_CHCNT(DMA_CH2))//等待一次发送完成
{
;
}
if(len - count > USART_DMA_TX_BUF_LEN)
{
send_len = USART_DMA_TX_BUF_LEN;
}
else
{
send_len = len - count;
}
memcpy(uart1_send_buf, data + count, send_len);
dma_channel_disable(DMA_CH2);
dma_memory_address_config(DMA_CH2, (uint32_t)&uart1_send_buf[0]);
dma_transfer_number_config(DMA_CH2, send_len);
dma_channel_enable(DMA_CH2);
count += send_len;
}
uart1_lock = 0;
return 0;
}
以及printf重定向
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE* f)
{
usart_data_transmit(USART1, (uint8_t)ch);
while(RESET == usart_flag_get(USART1, USART_FLAG_TBE))
;
return ch;
}
串口空闲中断+dma完成中断,双缓冲区接收
uint8_t usart1_rx_flag;
uint8_t usart1_rx_buf[2][USART1_RX_BUF_LEN];
void USART1_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE))
{
static uint16_t this_time_rx_len = 0;
// clear flag
usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
/* enable DMA channel 0 transfer complete interrupt */
dma_interrupt_disable(DMA_CH1, DMA_INT_FTF);//必须先关dma中断在关dma
dma_channel_disable(DMA_CH1);
dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_FTF);//清标志位
this_time_rx_len = USART1_RX_BUF_LEN - dma_transfer_number_get(DMA_CH1);;
dma_transfer_number_config(DMA_CH1, USART1_RX_BUF_LEN);
if(this_time_rx_len == 0)//满了触发完成中断
{
dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
dma_channel_enable(DMA_CH1);
return;
}
dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
if(usart1_rx_flag)
{
dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[0]);
dma_channel_enable(DMA_CH1);
usart1_rx_flag = 0;
}
else
{
dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[1]);
dma_channel_enable(DMA_CH1);
usart1_rx_flag = 1;
}
}
}
void DMA_Channel1_IRQHandler(void)
{
if(RESET != dma_interrupt_flag_get(DMA_CH1, DMA_INT_FLAG_FTF))
{
/*disable and clear flag */
dma_channel_disable(DMA_CH1);
dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_FTF);
dma_transfer_number_config(DMA_CH1, USART1_RX_BUF_LEN);
if(usart1_rx_flag)
{
dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[0]);
dma_channel_enable(DMA_CH1);
usart1_rx_flag = 0;
}
else
{
dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[1]);
dma_channel_enable(DMA_CH1);
usart1_rx_flag = 1;
}
}
}