项目是基于32905处理器LCD串口屏,裸机跑C代码。主要是通过串口接收指令,然后按照指令将相应的数据或素材显示到LCD屏上,实现一个串口屏功能。
在串口使用过程中总是偶尔出现数据帧丢失,具体表现:
1、串口进入中断处理函数后,偶尔在中断处理函数中读FSR状态寄存器,u32Count = (inpw(REG_UART_FSR+u32UartPort) & Rx_Pointer) >> 8; 得到FIFO中的可读数据数量为0,为什么可读数据数量为0会进入中断
2、使能超时寄存器UA_TOR, 超时进入中断,偶尔也会出现在 u32Count = (inpw(REG_UART_FSR+u32UartPort) & Rx_Pointer) >> 8; 得到FIFO中的可读数据数量为0。
串口初始化:
static char pi8UartBuf[MAX_RECV_NUM]; //串口数据接收缓存buffer
static VOID uart0_init(VOID)
{
WB_UART_T uart;
UINT32 u32ExtFreq;
memset(pi8UartBuf, 0, MAX_RECV_NUM);
u32ExtFreq = sysGetExternalClock();
sysUartPort0(0);
uart.uiFreq = u32ExtFreq*1000;
uart.uiBaudrate = 115200;
uart.uiDataBits = WB_DATA_BITS_8;
uart.uiStopBits = WB_STOP_BITS_1;
uart.uiParity = WB_PARITY_NONE;
uart.uiRxTriggerLevel = LEVEL_8_BYTES;
sysInitializeUART0(&uart);
sysUart0EnableInt(UART_INT_NONE);
sysUart0Installcallback(0, uartdatavalid_handler);
sysUart0Installcallback(1, uartdatatimeout_handler);
sysUart0EnableInt(UART_INT_RDA);
sysUart0EnableInt(UART_INT_RDTO);
sysSetLocalInterrupt(ENABLE_IRQ);
sysSetLocalInterrupt(ENABLE_FIQ); //使能快中断
//注:将串口0中断优先级设置为快中断,必须比定时器中断优先级高,\
// 否则用于刷新显存数据的定时器中断会导致串口数据频繁的丢失
}
串口驱动层代码
static PFN_SYS_UART_CALLBACK (pfnUartIntHandlerTable)[2][2]={0};
INT32 sysInitializeUART0(WB_UART_T *uart)
{
/* Enable UART multi-function pins*/
//outpw(REG_PINFUN, inpw(REG_PINFUN) | 0x80);
//outpw(REG_GPAFUN, inpw(REG_GPAFUN) | 0x00F00000); //Normal UART pin function
static BOOL bIsResetFIFO = FALSE;
/* Check the supplied parity */
if ((uart->uiParity != WB_PARITY_NONE) &&
(uart->uiParity != WB_PARITY_EVEN) &&
(uart->uiParity != WB_PARITY_ODD))
/* The supplied parity is not valid */
return WB_INVALID_PARITY;
/* Check the supplied number of data bits */
else if ((uart->uiDataBits != WB_DATA_BITS_5) &&
(uart->uiDataBits != WB_DATA_BITS_6) &&
(uart->uiDataBits != WB_DATA_BITS_7) &&
(uart->uiDataBits != WB_DATA_BITS_8))
/* The supplied data bits value is not valid */
return WB_INVALID_DATA_BITS;
/* Check the supplied number of stop bits */
else if ((uart->uiStopBits != WB_STOP_BITS_1) &&
(uart->uiStopBits != WB_STOP_BITS_2))
/* The supplied stop bits value is not valid */
return WB_INVALID_STOP_BITS;
/* Verify the baud rate is within acceptable range */
else if (uart->uiBaudrate < 1200)
/* The baud rate is out of range */
return WB_INVALID_BAUD;
/* Reset the TX/RX FIFOs */
if(bIsResetFIFO==FALSE)
{
outpw(REG_UART_FCR+u32UartPort, 0x07);
bIsResetFIFO=TRUE;
}
/* Setup reference clock */
_sys_uUARTClockRate = uart->uiFreq;
/* Setup baud rate */
sysSetBaudRate(uart->uiBaudrate);
/* Set the modem control register. Set DTR, RTS to output to LOW,
and set INT output pin to normal operating mode */
//outpb(UART_MCR, (WB_DTR_Low | WB_RTS_Low | WB_MODEM_En));
/* Setup parity, data bits, and stop bits */
outpw(REG_UART_LCR+u32UartPort,(uart->uiParity | uart->uiDataBits | uart->uiStopBits));
/* Timeout if more than ??? bits xfer time */
outpw(REG_UART_TOR+u32UartPort, 0x80+0x20);
/* Setup Fifo trigger level and enable FIFO */
outpw(REG_UART_FCR+u32UartPort, (uart->uiRxTriggerLevel << 4) | 0x02);
/* Enable HUART interrupt Only (Receive Data Available Interrupt & RX Time out Interrupt) */
/* Timeout if more than ??? bits xfer time */
outpw(REG_UART_TOR+u32UartPort, 0x7F);
// hook UART interrupt service routine
if (u32UartPort)
{//==1 NORMAL UART
_sys_uUartTxHead = _sys_uUartTxTail = NULL;
sysInstallISR(IRQ_LEVEL_1, IRQ_UART, (PVOID)sysUart0ISR);
sysEnableInterrupt(IRQ_UART);
}
else
{//==0 High SPEED
_sys_uUartTxHead = _sys_uUartTxTail = NULL;
sysInstallISR(FIQ_LEVEL_0, IRQ_HUART, (PVOID)sysUart0ISR);
sysEnableInterrupt(IRQ_HUART);
}
_sys_bIsUARTInitial = TRUE;
return Successful;
}
void sysUart0Installcallback(UINT32 u32IntType, PFN_SYS_UART_CALLBACK pfnCallback)
{
if(u32IntType>1)
return;
if(u32IntType == 0)
{
pfnUartIntHandlerTable[i32UsedPort][0] = (PFN_SYS_UART_CALLBACK)(pfnCallback);
}
else if(u32IntType == 1)
{
pfnUartIntHandlerTable[i32UsedPort][1] = (PFN_SYS_UART_CALLBACK)(pfnCallback);
}
}
static void uartdatatimeout_handler(UINT8* buf, UINT32 u32Len)
{
UINT32 len;
if((g_u32Idx + u32Len) > MAX_RECV_NUM)
{
len =MAX_RECV_NUM-g_u32Idx;
memcpy(&(pi8UartBuf[g_u32Idx]), buf, len);
g_u32Idx=0;
memcpy(&(pi8UartBuf[g_u32Idx]), &buf[len], u32Len-len);
g_u32Idx =g_u32Idx+u32Len-len;
}
else
{
memcpy(&(pi8UartBuf[g_u32Idx]), buf, u32Len);
g_u32Idx = g_u32Idx+u32Len;
if(g_u32Idx>=MAX_RECV_NUM)
{
g_u32Idx=0;
}
}
}
串口中断服务
static VOID sysUart0ISR() //中断服务程序
{
UINT32 volatile u32EnableInt,i;
UINT32 volatile u32Count = 0;
u32EnableInt = inpb(REG_UART_ISR + u32UartPort) & inpb(REG_UART_IER + u32UartPort);
if (u32EnableInt & THRE_IF)
{// buffer empty
if (_sys_uUartTxHead == _sys_uUartTxTail)
{
//Disable interrupt if no any request!
outpb((REG_UART_IER+u32UartPort), inp32(REG_UART_IER+u32UartPort) & (~THRE_IEN));
}
else
{
//Transmit data
for (i=0; i<8; i++)
{
#ifdef __HW_SIM__
#else
outpb(REG_UART_THR+u32UartPort, _sys_ucUartTxBuf[_sys_uUartTxHead]);
#endif
_sys_uUartTxHead = sysTxBufReadNextOne();
if (_sys_uUartTxHead == _sys_uUartTxTail) // buffer empty
break;
}
}
}
if(u32EnableInt & RDA_IF)
{
while((inpw(REG_UART_FSR+u32UartPort) & Rx_Pointer))
{
uart_rx[rx_cnt++] = (inpb(REG_UART_RBR+u32UartPort));
}
}
u32EnableInt = inpb(REG_UART_ISR + u32UartPort) & inpb(REG_UART_IER + u32UartPort);
if(u32EnableInt & Tout_IF)//接收状态分析
{
while((inpw(REG_UART_FSR+u32UartPort) & Rx_Pointer) )
{
uart_rx[rx_cnt++] = (inpb(REG_UART_RBR+u32UartPort));
}
}
pfnUartIntHandlerTable[i32UsedPort][0](&(uart_rx[0]), rx_cnt);
rx_cnt=0;
}
经过时间跟踪调试,发现自己掉进粪坑里面了,产生丢帧问题并不是串口驱动引起的,原因是被其他模块定时器中断影响了