前几年用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
设置前必须关闭串口
会自动获取系统当前的时钟,