RT-Thread 框架下,GD32F450,串口DMA收发驱动 编写示例

发布于:2022-12-28 ⋅ 阅读:(1783) ⋅ 点赞:(1)

写在前面的话

RT-Thread的软件包,BSP目录下,GD32F450-eval,串口驱动目前(2022/09/05)还不全,只能一个byte一个byte的接收,对于一个搞硬件的熟系MCU运行方式的强迫症来说, 如此浪费CPU资源,这能忍?,,本来想学一下怎么在gitte提交维护,但是没有用过,感觉有点麻烦,本文将实现方式进行说明,有空再去更新。

附RT-thread官网:https://www.rt-thread.org/page/download.html

步骤一:增加每个串口的DMA收发通道

去看好GD32F450的数据手册,定义好DMA收发通道,,定义好一个结构体,用于存放不同串口的通道描述

#ifdef RT_SERIAL_USING_DMA
struct dma_config
{
    uint32_t dma_periph;
    dma_channel_enum channel;
    dma_subperipheral_enum peripheral;
    uint32_t priority;
	uint32_t last_index;
	
	IRQn_Type dma_irqn;
};


static struct dma_config tx_dma_confings[] =
{
    //USART0 TODO
    {
        .dma_periph = DMA1,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART1
    {
        .dma_periph = DMA0,
        .channel = DMA_CH6,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART2
    {
        .dma_periph = DMA0,
        .channel = DMA_CH3,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART3
    {
        .dma_periph = DMA0,
        .channel = DMA_CH4,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART4
    {
        .dma_periph = DMA0,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART5
    {
        .dma_periph = DMA1,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART6
    {
        .dma_periph = DMA0,
        .channel = DMA_CH1,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART7
    {
        .dma_periph = DMA0,
        .channel = DMA_CH0,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    }
};

static struct dma_config rx_dma_confings[] =
{
    //USART0
    {
        .dma_periph = DMA1,
        .channel = DMA_CH5,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA1_Channel5_IRQn,
    },
    //USART1
    {
        .dma_periph = DMA0,
        .channel = DMA_CH5,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel5_IRQn,
    },
    //USART2
    {
        .dma_periph = DMA0,
        .channel = DMA_CH1,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel1_IRQn,
    },
    //USART3
    {
        .dma_periph = DMA0,
        .channel = DMA_CH2,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel2_IRQn,
    },
    //USART4
    {
        .dma_periph = DMA0,
        .channel = DMA_CH0,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel0_IRQn,
    },
    //USART5
    {
        .dma_periph = DMA1,
        .channel = DMA_CH2,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA1_Channel2_IRQn,
    },
    //USART6
    {
        .dma_periph = DMA0,
        .channel = DMA_CH3,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel3_IRQn,
    },
    //USART7
    {
        .dma_periph = DMA0,
        .channel = DMA_CH6,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel6_IRQn,
    }
};
#endif

我只用的uart1、uart2、uart3、uart5,其他的不用事实上可填NULL,要注意通道不要冲突

注意用预编译指令,设置好后,后期可以使用evn工具进行裁剪选用(RT-Thread Env工具下 scons命令构建工程 SConscript和Kconfig修改示例_灵魂Maker的博客-CSDN博客

步骤二:在原本的串口描述结构里,增加DMA相关内容

    #ifdef BSP_USING_UART2
    {
        USART2,                                 // uart peripheral index
        USART2_IRQn,                            // uart iqrn
        RCU_USART2, RCU_GPIOD, RCU_GPIOD,RCU_GPIOB,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOD, GPIO_AF_7, GPIO_PIN_8,           // tx port, tx alternate, tx pin
        GPIOD, GPIO_AF_7, GPIO_PIN_9,           // rx port, rx alternate, rx pin
		GPIOB, GPIO_AF_7, GPIO_PIN_14,           // rst port, rst alternate, rst pin
        &serial2,
        "uart2",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[2],
            .dma_tx =   &tx_dma_confings[2],
        #endif
    },
    #endif

串口二示例,将收发DMA相关描述放到,串口的描述结构体中。

dma_flag 用于判断当前串口支持的模式,注意应用程序会用什么,,因为在注册串口设备时,会传入,,应用中开启对应设备,会检查相应的模式是否支持,不支持直接退出。

 图上图,serial中间层设备框架会检查,,

步骤三:增加DMA收发函数实现

#if defined(RT_SERIAL_USING_DMA) 
static void gd32_dma_rx_config(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    struct rt_serial_rx_fifo *rx_fifo;
    
    rx_fifo = (struct rt_serial_rx_fifo *)uart->serial->serial_rx;
    
	dma_single_data_parameter_struct dma_init_struct;
    
    if(uart->dma_rx != 0)
    {
        /* rest RTS */
        if( (uart->rts_port)&&(uart->rts_pin))
        {  
            gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
        }
        /* enable DMA */
        rcu_periph_clock_enable(RCU_DMA0);  
        rcu_periph_clock_enable(RCU_DMA1);
        
        /* USART DMA enable for reception */
        usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);
        
        /* deinitialize DMA channel */
        dma_deinit(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        
        /* set the DMA struct */
        dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
        dma_init_struct.memory0_addr = (uint32_t)(rx_fifo->buffer);
        dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
        dma_init_struct.number = uart->serial->config.bufsz;
        dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph);
        dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
        dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
        dma_init_struct.priority = uart->dma_rx->priority;
		
		dma_single_data_mode_init(uart->dma_rx->dma_periph, uart->dma_rx->channel, &dma_init_struct);
		
        /* configure DMA mode */
        dma_circulation_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel); 
		dma_channel_subperipheral_select(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->dma_rx->peripheral);
		
        /* enable DMA channel */
        dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        
        /* enable rx irq */
        NVIC_EnableIRQ(uart->irqn);
        /* enable interrupt */
        usart_interrupt_enable(uart->uart_periph, USART_INT_IDLE);
		
		/* enable DMA rx irq */
		NVIC_EnableIRQ(uart->dma_rx->dma_irqn);
        /* enable DMA full transfer finish interrupt */
        dma_interrupt_enable(uart->dma_rx->dma_periph,uart->dma_rx->channel,DMA_CHXCTL_FTFIE); 
        
        uart->dma_rx->last_index = 0;
    }
}

static void gd32_dma_tx_config(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    if(uart->dma_tx != 0)
    {
        /* enable DMA */
        rcu_periph_clock_enable(RCU_DMA0);  
        rcu_periph_clock_enable(RCU_DMA1);
        
        /* clean TC flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
        /* enable rx irq */
        NVIC_EnableIRQ(uart->irqn);
        /* enable interrupt */
        usart_interrupt_enable(uart->uart_periph, USART_INT_TC);
		
    }
}
static void gd32_dma_rx_disable(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    /* USART DMA disable for reception */
    usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE); 
    
    /* disable DMA channel */   
    if(uart->dma_rx != 0)
    {
        dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel); 
    }
}   
static void gd32_dma_tx_disable(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    /* USART DMA enable for transmission */
    usart_dma_transmit_config(uart->uart_periph, USART_DENT_DISABLE);    
    
    /* disable DMA channel */  
    if(uart->dma_tx != 0)
    {
        dma_channel_disable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
    }
}

rt_size_t dma_tx_xfer(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
    struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data; 
    rt_size_t xfer_size = 0;      
    
//    dma_parameter_struct dma_init_struct; 
	dma_single_data_parameter_struct dma_init_struct;

    RT_ASSERT(uart != RT_NULL);
    
    if(0 != size )
    {
        if (RT_SERIAL_DMA_TX == direction)
        {   
            /* set RTS */ 
            if( (uart->rts_port)&&(uart->rts_pin))
            {  
                gpio_bit_write(uart->rts_port, uart->rts_pin, SET);
            }
//			while()
//			{
//			   rt_size_t ++;
//			   if(rt_size_t >= 10000) break;
//			}
			/* deinitialize DMA channel */
            dma_deinit(uart->dma_tx->dma_periph, uart->dma_tx->channel);
		
			dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
			dma_init_struct.memory0_addr = (uint32_t)buf;
			dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
			dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
			dma_init_struct.number = size;
			dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph);
			dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
			dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
			
			dma_single_data_mode_init(uart->dma_tx->dma_periph, uart->dma_tx->channel, &dma_init_struct);
            /* configure DMA mode */
            dma_circulation_disable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
			dma_channel_subperipheral_select(uart->dma_tx->dma_periph, uart->dma_tx->channel, uart->dma_tx->peripheral);
			
			/* enable DMA channel7 */
			dma_channel_enable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
			/* USART DMA enable for transmission and reception */
			usart_dma_transmit_config(uart->uart_periph, USART_DENT_ENABLE);
            xfer_size = size;
        }
    }
    return xfer_size;
}

#endif

gd32_dma_rx_disable 和 gd32_dma_tx_disable 用于失能DMA,应当在应用层关闭设备时调用,目前没有用到。

gd32_dma_rx_config 用于配置对应串口的dma收,前面配置传输方向,位长,数据长度,内存外设地址之类的,比较常规,不在详细描述。

特别需要注意的是,需要开启DMA接收完成中断(后文会详细说明这么做的理由)

你可能会注意到gd32_dma_tx_config 配置了串口的发送中断,而没有配置DMA的发送完成中断,这么做是因为DMA传输完成并不代表串口传输完成,加上实际应用中我采用了485芯片,需要用一个IO引脚控制切换485芯片的收发,需要等串口发送完成中断,才能改板IO电平状态。

串口发送完成中断,会在一帧发送完成后才触发,满足实际使用要求。

编写好DMA收发初始化函数后,记得要在控制函数里面添加相应的DMA控制分支

static rt_err_t gd32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    struct gd32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct gd32_uart *)serial->parent.user_data;

	#if defined(RT_SERIAL_USING_DMA) || defined(BSP_USING_USART_RTS) 
    rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
	#endif
	
    switch (cmd)
    {
		case RT_DEVICE_CTRL_CLR_INT:
			/* disable rx irq */
			NVIC_DisableIRQ(uart->irqn);
			/* disable interrupt */
			usart_interrupt_disable(uart->uart_periph, USART_INT_RBNE);

			break;
		case RT_DEVICE_CTRL_SET_INT:
			/* enable rx irq */
			NVIC_EnableIRQ(uart->irqn);
			/* enable interrupt */
			usart_interrupt_enable(uart->uart_periph, USART_INT_RBNE);
			break;
	#ifdef RT_SERIAL_USING_DMA        
		case RT_DEVICE_CTRL_CONFIG:
			if (RT_DEVICE_FLAG_DMA_RX == ctrl_arg)
			{
				gd32_dma_rx_config(uart);
			}
			else if(RT_DEVICE_FLAG_DMA_TX == ctrl_arg)
			{
				gd32_dma_tx_config(uart);
			}
			break;
	#endif
	#ifdef BSP_USING_USART_RTS
		case RT_SERIAL_CTRL_RTS:
			if(RT_SERIAL_RTS_SET == ctrl_arg)
			{  
				/* set RTS */
				if( (uart->rts_port)&&(uart->rts_pin))
				{  
					gpio_bit_write(uart->rts_port, uart->rts_pin, SET);
				}
			}
			else if(RT_SERIAL_RTS_RESET == ctrl_arg) 
			{ 
				/* reset RTS */
				if( (uart->rts_port)&&(uart->rts_pin))
				{  
					gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
				}
			}
			break;
	#endif
    }
    return RT_EOK;
}

步骤四:增加DMA收发函数实现

在接收函数需要在串口空闲中断里面处理,传完一帧后,触发空闲中断,此时DMA已经将数据复制到指定BUF,该buf,在open的时候,由Serial中间层组件动态申请。

/**
 * Uart common interrupt process. This need add to uart ISR.
 *
 * @param serial serial device
 */
static void uart_isr(struct rt_serial_device *serial)
{
    struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data;

    RT_ASSERT(uart != RT_NULL);
#ifdef RT_SERIAL_USING_DMA  
    rt_size_t total_index, recv_len, dma_cnt;
    rt_base_t level;
#endif
    /* UART in mode Receiver -------------------------------------------------*/
    if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) &&
            (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET))
    {
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
        /* Clear RXNE interrupt flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);
    }
	
#ifdef RT_SERIAL_USING_DMA   
	
	/* check DMA flag is set or not */
    if(dma_interrupt_flag_get(uart->dma_rx->dma_periph,uart->dma_rx->channel,DMA_INT_FLAG_FTF) != RESET) 
	{
	 	 /* clear DMA a channel flag */
		dma_interrupt_flag_clear(uart->dma_rx->dma_periph, uart->dma_rx->channel,DMA_INT_FLAG_FTF);
		
        usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE);
        dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        dma_transfer_number_config(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->serial->config.bufsz );
        dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);

