全志T113-S3裸机串口驱动(串口DMA发送,中断接收)

发布于:2024-07-22 ⋅ 阅读:(301) ⋅ 点赞:(0)

        前几年用V3S串口的时候,想用DMA进行收发,结果发现DMA只能接收32的整数倍数据,如今在T113-S3上面依旧存在这个问题,折腾很久依旧没有解决,最后只能通过DMA进行发送,中断进行接收,好在这个芯片的接收FIFO格外大,哪怕频繁接收也不会过多产生中断,除了串口0,其余的串口有200多个字节的收发FIFO,发送逻辑为发送的数据如果没有超过串口发送FIFO大小则直接通过FIFO发送,如果超过了,则使用DMA,提高效率。

        中断模式需要GIC支持,DMA模式需要DMA支持,寄存器都是自己定义的,但是名称与手册上面一致,大家可以按照手册上面分析,代码几乎与V3S兼容。

/*************************************************************************************************************
 * 文件名:			uart.c
 * 功能:			全志T113 UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2020-08-11
 * 最后修改时间:	2023-10-2
 * 详细:			串口通信底层支持
 *					串口通讯DMA存在问题,如果不开启DMA BMODE则出现重复接收,数据不及时显示,如果开启BMODE则数据会及时显示
 *					但是存在超过8字节后有4字节接收为0,后面会出现4字节正常,4字节异常,交替:123456783456123490
 *				2024-07-06:开启了DMA发送,屏蔽DMA接收
*************************************************************************************************************/
#include "t113_system.h"
#include "uart.h"
#include "typedef.h"
#if UART_TX_DMA_EN	//使用发送
#include "dma.h"
//static DMA_CH_Type sg_UartRxDmaChannel[UART_ChMax] = {DMA_CH_NULL, DMA_CH_NULL, DMA_CH_NULL, DMA_CH_NULL , DMA_CH_NULL , DMA_CH_NULL };		//初始化为无效
//static const DMA_SOURCE_DRQ_TYPE scg_UartDmaRxDRQ[UART_ChMax] = {DMA_SOURCE_UART0_RX, DMA_SOURCE_UART1_RX, DMA_SOURCE_UART2_RX, DMA_SOURCE_UART3_RX , DMA_SOURCE_UART4_RX , DMA_SOURCE_UART5_RX };	//串口 DMA 源类型
static const DMA_DEST_DRQ_TYPE scg_UartDmaTxDRQ[UART_ChMax] = {DMA_DEST_UART0_TX, DMA_DEST_UART1_TX, DMA_DEST_UART2_TX, DMA_DEST_UART3_TX , DMA_DEST_UART4_TX , DMA_DEST_UART5_TX };				//串口 DMA 目标类型
static DMA_LLI_TYPE dma_tx_lln[UART_ChMax];                                                                                         //串口发送DMA链表
//static DMA_LLI_TYPE dma_rx_lln[UART_ChMax];                                                                                         //串口接收DMA链表
#endif //UART_TX_DMA_EN

#include "irq_gic400.h"
static const GIC_IRQ_Typedef scg_UartIrqType[UART_ChMax] = {GIC_IRQ_UART0, GIC_IRQ_UART1, GIC_IRQ_UART2, GIC_IRQ_UART3 , GIC_IRQ_UART4 , GIC_IRQ_UART5 };	//中断编号
void UART0_IRQHandler(void);//串口0接收中断
void UART1_IRQHandler(void);//串口1接收中断
void UART2_IRQHandler(void);//串口2接收中断
void UART3_IRQHandler(void);//串口3接收中断
void UART4_IRQHandler(void);//串口4接收中断
void UART5_IRQHandler(void);//串口5接收中断
static const void *scg_pUartIrqHandle[UART_ChMax] = { (const void*)UART0_IRQHandler, (const void *)UART1_IRQHandler, (const void *)UART2_IRQHandler, (const void *)UART3_IRQHandler
, (const void*)UART4_IRQHandler , (const void*)UART5_IRQHandler };

static const u32 scg_UARTx_Base[UART_ChMax] = {UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE , UART4_BASE , UART5_BASE };		//基址

