GD32F103串口DMA收发空闲中断与DMA的使用方法详解
GD32F103串口DMA收发(空闲中断 + DMA)
此前写了一篇DMA串口收发的文章,参照的是GD官方例程,虽然实现了串口数据的传输,后面在实际项目应用时发现还是有点问题,不能完全按照预想的方式进行数据传输和处理,经过不断的调试,现更新如下,特此记录。
GD32F103串口DMA收发(空闲中断 + DMA)
1. 串口IO初始化
这次使用的是GD32F103CBT6串口2,对应Pin脚PB10、PB11。
代码如下:
uint8_t rxbuffer[84];
uint8_t txbuffer[84] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};
#define USART0_DATA_ADDRESS ((uint32_t)&USART_DATA(USART0))
#define USART2_DATA_ADDRESS ((uint32_t)&USART_DATA(USART2))
static void usart_config(uint32_t baudval)
{
//USART0
rcu_periph_clock_enable(RCU_GPIOA); //enable GPIO clock, PA9/PA10
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_USART0); //enable USART clock
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); //PA9--TX0
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); //PA10--RX0
usart_deinit(USART0);
usart_baudrate_set(USART0, baudval);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
//USART2
rcu_periph_clock_enable(RCU_GPIOB); //enable GPIO clock, PB10/PA11
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_USART2); //enable USART2 clock
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);//USART2_TX
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);//USART2_RX
usart_deinit(USART2);
usart_baudrate_set(USART2, baudval);
usart_word_length_set(USART2, USART_WL_8BIT);
usart_stop_bit_set(USART2, USART_STB_1BIT);
usart_parity_config(USART2, USART_PM_NONE);
usart_hardware_flow_rts_config(USART2, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART2, USART_CTS_DISABLE);
usart_receive_config(USART2, USART_RECEIVE_ENABLE);
usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);
usart_enable(USART2);
}
2. DMA初始化
代码如下:
static void usart_dma_config(void)
{
dma_parameter_struct dma_init_struct;
/* enable DMA0 clock */
rcu_periph_clock_enable(RCU_DMA0);
/* deinitialize DMA channel1(USART2 tx) */
dma_deinit(DMA0, DMA_CH1);
dma_struct_para_init(&dma_init_struct);
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 = ARRAYNUM(txbuffer);
dma_init_struct.periph_addr = USART2_DATA_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(DMA0, DMA_CH1, &dma_init_struct);
/* deinitialize DMA channel2 (USART2 rx) */
dma_deinit(DMA0, DMA_CH2);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)rxbuffer;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = ARRAYNUM(rxbuffer);
dma_init_struct.periph_addr = USART2_DATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH2, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH1);
dma_memory_to_memory_disable(DMA0, DMA_CH1);
// dma_circulation_enable(DMA0, DMA_CH2); // 使用接收空闲中断,是否循环没有关系
dma_circulation_disable(DMA0, DMA_CH2);
dma_memory_to_memory_disable(DMA0, DMA_CH2);
/* USART DMA0 enable for reception */
usart_dma_receive_config(USART2, USART_DENR_ENABLE);
/* enable DMA0 channel2 transfer complete interrupt */
dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);
/* enable DMA0 channel2 */
dma_channel_enable(DMA0, DMA_CH2);
/* USART DMA0 enable for transmission */
usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
/* enable DMA0 channel1 transfer complete interrupt */
// dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
// /* disable DMA0 channel1 */
dma_channel_disable(DMA0, DMA_CH1);
}
3. 中断配置
代码如下:
static void nvic_config(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE3_SUB1);
// nvic_irq_enable(DMA0_Channel1_IRQn, 0, 0);
nvic_irq_enable(USART2_IRQn,1,0);
usart_interrupt_enable(USART2, USART_INT_FLAG_IDLE);
// nvic_irq_enable(DMA0_Channel2_IRQn, 0, 1);
}
4. 串口初始化
代码如下:
void bsp_usart_init()
{
memset(rxbuffer,0xff,sizeof(rxbuffer));
usart_config(BAUDRATE);
nvic_config();
usart_dma_config();
}
5. 串口发送函数和printf支持实现
代码如下:
void usart2_dma_send(uint8_t *buffer,uint16_t len)
{
dma_channel_disable(DMA0, DMA_CH1);
dma_memory_address_config(DMA0, DMA_CH1,(uint32_t)buffer);//设置要发送数据的内存地址
dma_transfer_number_config(DMA0, DMA_CH1, len);//一共发送多少个数据
dma_channel_enable(DMA0, DMA_CH1);
}
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART2, (uint8_t)ch);
while(RESET == usart_flag_get(USART2, USART_FLAG_TBE));
return ch;
}
6. 头文件中的宏定义和函数声明如下
代码如下:
#define BAUDRATE 115200U
#define ARRAYNUM(arr_name) (uint32_t)(sizeof(arr_name) / sizeof(*(arr_name)))
void bsp_usart_init(void);
void usart2_dma_send(uint8_t *buffer,uint16_t len);
int fputc(int ch, FILE *f);
7. 中断处理
代码如下:
void USART2_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE))
{
usart_data_receive(USART2);
dma_channel_disable(DMA0, DMA_CH2);
/************************
接收数据处理函数
************************/
dma_transfer_number_config(DMA0, DMA_CH2, 84);
dma_channel_enable(DMA0, DMA_CH2);
}
}
总结
GD32F103串口DMA收发(空闲中断 + DMA)