//	  	gd32_dma_rx_config(uart);
	}
	
    if(usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_IDLE) != RESET) 
    {
        usart_flag_get(uart->uart_periph,USART_FLAG_IDLE);
        usart_data_receive(uart->uart_periph);
        
        level = rt_hw_interrupt_disable();

        dma_cnt = dma_transfer_number_get(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        total_index = uart->serial->config.bufsz - dma_cnt;// DMA_CH4CNT(DMA0);     //uart0 use dma0 ch4
        if (total_index > uart->dma_rx->last_index)
        {
            recv_len = total_index - uart->dma_rx->last_index;
        }
        else
        {
            recv_len = total_index + (uart->serial->config.bufsz - uart->dma_rx->last_index);
        }
        
        if ((recv_len > 0) && (recv_len < uart->serial->config.bufsz))
        {
            if(dma_cnt)  //不用环,用环得加DMA接收完成中断
            {
                uart->dma_rx->last_index = total_index;
            }
            else
            {
                uart->dma_rx->last_index = 0;
            }
            rt_hw_interrupt_enable(level);
			
            rt_hw_serial_isr(uart->serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
        }
        else
        {
            rt_hw_interrupt_enable(level);
        }
//        //transfer completed, configurate dma
//        if(dma_cnt == 0)
//        {
//            usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE);
//            dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
//            dma_transfer_number_config(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->serial->config.bufsz );
//            dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
//            usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);
//        }
    }
    if(usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TC) != RESET) 
    {            
        usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
        rt_hw_serial_isr(uart->serial, RT_SERIAL_EVENT_TX_DMADONE);  
        /* rest RTS */
        if( (uart->rts_port)&&(uart->rts_pin))
        {  
            gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
        }
    }
#endif
}