//相关UART状态结构
typedef struct
{
	bool		isNewDataFlag;	//接收到新数据
	bool		isBuffFull;		//接收Buff满
	bool		isIntRx;		//是否开启中断接收
	u8 			*RxBuff;		//接收Buff指针
	u16			RxBuffSize;		//接收缓冲区大小,一帧数据大小
	u16 		UartRxCnt;		//接收数据计数器
	u8			TempData;		//用于接收溢出后读取数据寄存器,清除读取数据标志
} UartRx_TypeDef;
static UartRx_TypeDef sg_UartRx[UART_ChMax];

/*************************************************************************************************************************
*函数        	:	bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
*功能        	:	串口配置
*参数        	:	ch:串口号;cfg:配置结构体
*返回        	:	TRUE:配置成功; FALSE: 配置失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2020-08-11
*最后修改时间	:	2020-08-11
*说明        	:	调用前请提前停止发送
*************************************************************************************************************************/
bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
{
	u32 temp;
	bool isBusy;
	
	if(ch > UART_ChMax - 1)
		return FALSE;	//端口号超出范围
	
	isBusy = (r_UARTx_USR(scg_UARTx_Base[ch]) & BIT0) ? TRUE : FALSE;	//获取忙状态
	if(isBusy) 											//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT1;		//使能忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) &= ~BIT7;		//清除掉DLAB,此位必须清零才能访问其他寄存器;
	}
	
	//配置寄存器
	temp = 0;
	if(cfg->OddEvenVerify)								//开启了奇偶校验
	{
		temp |= BIT3;	
		if(cfg->OddEvenVerify == UART_EVEN)				//偶校验
		{
			temp |= BIT4;
		}
	}
	//停止位
	if(cfg->StopBitWidth == UART_STOP_2BIT)				//2个停止位
	{
		temp |= BIT2;	
	}

	//数据位数
	temp |= cfg->DataBitWidth & 0x3;
	//配置写入到LCR
	r_UARTx_LCR(scg_UARTx_Base[ch]) = temp;
	
	if(isBusy) 	
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT2;		//更新忙时修改
		while(r_UARTx_HALT(scg_UARTx_Base[ch]) & BIT2);	//等待更新成功
		r_UARTx_HALT(scg_UARTx_Base[ch]) &= ~BIT1;		//清除忙时修改拨通了与LCR配置
	}
	
	return TRUE;
}



/*************************************************************************************************************************
* 函数	:	void UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
* 功能	:	串口波特率设置
* 参数	:	ch:通道选择,baud:波特率,如9600,115200等等
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	2013316
* 最后修改时间 : 2013316
* 说明	: 	USART1~UART5,对应通道UART_CH1-UART_CH5
			设置前必须关闭串口
			会自动获取系统当前的时钟,并进行计算.
*************************************************************************************************************************/
bool UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
{
	u32 SysClk = 0;
	bool isBusy;
	
	SysClk = 24000000;										//获取系统时钟
	SysClk = SysClk / 16 / baud;							//计算波特率分频系数
	
	if(ch > UART_ChMax - 1)
		return FALSE;	//端口号超出范围
    
	isBusy = (r_UARTx_USR(scg_UARTx_Base[ch]) & BIT0) ? TRUE : FALSE;	//获取忙状态
	if(isBusy) 												//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT1;			//使能忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) |= BIT7;			//设置DLAB,才能设置波特率
	}
	
	
	r_UARTx_DLL(scg_UARTx_Base[ch]) = SysClk & 0xFF;		
	r_UARTx_DLH(scg_UARTx_Base[ch]) = (SysClk>>8) & 0xFF;
	
	if(isBusy) 												//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT2;			//更新忙时修改
		while(r_UARTx_HALT(scg_UARTx_Base[ch]) & BIT2);		//等待更新成功
		r_UARTx_HALT(scg_UARTx_Base[ch]) &= ~BIT1;			//清除忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) &= ~BIT7;			//清除掉DLAB,此位必须清零才能访问其他寄存器;
	}
	
	

	return TRUE;
}




