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)

物联沃分享整理
物联沃-IOTWORD物联网 » GD32F103串口DMA收发空闲中断与DMA的使用方法详解

发表评论