DMA接收完成中断,也调用uart_isr,然后再里面判断是那一种中断类型,进行处理。

编写驱动时遇到的问题(供大家参考学习)

Q0: 最初只有串口空闲中断,没有开DMA接收完成中断时,串口收数据时,收几个包后(总长大于设定值),串口就会死机,

D0: 一开始时以为DMA收完了,没有重新初始化导致的,,改成每进入一次串口空闲中断就重新初始化一次DMA接收,,

Q1: 在线debug发现每次收数据都能正常,但是应用层通过rt_device_read接口读出的数据不正常,

D1: 后来想起来rt-thread对应串口的数据接收采用的是ringbuffer的模式,

以前常规的写法(每进入一次串口空闲中断就重新初始化一次DMA接收),串口每收到一个包的数据,都是按顺序从0开始排放。也就是每次都应该重0开始读,但是ringbuffer不是这样,rt_device_read去读时,读错位置。

Q2: 因为不能更改设备驱动(公共文件),一开始先想办法欺骗ringbuffer,让其指针不用动,一直停留在0,这个rt_device_read去读时,就会一直从0开始读。(如果可以就不用添加DMA中断,省很多事)

D2:,先设置传入rt_hw_serial_isr的recv_len强行设为0.

Q3:这样缺少可以欺骗ringbuffer,又引入另一个问题,应用层无法得知包长,因为包长也是通过recv_len传下去的。

D3:最终还是得老老实实加DMA中断,在接收完成立刻重新初始化DMA(重新设置接收长度即可),

附上最终能用的驱动层.c和.h

drv_usart.c


#include <gd32f4xx.h>
#include <drv_usart.h>
#include <board.h>