/*************************************************************************************************************************
* 函数	:	bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
* 功能	:	串口初始化
* 参数	:	ch:通道选择,0->usart1,Speed:串口速度,isEnableRx:是否使能接收
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 2020-08-17
* 说明	: 	注意:IO口需要外部独立进行初始化
*************************************************************************************************************************/
bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
{
	UART_Config_TypeDef cfg;

	
	if (ch > UART_ChMax - 1)									//判断端口是否超出范围
		return FALSE;

        
	r_UART_BGR_REG |= (1 << ch);								//使能时钟

	r_UART_BGR_REG &= ~(1 << (ch+16));							//复位UART
	nop; nop; nop; nop; nop; nop; nop; nop; nop;
	r_UART_BGR_REG |= (1 << (ch + 16));							//复位完成
	nop; nop; nop; nop;
	
	cfg.DataBitWidth = UART_DATA_8BIT;							//数据宽度8
	cfg.OddEvenVerify = UART_VERIFY_NULL;						//无奇偶校验
	cfg.StopBitWidth = UART_STOP_1BIT;							//1个停止位
	if(UARTx_SetBaudRate(ch, Speed) == FALSE) return FALSE;
	if(UARTx_Config(ch, &cfg) == FALSE) return FALSE;			//设置波特率
	r_UARTx_MCR(scg_UARTx_Base[ch]) = 0;						//关闭SIR模式,关闭流控
	r_UARTx_FCR(scg_UARTx_Base[ch]) = 0x07 | (3 << 6) | (3 << 4);	//开启FIFO,并将FIFO复位,接收FIFO为-2满触发,发送FIFO为1/2满触发
	r_UARTx_IER(scg_UARTx_Base[ch]) = 0;						//关闭所有中断
	sg_UartRx[ch].isIntRx = FALSE;								//没有开启中断接收
	
        //r_UARTx_FCC(scg_UARTx_Base[ch]) = BIT2|BIT1|BIT0;       //使能FIFO 时钟
	
	if(isEnableRx)
	{
#if UART_DMA_EN	//使用DMA接收		
		if(sg_UartRxDmaChannel[ch] == DMA_CH_NULL)			//没有申请过DMA通道-注意:串口的接收DMA通道会一直占用
		{
			sg_UartRxDmaChannel[ch] = DMA_RequestChannel("UART RX");		    //申请一个空闲的通道
		}
		//r_UARTx_FCR(scg_UARTx_Base[ch]) = 0;	//关闭FIFO
		//r_UARTx_FCC(scg_UARTx_Base[ch]) = 0|BIT3;	//关闭FIFO时钟,BIT3必须开启

		r_UARTx_DMA_REQ_EN(scg_UARTx_Base[ch]) =  BIT1 | BIT0;	//使能DMA收发请求
		//r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT6;
        //r_UARTx_DMA_REQ_EN(scg_UARTx_Base[ch]) = BIT2|BIT1|BIT0;
               
		//r_UARTx_RXDMA_CTRL(scg_UARTx_Base[ch]) = (100 << 8) | BIT6 | BIT1 | BIT0;
		//r_UARTx_FCR(scg_UARTx_Base[ch]) &= ~(3 << 6);
		//r_UARTx_FCR(scg_UARTx_Base[ch]) &= ~BIT0;	//关闭FIFO
		//r_UARTx_FCR(scg_UARTx_Base[ch]) |= BIT3;
               // r_UARTx_HSK(scg_UARTx_Base[ch]) = 0Xe5;
#else
		r_UARTx_IER(scg_UARTx_Base[ch]) |= BIT0 | BIT2;							//使能接收数据有效中断
		GIC_SetIrqPriority(scg_UartIrqType[ch], 2);	                    		//GIC设置一个中断的优先级
		GIC_SetIrqEdgeTriggered(scg_UartIrqType[ch], TRUE);              		//GIC设置一个中断为边沿触发
		GIC_RegisterIRQHandler(scg_UartIrqType[ch], (void (*)(void))scg_pUartIrqHandle[ch]);   	//注册中断服务程序
		GIC_IrqEnable(scg_UartIrqType[ch], TRUE);	                    		//GIC中断使能-串口中断使能
		sg_UartRx[ch].isIntRx = TRUE;											//开启了中断接收
#endif //UART_DMA_EN
	}

	
	return TRUE;
}