#ifdef RT_USING_SERIAL

#if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1) && \
    !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3) && \
    !defined(BSP_USING_UART4) && !defined(BSP_USING_UART5) && \
    !defined(BSP_USING_UART6) && !defined(BSP_USING_UART7)
#error "Please define at least one UARTx"

#endif

#include <rtdevice.h>
	  
	  
#ifdef RT_SERIAL_USING_DMA

struct dma_config
{
    uint32_t dma_periph;
    dma_channel_enum channel;
    dma_subperipheral_enum peripheral;
    uint32_t priority;
	uint32_t last_index;
	
	IRQn_Type dma_irqn;
};

#endif

/* GD32 uart driver */
// Todo: compress uart info
struct gd32_uart
{
    uint32_t uart_periph;           //Todo: 3bits
    IRQn_Type irqn;                 //Todo: 7bits
    rcu_periph_enum per_clk;        //Todo: 5bits
    rcu_periph_enum tx_gpio_clk;    //Todo: 5bits
    rcu_periph_enum rx_gpio_clk;    //Todo: 5bits
    rcu_periph_enum rts_gpio_clk;   //Todo: 5bits
	
    uint32_t tx_port;               //Todo: 4bits
    uint16_t tx_af;                 //Todo: 4bits
    uint16_t tx_pin;                //Todo: 4bits
    uint32_t rx_port;               //Todo: 4bits
    uint16_t rx_af;                 //Todo: 4bits
    uint16_t rx_pin;                //Todo: 4bits
	
    uint32_t rts_port;              //Todo: 4bits
    uint16_t rts_af;                //Todo: 4bits
    uint16_t rts_pin;               //Todo: 4bits
	
    struct rt_serial_device * serial;
    char *device_name;
	
#ifdef RT_SERIAL_USING_DMA          // don't change the sequence
    uint32_t dma_flag;
    struct dma_config *dma_rx;
    struct dma_config *dma_tx;
#endif
	
};

static void uart_isr(struct rt_serial_device *serial);

#if defined(BSP_USING_UART0)
struct rt_serial_device serial0;

void USART0_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial0);

    /* leave interrupt */
    rt_interrupt_leave();
}

#endif /* BSP_USING_UART0 */

#if defined(BSP_USING_UART1)
struct rt_serial_device serial1;

void USART1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial1);

    /* leave interrupt */
    rt_interrupt_leave();
}
//开DMA完成中断
void DMA0_Channel5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
	uart_isr(&serial1);
    /* leave interrupt */
    rt_interrupt_leave();  
}

#endif /* BSP_USING_UART1 */

#if defined(BSP_USING_UART2)
struct rt_serial_device serial2;

void USART2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial2);

    /* leave interrupt */
    rt_interrupt_leave();
}
//开DMA完成中断
void DMA0_Channel1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
	
	uart_isr(&serial2);
	
    /* leave interrupt */
    rt_interrupt_leave();  
}

#endif /* BSP_USING_UART2 */

#if defined(BSP_USING_UART3)
struct rt_serial_device serial3;

void UART3_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial3);

    /* leave interrupt */
    rt_interrupt_leave();
}
//开DMA完成中断
void DMA0_Channel2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
	
	uart_isr(&serial3);
	
    /* leave interrupt */
    rt_interrupt_leave();  
}

#endif /* BSP_USING_UART3 */

#if defined(BSP_USING_UART4)
struct rt_serial_device serial4;

void UART4_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial4);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif /* BSP_USING_UART4 */

#if defined(BSP_USING_UART5)
struct rt_serial_device serial5;

void USART5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial5);

    /* leave interrupt */
    rt_interrupt_leave();
}
//开DMA完成中断
void DMA1_Channel2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
	
	uart_isr(&serial5);
	
    /* leave interrupt */
    rt_interrupt_leave();  
}

#endif /* BSP_USING_UART5 */

#if defined(BSP_USING_UART6)
struct rt_serial_device serial6;

void UART6_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial6);

    /* leave interrupt */
    rt_interrupt_leave();
}

#endif /* BSP_USING_UART6 */

#if defined(BSP_USING_UART7)
struct rt_serial_device serial7;

void UART7_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial7);

    /* leave interrupt */
    rt_interrupt_leave();
}

#endif /* BSP_USING_UART7 */

#ifdef RT_SERIAL_USING_DMA