/*************************************************************************************************************************
* 函数	:	void UARTx_SendByte(UART_CH_Type ch,u8 data)
* 功能	:	UART单字节发送
* 参数	:	ch:通道号,dataL:要发送的数据
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 2020-08-12
* 说明	: 	单字节发送不要使用DMA,浪费
*			2023-10-02:如果FIFO关闭了,则此处就要注意了,不能使用FIFO作为判断是否能写入发送数据
*************************************************************************************************************************/
void UARTx_SendByte(UART_CH_Type ch,u8 data)
{
	u16 FifoSize;

	if(ch > UART_ChMax - 1)									//判断端口是否超出范围
		return;
	
	if (ch == UART_CH0)
	{
		FifoSize = 64;
	}
	else
	{
		FifoSize = 256;
	}
	FifoSize -= 2;

	if (((r_UARTx_FCC(scg_UARTx_Base[ch]) & BIT1) && (r_UARTx_FCR(scg_UARTx_Base[ch]) & BIT0)) == 0) //如果没有使能TX FIFO时钟或FIFO关闭,则通过保持寄存器为空来判断
	{
		while ((r_UARTx_LSR(scg_UARTx_Base[ch]) & BIT5)==0);
	}
	else
	{
		while ((r_UARTx_TFL(scg_UARTx_Base[ch]) & 0x1FF) > FifoSize);	//防止FIFO满了
	}
	
 	r_UARTx_THR(scg_UARTx_Base[ch]) = data;						//发送数据-写到FIFO中而已,并不会等待数据发送完成
}




/*************************************************************************************************************************
* 函数	:	void UARTx_SendData(UART_CH_Type ch,u8 *tx_buff,u16 byte_number)
* 功能	:	UART数据发送函数
* 参数	:	ch:通道号,tx_buff:发送缓冲区,byte_number:需要发送的字节
* 返回	:	无
* 依赖	:	void UART_SendByte(u8 ch,u8 data)
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	非DMA方式,非FIFO方式发送
*************************************************************************************************************************/
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen)
{
	u16 i;
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return;
	
#if UART_TX_DMA_EN //使能DMA发送
	if((ch==UART_CH0 &&  DataLen > 64) || DataLen > 256)	//超过发送缓冲区大小才使用DMA,串口0只有64字节缓冲区,其余为256字节缓冲区
	{
		DMA_CH_Type dma_ch;
		
		dma_tx_lln[ch].cfg = DMA_GetConfig(scg_UartDmaTxDRQ[ch], //目标类型
								DMA_BLOCK_SIZE_1B, 		//目标突发传输长度配置
								DMA_SIZE_8BIT, 			//目标数据宽度
								FALSE,					//目标地址自增模式
								isSdram_MemAddr(pTxBuff)? DMA_SOURCE_SDRAM : DMA_SOURCE_SRAM, 		//源类型
								DMA_BLOCK_SIZE_1B, 		//源突发传输长度配置
								DMA_SIZE_8BIT, 			//源数据宽度
								TRUE);					//源地址自增模式
		dma_tx_lln[ch].src = (u32)pTxBuff;								//DMA源地址
		dma_tx_lln[ch].dst = (u32)&r_UARTx_THR(scg_UARTx_Base[ch]);	    //DMA目标地址
		dma_tx_lln[ch].len = DataLen;								    //传输长度
        dma_tx_lln[ch].reserved[0] = 0;
        dma_tx_lln[ch].reserved[1] = 0;

		//DMA参数寄存器值生成
		dma_tx_lln[ch].para = 1;										//传输等待时钟周期数,猜测用于防止连续占用总线,就是传输以包后停几个周期
		dma_tx_lln[ch].next_lli = DMA_LINK_END;					        //指向下一个链表,最后一个指向0xFFFFF800
		//申请DMA通道
		dma_ch = DMA_RequestChannel("UARTx_SendData");		            //申请一个空闲的通道
		if(dma_ch != DMA_CH_NULL)							            //申请到空闲的通道了
		{
			DMA_ChannelStart(dma_ch, &dma_tx_lln[ch], 10);
			if(DMA_ChannelWaitComplete(dma_ch, DataLen*10) == TRUE)	    //等待DMA传输完成
			{
				
			}
			else
			{
				
			}
			DMA_FreedChannel(dma_ch);						            //释放DMA通道
		}
		else
		{
			for(i = 0;i < DataLen;i++)				//循环发送,直至发送完毕
			{
				UARTx_SendByte(ch, pTxBuff[i]);
			}
		}
	}
	else
	{
		for (i = 0; i < DataLen; i++)				//循环发送,直至发送完毕
		{
			UARTx_SendByte(ch, pTxBuff[i]);
		}
	}
	
#else	
	for(i = 0;i < DataLen;i++)				//循环发送,直至发送完毕
	{
	 	UARTx_SendByte(ch, pTxBuff[i]);
	}
#if (!UART_TX_TO_FIFI)	//要求等待数据发送完成
	UARTx_WaitSendComplete(ch);				//等待数据发送完成-从串口发送完成
#endif //UART_TX_TO_FIFI	
#endif //UART_DMA_EN
}


/*************************************************************************************************************************
* 函数			:	void UARTx_WaitSendComplete(UART_CH_Type ch)
* 功能			:	等待数据发送完成-从串口发送完成
* 参数			:	ch:通道号
* 返回			:	无
* 依赖			:	void UART_SendByte(u8 ch,u8 data)
* 作者			:	cp1300@139.com
* 时间			:	2020-08-19
* 最后修改时间 	: 	2020-08-19
* 说明			:
*************************************************************************************************************************/
void UARTx_WaitSendComplete(UART_CH_Type ch)
{
	while((r_UARTx_LSR(scg_UARTx_Base[ch]) & BIT6) == 0);	//等待发送移位寄存器为空
}


/*************************************************************************************************************************
* 函数	:	void UARTx_SendString(UART_CH_Type ch,char *pString)
* 功能	:	UART发送字符串
* 参数	:	ch:通道号
			pString:字符串指针
* 返回	:	无
* 依赖	:	void UART_SendByte(u8 ch,u8 data)
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	
*************************************************************************************************************************/
#include "string.h"
void UARTx_SendString(UART_CH_Type ch,char *pString)
{	
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return;
	
	UARTx_SendData(ch, (u8 *)pString, strlen(pString));
}






/*************************************************************************************************************************
* 函数	:	bool UARTx_GetNewDataFlag(UART_CH_Type ch)
* 功能	:	获取串口新数据标志
* 参数	:	ch:通道选择
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于判断是否有新的数据,会清除掉新数据标志的
*************************************************************************************************************************/
bool UARTx_GetNewDataFlag(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)										//判断端口是否超出范围
		return FALSE;

	if(sg_UartRx[ch].isIntRx == TRUE)							//开启了中断接收
	{
		if(sg_UartRx[ch].isNewDataFlag == TRUE) 				//有新数据
		{
		 	sg_UartRx[ch].isNewDataFlag = FALSE;				//清除标志
			return TRUE;										//返回有新数据
		}
	}
	else														//没开启中断接收
	{
	 	if(r_UARTx_LSR(scg_UARTx_Base[ch]) & BIT0)				//接收数据就绪,但是需要读取RBR才能清楚
		{
			return TRUE;
		}
	}
	return FALSE;
}


/*************************************************************************************************************************
* 函数	:	bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
* 功能	:	获取串口接收缓冲区满标志
* 参数	:	ch:通道选择
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于判断接收缓冲区是否满,会清除标志
*************************************************************************************************************************/
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)					//判断端口是否超出范围
		return FALSE;
	
#if UART_DMA_EN

#else 
	if(sg_UartRx[ch].isBuffFull == TRUE)			//缓冲区已满
	{
	 	sg_UartRx[ch].isBuffFull = FALSE;			//清除满标志
		return TRUE;
	}
	return FALSE;
#endif //UART_DMA_EN
}