static struct dma_config tx_dma_confings[] =
{
    //USART0 TODO
    {
        .dma_periph = DMA1,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART1
    {
        .dma_periph = DMA0,
        .channel = DMA_CH6,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART2
    {
        .dma_periph = DMA0,
        .channel = DMA_CH3,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART3
    {
        .dma_periph = DMA0,
        .channel = DMA_CH4,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART4
    {
        .dma_periph = DMA0,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART5
    {
        .dma_periph = DMA1,
        .channel = DMA_CH7,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART6
    {
        .dma_periph = DMA0,
        .channel = DMA_CH1,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    },
    //USART7
    {
        .dma_periph = DMA0,
        .channel = DMA_CH0,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = NULL,
    }
};

static struct dma_config rx_dma_confings[] =
{
    //USART0
    {
        .dma_periph = DMA1,
        .channel = DMA_CH5,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA1_Channel5_IRQn,
    },
    //USART1
    {
        .dma_periph = DMA0,
        .channel = DMA_CH5,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel5_IRQn,
    },
    //USART2
    {
        .dma_periph = DMA0,
        .channel = DMA_CH1,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel1_IRQn,
    },
    //USART3
    {
        .dma_periph = DMA0,
        .channel = DMA_CH2,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel2_IRQn,
    },
    //USART4
    {
        .dma_periph = DMA0,
        .channel = DMA_CH0,
        .peripheral = DMA_SUBPERI4,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel0_IRQn,
    },
    //USART5
    {
        .dma_periph = DMA1,
        .channel = DMA_CH2,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA1_Channel2_IRQn,
    },
    //USART6
    {
        .dma_periph = DMA0,
        .channel = DMA_CH3,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel3_IRQn,
    },
    //USART7
    {
        .dma_periph = DMA0,
        .channel = DMA_CH6,
        .peripheral = DMA_SUBPERI5,
        .priority = DMA_PRIORITY_ULTRA_HIGH,
		.dma_irqn = DMA0_Channel6_IRQn,
    }
};

#endif


static const struct gd32_uart uarts[] = {
    #ifdef BSP_USING_UART0
    {
        .uart_periph = USART0,                                 // uart peripheral index
        USART0_IRQn,                            // uart iqrn
        RCU_USART0, RCU_GPIOA, RCU_GPIOA,NULL,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOA, GPIO_AF_7, GPIO_PIN_9,           // tx port, tx alternate, tx pin
        GPIOA, GPIO_AF_7, GPIO_PIN_10,          // rx port, rx alternate, rx pin
		NULL, NULL, NULL,                       // rst port, rst alternate, rst pin
        &serial0,
        "uart0",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[0],
            .dma_tx =   &tx_dma_confings[0],
        #endif
    },
    #endif

    #ifdef BSP_USING_UART1
    {
        USART1,                                 // uart peripheral index
        USART1_IRQn,                            // uart iqrn
        RCU_USART1, RCU_GPIOD, RCU_GPIOD,RCU_GPIOD,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOD, GPIO_AF_7, GPIO_PIN_5,           // tx port, tx alternate, tx pin
        GPIOD, GPIO_AF_7, GPIO_PIN_6,           // rx port, rx alternate, rx pin
		GPIOD, GPIO_AF_7, GPIO_PIN_4,           // rst port, rst alternate, rst pin
        &serial1,
        "uart1",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[1],
            .dma_tx =   &tx_dma_confings[1],
        #endif
    },
    #endif

    #ifdef BSP_USING_UART2
    {
        USART2,                                 // uart peripheral index
        USART2_IRQn,                            // uart iqrn
        RCU_USART2, RCU_GPIOD, RCU_GPIOD,RCU_GPIOB,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOD, GPIO_AF_7, GPIO_PIN_8,           // tx port, tx alternate, tx pin
        GPIOD, GPIO_AF_7, GPIO_PIN_9,           // rx port, rx alternate, rx pin
		GPIOB, GPIO_AF_7, GPIO_PIN_14,           // rst port, rst alternate, rst pin
        &serial2,
        "uart2",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[2],
            .dma_tx =   &tx_dma_confings[2],
        #endif
    },
    #endif

    #ifdef BSP_USING_UART3
    {
        UART3,                                 // uart peripheral index
        UART3_IRQn,                            // uart iqrn
        RCU_UART3, RCU_GPIOC, RCU_GPIOC,NULL,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOC, GPIO_AF_8, GPIO_PIN_10,         // tx port, tx alternate, tx pin
        GPIOC, GPIO_AF_8, GPIO_PIN_11,         // rx port, rx alternate, rx pin
		NULL, NULL, NULL,                      // rst port, rst alternate, rst pin
        &serial3,
        "uart3",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag =  RT_DEVICE_FLAG_INT_RX , //串口3用于控制台控制,,
            .dma_rx =   &rx_dma_confings[3],
            .dma_tx =   &tx_dma_confings[3],
        #endif	
    },
    #endif

    #ifdef BSP_USING_UART4
    {
        UART4,                                 // uart peripheral index
        UART4_IRQn,                            // uart iqrn
        RCU_UART4, RCU_GPIOC, RCU_GPIOD,NULL,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOC, GPIO_AF_8, GPIO_PIN_12,         // tx port, tx alternate, tx pin
        GPIOD, GPIO_AF_8, GPIO_PIN_2,          // rx port, rx alternate, rx pin
		NULL, NULL, NULL,                      // rst port, rst alternate, rst pin
        &serial4,
        "uart4",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[4],
            .dma_tx =   &tx_dma_confings[4],
        #endif
    },
    #endif

    #ifdef BSP_USING_UART5
    {
        USART5,                                 // uart peripheral index
        USART5_IRQn,                            // uart iqrn
        RCU_USART5, RCU_GPIOC, RCU_GPIOC,RCU_GPIOC,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOC, GPIO_AF_8, GPIO_PIN_6,           // tx port, tx alternate, tx pin
        GPIOC, GPIO_AF_8, GPIO_PIN_7,           // rx port, rx alternate, rx pin
		GPIOC, GPIO_AF_8, GPIO_PIN_8,           // rst port, rst alternate, rst pin
        &serial5,
        "uart5",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[5],
            .dma_tx =   &tx_dma_confings[5],
        #endif

    },
    #endif

    #ifdef BSP_USING_UART6
    {
        UART6,                                 // uart peripheral index
        UART6_IRQn,                            // uart iqrn
        RCU_UART6, RCU_GPIOE, RCU_GPIOE,NULL,       // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOE, GPIO_AF_8, GPIO_PIN_7,          // tx port, tx alternate, tx pin
        GPIOE, GPIO_AF_8, GPIO_PIN_8,          // rx port, rx alternate, rx pin
		NULL, NULL, NULL,                       // rst port, rst alternate, rst pin
        &serial6,
        "uart6",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[6],
            .dma_tx =   &tx_dma_confings[6],
        #endif
    },
    #endif

    #ifdef BSP_USING_UART7
    {
        UART7,                                 // uart peripheral index
        UART7_IRQn,                            // uart iqrn
        RCU_UART7, RCU_GPIOE, RCU_GPIOE,NULL,  // periph clock, tx gpio clock, rt gpio clock, rst gpio clock
        GPIOE, GPIO_AF_8, GPIO_PIN_0,          // tx port, tx alternate, tx pin
        GPIOE, GPIO_AF_8, GPIO_PIN_1,          // rx port, rx alternate, rx pin
		NULL, NULL, NULL,                      // rst port, rst alternate, rst pin
        &serial7,
        "uart7",
        #ifdef RT_SERIAL_USING_DMA
            .dma_flag = RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
            .dma_rx =   &rx_dma_confings[7],
            .dma_tx =   &tx_dma_confings[7],
        #endif
    },
    #endif
};

#if defined(RT_SERIAL_USING_DMA) 
static void gd32_dma_rx_config(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    struct rt_serial_rx_fifo *rx_fifo;
    
    rx_fifo = (struct rt_serial_rx_fifo *)uart->serial->serial_rx;
    
	dma_single_data_parameter_struct dma_init_struct;
    
    if(uart->dma_rx != 0)
    {
        /* rest RTS */
        if( (uart->rts_port)&&(uart->rts_pin))
        {  
            gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
        }
        /* enable DMA */
        rcu_periph_clock_enable(RCU_DMA0);  
        rcu_periph_clock_enable(RCU_DMA1);
        
        /* USART DMA enable for reception */
        usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);
        
        /* deinitialize DMA channel */
        dma_deinit(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        
        /* set the DMA struct */
        dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
        dma_init_struct.memory0_addr = (uint32_t)(rx_fifo->buffer);
        dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
        dma_init_struct.number = uart->serial->config.bufsz;
        dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph);
        dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
        dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
        dma_init_struct.priority = uart->dma_rx->priority;
		
		dma_single_data_mode_init(uart->dma_rx->dma_periph, uart->dma_rx->channel, &dma_init_struct);
		
        /* configure DMA mode */
        dma_circulation_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel); 
		dma_channel_subperipheral_select(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->dma_rx->peripheral);
		
        /* enable DMA channel */
        dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        
        /* enable rx irq */
        NVIC_EnableIRQ(uart->irqn);
        /* enable interrupt */
        usart_interrupt_enable(uart->uart_periph, USART_INT_IDLE);
		
		/* enable DMA rx irq */
		NVIC_EnableIRQ(uart->dma_rx->dma_irqn);
        /* enable DMA full transfer finish interrupt */
        dma_interrupt_enable(uart->dma_rx->dma_periph,uart->dma_rx->channel,DMA_CHXCTL_FTFIE); 
        
        uart->dma_rx->last_index = 0;
    }
}

static void gd32_dma_tx_config(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    if(uart->dma_tx != 0)
    {
        /* enable DMA */
        rcu_periph_clock_enable(RCU_DMA0);  
        rcu_periph_clock_enable(RCU_DMA1);
        
        /* clean TC flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
        /* enable rx irq */
        NVIC_EnableIRQ(uart->irqn);
        /* enable interrupt */
        usart_interrupt_enable(uart->uart_periph, USART_INT_TC);
		
    }
}
static void gd32_dma_rx_disable(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    /* USART DMA disable for reception */
    usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE); 
    
    /* disable DMA channel */   
    if(uart->dma_rx != 0)
    {
        dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel); 
    }
}   
static void gd32_dma_tx_disable(struct gd32_uart *uart)
{                    
    RT_ASSERT(uart != RT_NULL);
    
    /* USART DMA enable for transmission */
    usart_dma_transmit_config(uart->uart_periph, USART_DENT_DISABLE);    
    
    /* disable DMA channel */  
    if(uart->dma_tx != 0)
    {
        dma_channel_disable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
    }
}
#endif

/**
* @brief UART MSP Initialization
*        This function configures the hardware resources used in this example:
*           - Peripheral's clock enable
*           - Peripheral's GPIO Configuration
*           - NVIC configuration for UART interrupt request enable
* @param huart: UART handle pointer
* @retval None
*/
void gd32_uart_gpio_init(struct gd32_uart *uart)
{
    /* enable USART clock */
    rcu_periph_clock_enable(uart->tx_gpio_clk);
    rcu_periph_clock_enable(uart->rx_gpio_clk);
    rcu_periph_clock_enable(uart->per_clk);

    /* connect port to USARTx_Tx */
    gpio_af_set(uart->tx_port, uart->tx_af, uart->tx_pin);

    /* connect port to USARTx_Rx */
    gpio_af_set(uart->rx_port, uart->rx_af, uart->rx_pin);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(uart->tx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, uart->tx_pin);
    gpio_output_options_set(uart->tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, uart->tx_pin);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(uart->rx_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, uart->rx_pin);
    gpio_output_options_set(uart->rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, uart->rx_pin);
	
    /* connect port to USARTx_RTS */    
    if( (uart->rts_port)&&(uart->rts_pin))
    {
	  	rcu_periph_clock_enable(uart->rts_gpio_clk);
		gpio_mode_set(uart->rts_port, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, uart->rts_pin);
     	gpio_output_options_set(uart->rts_port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, uart->rts_pin);
        gpio_bit_write(uart->rts_port, uart->rts_pin, RESET); //接收
    }

    NVIC_SetPriority(uart->irqn, 0);
    NVIC_EnableIRQ(uart->irqn);
}

static rt_err_t gd32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
    struct gd32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    uart = (struct gd32_uart *)serial->parent.user_data;

    gd32_uart_gpio_init(uart);

    usart_baudrate_set(uart->uart_periph, cfg->baud_rate);

    switch (cfg->data_bits)
    {
		case DATA_BITS_9:
			usart_word_length_set(uart->uart_periph, USART_WL_9BIT);
			break;

		default:
			usart_word_length_set(uart->uart_periph, USART_WL_8BIT);
			break;
    }
    switch (cfg->stop_bits)
    {
		case STOP_BITS_2:
			usart_stop_bit_set(uart->uart_periph, USART_STB_2BIT);
			break;
		default:
			usart_stop_bit_set(uart->uart_periph, USART_STB_1BIT);
			break;
    }
    switch (cfg->parity)
    {
		case PARITY_ODD:
			usart_parity_config(uart->uart_periph, USART_PM_ODD);
			break;
		case PARITY_EVEN:
			usart_parity_config(uart->uart_periph, USART_PM_EVEN);
			break;
		default:
			usart_parity_config(uart->uart_periph, USART_PM_NONE);
			break;
    }
    usart_receive_config(uart->uart_periph, USART_RECEIVE_ENABLE);
    usart_transmit_config(uart->uart_periph, USART_TRANSMIT_ENABLE);
    usart_enable(uart->uart_periph);

    return RT_EOK;
}

static rt_err_t gd32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    struct gd32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct gd32_uart *)serial->parent.user_data;

	#if defined(RT_SERIAL_USING_DMA) || defined(BSP_USING_USART_RTS) 
    rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
	#endif
	
    switch (cmd)
    {
		case RT_DEVICE_CTRL_CLR_INT:
			/* disable rx irq */
			NVIC_DisableIRQ(uart->irqn);
			/* disable interrupt */
			usart_interrupt_disable(uart->uart_periph, USART_INT_RBNE);

			break;
		case RT_DEVICE_CTRL_SET_INT:
			/* enable rx irq */
			NVIC_EnableIRQ(uart->irqn);
			/* enable interrupt */
			usart_interrupt_enable(uart->uart_periph, USART_INT_RBNE);
			break;
	#ifdef RT_SERIAL_USING_DMA        
		case RT_DEVICE_CTRL_CONFIG:
			if (RT_DEVICE_FLAG_DMA_RX == ctrl_arg)
			{
				gd32_dma_rx_config(uart);
			}
			else if(RT_DEVICE_FLAG_DMA_TX == ctrl_arg)
			{
				gd32_dma_tx_config(uart);
			}
			break;
	#endif
	#ifdef BSP_USING_USART_RTS
		case RT_SERIAL_CTRL_RTS:
			if(RT_SERIAL_RTS_SET == ctrl_arg)
			{  
				/* set RTS */
				if( (uart->rts_port)&&(uart->rts_pin))
				{  
					gpio_bit_write(uart->rts_port, uart->rts_pin, SET);
				}
			}
			else if(RT_SERIAL_RTS_RESET == ctrl_arg) 
			{ 
				/* reset RTS */
				if( (uart->rts_port)&&(uart->rts_pin))
				{  
					gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
				}
			}
			break;
	#endif
    }
    return RT_EOK;
}