/*************************************************************************************************************************
* 函数	:	u8 UARTx_GetNewData(UART_CH_Type ch)
* 功能	:	获取串口新数据
* 参数	:	ch:通道选择
* 返回	:	收到的数据
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于接收一个字节数据
*************************************************************************************************************************/
u8 UARTx_GetNewData(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)								//判断端口是否超出范围
		return 0;

	return r_UARTx_RBR(scg_UARTx_Base[ch]);				//返回数据
}




#if UART_DMA_EN
/*************************************************************************************************************************
* 函数			:	void UARTx_SetRxDMA(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
* 功能			:	串口接收DMA配置
* 参数			:	ch:通道选择,RxBuffSize:缓冲区大小,RxBuff:缓冲区指针
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2023-10-01
* 最后修改时间 	: 	2023-10-01
* 说明			: 	
*************************************************************************************************************************/
void UARTx_SetRxDMA(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
{
	
	DMA_CH_Type dma_ch;
	
	dma_rx_lln[ch].cfg = DMA_GetConfig(isSdram_MemAddr(RxBuff)? DMA_DEST_SDRAM : DMA_DEST_SRAM, 	//目标类型
							DMA_BLOCK_SIZE_1B, 		//目标突发传输长度配置
							DMA_SIZE_8BIT, 			//目标数据宽度
							TRUE,					//目标地址自增模式
							scg_UartDmaRxDRQ[ch], 	//源类型
							DMA_BLOCK_SIZE_1B, 		//源突发传输长度配置
							DMA_SIZE_8BIT, 			//源数据宽度
							FALSE) | BIT30;					//源地址自增模式
    //uart_printf("cfg:0x%X\r\n", dma_lli.cfg);
	dma_rx_lln[ch].src = (u32)&(r_UARTx_RBR(scg_UARTx_Base[ch]));//DMA源地址
    //uart_printf("src:0x%X\r\n", dma_lli.src);
	dma_rx_lln[ch].dst = (u32)RxBuff;							//DMA目标地址
    //uart_printf("dst:0x%X\r\n", dma_lli.dst);
	dma_rx_lln[ch].len = RxBuffSize;							//传输长度-buff大小
	//DMA参数寄存器值生成
	dma_rx_lln[ch].para = 0X5;									//延时检查DMA触发信号周期
	dma_rx_lln[ch].next_lli = DMA_LINK_END;					    //指向下一个链表,最后一个指向0xFFFFF800
	
	//申请DMA通道
	dma_ch = sg_UartRxDmaChannel[ch];					//提前已经申请了一个空闲的通道,这个通道会一直给串口接收使用
	if(dma_ch != DMA_CH_NULL)							//申请到空闲的通道了
	{
		DMA_ChannelStart(dma_ch, &dma_rx_lln[ch], 0);
	}
	else
	{
		
	}
}

#endif //UART_DMA_EN



/*************************************************************************************************************************
* 函数	:	void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
* 功能	:	设置串口接收缓冲区
* 参数	:	ch:通道选择,RxBuffSize:缓冲区大小,RxBuff:缓冲区指针
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	一定要设置,否则开启中断接收时可能会异常
*************************************************************************************************************************/
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
{
#ifdef _UCOS_II_
	OS_CRITICAL_SR_VAL;
#endif	//_UCOS_II_
	
	if(ch > UART_ChMax - 1)							//判断端口是否超出范围
		return;
	
#if UART_DMA_EN
	UARTx_SetRxDMA(ch, RxBuff, RxBuffSize);			//DMA配置
#endif //UART_DMA_EN
	
#ifdef _UCOS_II_
	OS_EnterCriticalSection();                         //进入临界区
#endif	//_UCOS_II_
	sg_UartRx[ch].RxBuffSize = RxBuffSize; 			//设置缓冲区大小
	sg_UartRx[ch].RxBuff = RxBuff;					//设置缓冲区指针
#if !UART_DMA_EN		
	sg_UartRx[ch].UartRxCnt = 0;					//计数器清零
#endif //!UART_DMA_EN
#ifdef _UCOS_II_
	OS_LeaveCriticalSection();                         //退出临界区
#endif	//_UCOS_II_
}





/*************************************************************************************************************************
* 函数	:	u32 UARTx_GetRxCnt(UART_CH_Type ch)
* 功能	:	获取串口接收数据计数器
* 参数	:	ch:通道选择
* 返回	:	接收到的数据数量
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20130307
* 最后修改时间 : 20130307
* 说明	: 	无
*************************************************************************************************************************/
u32 UARTx_GetRxCnt(UART_CH_Type ch)
{	
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return 0;
	
#if UART_DMA_EN
	return  sg_UartRx[ch].RxBuffSize - DMA_ChannelGetCount(sg_UartRxDmaChannel[ch]);
#else
	return sg_UartRx[ch].UartRxCnt;			//返回计数值	
#endif //UART_DMA_EN	
}




/*************************************************************************************************************************
* 函数	:	void UARTx_ClearRxCnt(UART_CH_Type ch)
* 功能	:	清除串口接收数据计数器
* 参数	:	ch:通道选择
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20130307
* 最后修改时间 : 20130307
* 说明	: 	无
*************************************************************************************************************************/
void UARTx_ClearRxCnt(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)					//判断端口是否超出范围
		return;
#if UART_DMA_EN
	UARTx_SetRxDMA(ch, sg_UartRx[ch].RxBuff, sg_UartRx[ch].RxBuffSize);			//DMA配置
#else
	sg_UartRx[ch].UartRxCnt = 0;				//计数器清零
#endif //UART_DMA_EN
}























#if !UART_DMA_EN	//使用的中断

//用于串口中断中循环读取数据
#if __ICCARM__
#pragma inline 
static void UARTx_ReadRxData(UART_CH_Type ch)
#else
__inline static void UARTx_ReadRxData(UART_CH_Type ch)
#endif //__ICCARM__
{
    while(r_UARTx_RFL(scg_UARTx_Base[ch]))   //接收FIFO中有数据,循环读取
    {
        if((sg_UartRx[ch].RxBuffSize) > 0 && (sg_UartRx[ch].UartRxCnt < sg_UartRx[ch].RxBuffSize))			//接收缓冲区大于0,并且没有满
        {
            (sg_UartRx[ch].RxBuff)[(sg_UartRx[ch].UartRxCnt) ++] = r_UARTx_RBR(scg_UARTx_Base[ch]); 		//将数据存放到缓冲区
            if(sg_UartRx[ch].UartRxCnt == sg_UartRx[ch].RxBuffSize) 										//缓冲区已满
            {
                 //sg_UartRx[ch].UartRxCnt = 0;																//接收计数器清零
                  sg_UartRx[ch].isBuffFull = TRUE;															//缓冲区已满标志
            }	
        }
        else //缓冲区满了,清除接收到的数据
        {
            sg_UartRx[ch].TempData = r_UARTx_RBR(scg_UARTx_Base[ch]);
        }
    }
}



//串口中断处理
#if __ICCARM__
#pragma inline 
static void UARTx_IRQHandler(UART_CH_Type ch)
#else
__inline static void UARTx_IRQHandler(UART_CH_Type ch)
#endif //__ICCARM__
{
	//uart_printf("CH%d 0x%X\r\n", ch, (r_UARTx_IIR(scg_UARTx_Base[ch]) & 0x0F));
	switch(r_UARTx_IIR(scg_UARTx_Base[ch]) & 0x0F)
	{
		case 0x06:	//接收线状态; 溢出/奇偶校验/成帧错误或中断中断,优先级1
		{
			while(r_UARTx_RFL(scg_UARTx_Base[ch]))                      //接收FIFO中有数据,循环读取
            {
                sg_UartRx[ch].TempData = r_UARTx_RBR(scg_UARTx_Base[ch]);
            }
		}break;
		case 0x04:	//收到可用的数据; 可用的接收器数据(禁用非FIFO模式或FIFO)或达到RCVR FIFO触发级别(启用FIFO模式和FIFO),优先级2
		{
			UARTx_ReadRxData(ch);
		}break;
		case 0x0C:	//接收字符超时;在FIFO模式下最近的4个字符时间内,没有字符进出RCVR FIFO,并且在此期间至少有1个字符,优先级2
		{
			//收到的数据没有满足FIFO阈值
            UARTx_ReadRxData(ch);
		}break;
		case 0x02:	//发送器为空,优先级3
		{
			//没有开启发送中断
		}break;
		case 0x00:	//调制解调器状态,优先级4
		{
			//没有使用到
		}break;
		case 0x07:	//忙检测,优先级5
		{
			//没用到
		}break;
		default:break;
	}
	r_UARTx_LSR(scg_UARTx_Base[ch]) |= r_UARTx_LSR(scg_UARTx_Base[ch]);	//清除中断
}