static int gd32_putc(struct rt_serial_device *serial, char ch)
{
    struct gd32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
	uart = (struct gd32_uart *)serial->parent.user_data;
	
    /* set RTS */ 
    if( (uart->rts_port)&&(uart->rts_pin))
    {  
        gpio_bit_write(uart->rts_port, uart->rts_pin, SET);
    }

    usart_data_transmit(uart->uart_periph, ch);
    while((usart_flag_get(uart->uart_periph, USART_FLAG_TC) == RESET));
	
    /* RESET RTS */ 
    if( (uart->rts_port)&&(uart->rts_pin))
    {  
        gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
    }
    return 1;
}

static int gd32_getc(struct rt_serial_device *serial)
{
    int ch;
    struct gd32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct gd32_uart *)serial->parent.user_data;

    ch = -1;
    if (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET)
        ch = usart_data_receive(uart->uart_periph);
    return ch;
}


#ifdef RT_SERIAL_USING_DMA 
rt_size_t dma_tx_xfer(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
    struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data; 
    rt_size_t xfer_size = 0;      
    
//    dma_parameter_struct dma_init_struct; 
	dma_single_data_parameter_struct dma_init_struct;

    RT_ASSERT(uart != RT_NULL);
    
    if(0 != size )
    {
        if (RT_SERIAL_DMA_TX == direction)
        {   
            /* set RTS */ 
            if( (uart->rts_port)&&(uart->rts_pin))
            {  
                gpio_bit_write(uart->rts_port, uart->rts_pin, SET);
            }
//			while()
//			{
//			   rt_size_t ++;
//			   if(rt_size_t >= 10000) break;
//			}
			/* deinitialize DMA channel */
            dma_deinit(uart->dma_tx->dma_periph, uart->dma_tx->channel);
		
			dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
			dma_init_struct.memory0_addr = (uint32_t)buf;
			dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
			dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
			dma_init_struct.number = size;
			dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph);
			dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
			dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
			
			dma_single_data_mode_init(uart->dma_tx->dma_periph, uart->dma_tx->channel, &dma_init_struct);
            /* configure DMA mode */
            dma_circulation_disable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
			dma_channel_subperipheral_select(uart->dma_tx->dma_periph, uart->dma_tx->channel, uart->dma_tx->peripheral);
			
			/* enable DMA channel7 */
			dma_channel_enable(uart->dma_tx->dma_periph, uart->dma_tx->channel);
			/* USART DMA enable for transmission and reception */
			usart_dma_transmit_config(uart->uart_periph, USART_DENT_ENABLE);
            xfer_size = size;
        }
    }
    return xfer_size;
}
#endif

/**
 * Uart common interrupt process. This need add to uart ISR.
 *
 * @param serial serial device
 */
static void uart_isr(struct rt_serial_device *serial)
{
    struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data;

    RT_ASSERT(uart != RT_NULL);
#ifdef RT_SERIAL_USING_DMA  
    rt_size_t total_index, recv_len, dma_cnt;
    rt_base_t level;
#endif
    /* UART in mode Receiver -------------------------------------------------*/
    if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) &&
            (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET))
    {
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
        /* Clear RXNE interrupt flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);
    }
	
#ifdef RT_SERIAL_USING_DMA   
	
	/* check DMA flag is set or not */
    if(dma_interrupt_flag_get(uart->dma_rx->dma_periph,uart->dma_rx->channel,DMA_INT_FLAG_FTF) != RESET) 
	{
	 	 /* clear DMA a channel flag */
		dma_interrupt_flag_clear(uart->dma_rx->dma_periph, uart->dma_rx->channel,DMA_INT_FLAG_FTF);
		
        usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE);
        dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        dma_transfer_number_config(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->serial->config.bufsz );
        dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);

//	  	gd32_dma_rx_config(uart);
	}
	
    if(usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_IDLE) != RESET) 
    {
        usart_flag_get(uart->uart_periph,USART_FLAG_IDLE);
        usart_data_receive(uart->uart_periph);
        
        level = rt_hw_interrupt_disable();

        dma_cnt = dma_transfer_number_get(uart->dma_rx->dma_periph, uart->dma_rx->channel);
        total_index = uart->serial->config.bufsz - dma_cnt;// DMA_CH4CNT(DMA0);     //uart0 use dma0 ch4
        if (total_index > uart->dma_rx->last_index)
        {
            recv_len = total_index - uart->dma_rx->last_index;
        }
        else
        {
            recv_len = total_index + (uart->serial->config.bufsz - uart->dma_rx->last_index);
        }
        
        if ((recv_len > 0) && (recv_len < uart->serial->config.bufsz))
        {
            if(dma_cnt)  //不用环,用环得加DMA接收完成中断
            {
                uart->dma_rx->last_index = total_index;
            }
            else
            {
                uart->dma_rx->last_index = 0;
            }
            rt_hw_interrupt_enable(level);

            rt_hw_serial_isr(uart->serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
        }
        else
        {
            rt_hw_interrupt_enable(level);
        }
//        //transfer completed, configurate dma
//        if(dma_cnt == 0)
//        {
//            usart_dma_receive_config(uart->uart_periph, USART_DENR_DISABLE);
//            dma_channel_disable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
//            dma_transfer_number_config(uart->dma_rx->dma_periph, uart->dma_rx->channel, uart->serial->config.bufsz );
//            dma_channel_enable(uart->dma_rx->dma_periph, uart->dma_rx->channel);
//            usart_dma_receive_config(uart->uart_periph, USART_DENR_ENABLE);
//        }
    }
    if(usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TC) != RESET) 
    {            
        usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
        rt_hw_serial_isr(uart->serial, RT_SERIAL_EVENT_TX_DMADONE);  
        /* rest RTS */
        if( (uart->rts_port)&&(uart->rts_pin))
        {  
            gpio_bit_write(uart->rts_port, uart->rts_pin, RESET);
        }
    }
#endif
}

static const struct rt_uart_ops gd32_uart_ops =
{
    gd32_configure,
    gd32_control,
    gd32_putc,
    gd32_getc,
#ifdef RT_SERIAL_USING_DMA 
    dma_tx_xfer
#else  
    RT_NULL
#endif
	
};

int gd32_hw_usart_init(void)
{
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    int i;


    for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
    {
        uarts[i].serial->ops    = &gd32_uart_ops;
        uarts[i].serial->config = config;

        /* register UART1 device */
        rt_hw_serial_register(uarts[i].serial,
                              uarts[i].device_name,
#ifdef RT_SERIAL_USING_DMA
                              RT_DEVICE_FLAG_RDWR | uarts[i].dma_flag,
#else
                              RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
#endif
                              (void *)&uarts[i]);
    }

    return 0;
}
INIT_BOARD_EXPORT(gd32_hw_usart_init);
#endif

drv_usart.h



#ifndef __USART_H__
#define __USART_H__

#include <rthw.h>
#include <rtthread.h>

#define UART_ENABLE_IRQ(n)            NVIC_EnableIRQ((n))
#define UART_DISABLE_IRQ(n)           NVIC_DisableIRQ((n))

int gd32_hw_usart_init(void);

#endif

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到