//串口0接收中断
void UART0_IRQHandler(void) { UARTx_IRQHandler(UART_CH0); }
//串口1接收中断
void UART1_IRQHandler(void) {UARTx_IRQHandler(UART_CH1);}
//串口2接收中断
void UART2_IRQHandler(void) {UARTx_IRQHandler(UART_CH2);}
//串口3接收中断
void UART3_IRQHandler(void) {UARTx_IRQHandler(UART_CH3);}
//串口4接收中断
void UART4_IRQHandler(void) { UARTx_IRQHandler(UART_CH4); }
//串口5接收中断
void UART5_IRQHandler(void) { UARTx_IRQHandler(UART_CH5); }

#endif //UART_DMA_EN
/*************************************************************************************************************
 * 文件名:			uart.h
 * 功能:			全志v3s UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2020-08-11
 * 最后修改时间:	2020-08-11
 * 详细:			串口通信底层支持
*************************************************************************************************************/
#ifndef _UART_H_  
#define _UART_H_
#include "t113_system.h"

/***********************配置相关************************/
#define UART_TX_DMA_EN		1			//1:使能DAM发送,DMA接收有问题,必须是32整数倍,目前没有解决,直接使用中断接收
#define UART_TX_TO_FIFI		1			//1:数据发送到发送FIFO则认为发送完成; 0:数据从移位寄存器发送完成则认为发送完成
#define UART_ChMax			6			//串口通道数量


/*********************************************************/



//串口选择,串口1开始,到串口3
typedef enum
{
	UART_CH0	=		0,	//UART0
	UART_CH1	=		1,	//UART1
	UART_CH2	=		2,	//UART2
	UART_CH3	=		3,	//UART3
	UART_CH4	=		4,	//UART4
	UART_CH5	=		5,	//UART5
}UART_CH_Type;


//UART配置相关结构定义
typedef struct
{
	u8 OddEvenVerify;	//奇偶校验,奇,偶,无
	u8 StopBitWidth;	//停止位位宽1,2
	u8 DataBitWidth;	//数据位宽度
} UART_Config_TypeDef;


//奇偶校验
#define UART_VERIFY_NULL	0	//无校验
#define UART_ODD			1	//奇校验
#define UART_EVEN			2	//偶校验
//停止位
#define UART_STOP_1BIT		0	//一个停止位
#define UART_STOP_2BIT		1	//2个停止位
//数据位数
#define UART_DATA_5BIT		0	//5位数据长度
#define UART_DATA_6BIT		1	//6位数据长度
#define UART_DATA_7BIT		2	//7位数据长度
#define UART_DATA_8BIT		3	//8位数据长度

//相关API
bool UARTx_Init(UART_CH_Type ch,u32 Speed, bool isEnableRx);		//串口初始化
void UARTx_SendByte(UART_CH_Type ch,u8 data);						//UART单字节发送
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen);		//UART数据发送函数
void UARTx_WaitSendComplete(UART_CH_Type ch);						//等待数据发送完成-从串口发送完成
void UARTx_SendString(UART_CH_Type ch,char *pString);				//UART发送字符串
bool UARTx_GetNewDataFlag(UART_CH_Type ch);							//获取串口新数据标志
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch);						//获取串口接收缓冲区满标志
u8 	 UARTx_GetNewData(UART_CH_Type ch);								//获取串口新数据
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize);	//设置串口接收缓冲区
//void UARTx_ClearRxInt(UART_CH_Type ch);								//清除串口接收中断标志
u32  UARTx_GetRxCnt(UART_CH_Type ch);								//获取串口接收数据计数器
void UARTx_ClearRxCnt(UART_CH_Type ch);								//清除串口接收数据计数器

#endif //_UART_H_