高效FIFO串口双机通信在ARM7上的实现
S3C44B0X(时钟频率为60 MHz)的UART单元提供2个独立的异步串行I/O口,每个通信口均可工作于中断或DMA模式。即UART能产生内部中断请求或DMA请求,在CPU和串行I/O口之间传送数据。它支持高达115.2 Kb/s的传输速率,每1个UART通道包含了2个16位的分别用于接收和发送信号的先进先出(FIFO)通道。S3C44B0X UART包括可编程波特率、红外发送/接收、1个开始位、1个或2个停止位、5/6/7/8位数据宽度和奇偶校验。每个UART包含1个波特率发生器、接收器、发送器和控制单元,其构成如图1所示[1]。
1 FIFO概述
1.1 FIFO概念
先入先出FIFO(First In First Out),即先被写入到FIFO的数据将会先被读出。它是一片用来缓存数据的存储单元,可以把需要处理的数据先暂存在这片存储单元中,在数据量达到一定数量时再集中处理,以提高系统性能。FIFO可以集成在芯片中,而当系统需要的缓冲区较大时,也可以用单独的RAM实现。S3C44B0X串口收发器包含了16 B的FIFO和数据移位器,将要传输的数据写进FIFO,然后赋值到发送移位器,最后从发送的引脚移位发送出去,达到利用FIFO缓冲区高效通信的目的。
1.2 FIFO意义
FIFO是数据传输系统中极其重要的一环,特别是在2个处于不同时钟域的系统接口部分,FIFO的合理使用,不但能使接口处数据传输的输入输出速率进行有效的匹配,不使数据发生复写、丢失和读入无效数据的情况,而且还会有效地提高系统中数据的传输效率。使用FIFO进行串口通信,较之传统的串口通信有更高的效率。它将要发送和已经接收的数据集中起来进行操作,避免了频繁的总线操作,减轻了CPU的负担。因此,使得基于FIFO方式的串口通信目前应用十分广泛。
1.3 FIFO中断请求
S3C44B0X的UART有7个状态(Tx/Rx/Error)信号:溢出错误、奇偶错误、帧错误、断点条件、接收FIFO/Buffer数据准备就绪、发送FIFO/Buffer空和发送移位寄存器空,这些状态信号由相应的UART状态寄存器(UTRSTATn/UERSTATn)声明[1]。
当处于接收错误状态时,如果在控制寄存器(UCONn)中接收错误状态中断使能位被置为1,则溢出错误、奇偶校验错误、帧错误及断点错误,每1个作为1种错误状态都可发出错误中断请求。当1个接收错误状态中断请求被发现时,引起中断请求信号会被读UERSTATn所识别。如果控制器中的接收模式被选定为中断模式,则当接收器从接收移位寄存器向接收FIFO传输数据时,会激活接收FIFO的可引起接收中断的"满"状态信号。同样,如果控制器中的发送模式被选定为中断模式,则当发送器从发送FIFO向发送移位寄存器传输数据时,可引起发送中断的发送FIFO"空"状态信号被激活。如表1所示。
2 FIFO串口通信的实现
FIFO重启时,输入和输出的指针都指向FIFO中的第1个存储位置。对FIFO的每次写入操作会使输入指针指向FIFO的下1个存储位置,相应地每次读取操作会使FIFO的输出指针指向FIFO的上1个存储位置。若指针需要从最后1个存储位置移动到第1个存储位置,则FIFO会自动实现这一过程而不需要任何对指针的重启操作。FIFO内部除了包含输入和输出端口之外,通常还有其他状态标志输出,如空状态和满状态。当FIFO已空或者已满时,空状态和满状态标志位就会有相应的输出,即当FIFO已空时不能进行读取操作,当FIFO已满时不能进行写入操作[2]。
2.1 配置特殊寄存器
为了使目标系统能正常工作,必须配置相关的寄存器,如I/O口寄存器、串口控制寄存器和串口源/目的寄存器等。S3C44B0X有2个串口,这里以串口0为例,进行相关寄存器的配置。
/*I/O口配置,定义各相关引脚功能和上拉电阻状态 */
rPCONC |=0xf0000000;
rPUPC |=0xc000;
rPCONE=(rPCONE &0x3ffeb)|0x28;
rPUPE |=0x6;
rPCONF=(rPCONF &0x3ff)+0x124800;
rPUPF |=0x1e0;
/* 定义串口0工作寄存器组 */
rULCON0=0x3; //正常模式,无奇偶校验,1位停止位,8位数据位
rUCON0=0x245; //Rx为边沿触发,Tx为电平触发,禁
//止超时中断,产生接收错误中断,普通传送、
//发送与接收为中断或轮询模式
rUFCON0=(2<<6)|(1<<4)|(6)|1; //FIFO启动需先复位
rUBRdiv0=(mclk/(baud*16)); //mclk为60000000,baud为115200
2.2 FIFO串口发送模块
串口数据发送帧格式是可编程的,它包含1个开始位,5~8个数据位,1个可选的奇偶位和1~2个停止位,这些都可以通过线控制寄存器(UCONn)来设置。发送器也能够产生发送中止条件。中止条件迫使串口输出保持在逻辑0状态,这种状态保持超过1个传输帧的时间长度。通常在1帧传输数据完整地传输完之后,再通过这个全0状态将中止信号发送给对方。中止信号发送之后,传送数据将持续地放入到输出FIFO中。要发送的数据被存放在定义的字符串指针uart0TxStr 中,串口发送模块通过读该字符串中的字符进行数据发送,核心源代码如下:
void __irq Uart0_TxFifoInt(void)
{
/* 判断FIFO发送缓冲区是否为满或字符串结束 */
while( !(rUFSTAT0 & 0x200) && (*uart0TxStr !='\0'))
{
rUTXH0=*uart0TxStr++;
for(i=0;i<700;i++); //延迟,防止FIFO误写
}
rI_ISPC=BIT_UTXD0;
if(*uart0TxStr == '\0')
{
rINTMSK |= BIT_UTXD0;
rI_ISPC=BIT_UTXD0;
}
}
2.3 FIFO串口接收模块
接收的数据帧格式与发送一样都是可编程的。它包括了1个起始位,5~8个数据位,1个可选的奇偶校验位和1~2个停止位,这些都可以通过线控制寄存器(UCONn)来设置。接收器还可以检测到溢出错误、奇偶校验错误、帧错误和中止状况,每种情况下都会将1个错误标志置位。
(1)溢出错误表示新的数据已经覆盖了旧的数据,因为旧的数据没有及时被读入。
(2)奇偶校验错误表示接收器检测到了意料之外的奇偶校验结果。
(3)帧错误表示接收到的数据没有有效的停止位。
(4)中止状况表示RxDn的输入被保持为0状态超过了1个帧传输的时间[3]。
(5)在FIFO模式下接收FIFO不为空,但接收器已经在3个字时间内没有接收到任何数据,就认为发生了接收超时状况。
接收模块将数据从接收移位寄存器中读出后,首先被存储到接收缓存数组keyBuf[ ]中。变量keyBufWrPt和keyBufRdPt指向缓存数组中当前写数据和读数据,当接收模块往缓存数组中写入1个字节后,keyBufWrPt加1;当Uart_IntGetKey从缓存数组中读出1个字节后,keyBufRdPt加1。两变量最大值为KEY_LEN,超过最大值时置零。接收模块的核心代码如下[4]:
/* 接收模块将移位寄存器中的数据读出到接收缓存数组中 */
void __irq Uart0_RxFifoInt(void)
{
rI_ISPC=BIT_URXD0;
if(rUFSTAT0==0)
Uart_Printf("time out\n");
while( (rUFSTAT0&0xf) >0 ) //循环直到FIFO
//发送缓冲区为空
{
keyBuf[keyBufWrPt++]=rURXH0; //读取接收缓冲区数据存入缓存数组
if(keyBufWrPt==KEY_BUFLEN)
keyBufWrPt=0;
}
}
/* 定义1个函数从接收缓存数组中读取数据 */
char Uart_IntGetkey(void)
{
if(keyBufRdPt==KEY_BUFLEN)
keyBufRdPt=0;
while(keyBufWrPt==keyBufRdPt);//等待直到FIFO被触发
return keyBuf[keyBufRdPt++];
}
2.4 FIFO容错模块
除了接收FIFO寄存器之外,UART还具有1个状态FIFO。状态FIFO表示了在FIFO寄存器中,哪一个数据被毫无错误地接收。假设UART的FIFO连续接收到A、B、C、D、E字符,并且在接收B字符时发生了帧错误(即该字符没有停止位),在接收D字符时发生了奇偶校验错。虽然UART错误发生了,但不会产生错误中断,因为含有错误的字符还没有被CPU读取。当字符被读出时错误中断才会发生,而且只有在读出URXHn和UERSTATn寄存器后,FIFO错误状态寄存器才会被清除[5]。容错模块核心代码如下[6]。
void __irq Uart0_RxFifoErrorInt(void)
{
rI_ISPC=BIT_UERR01;
Uart_Printf("UERSTAT0=0x%x\n",rUERSTAT0& 0xf);
while( (rUFSTAT0&0xf) >0 )
{
keyBuf[keyBufWrPt++]=rURXH0;
if(keyBufWrPt==KEY_BUFLEN);
keyBufWrPt=0;
}
}
- 利用Virtex-5 FPGA实现更高的性能(04-29)
- 如何采用FPGA协处理器实现算法加速(04-29)
- Virtex-5 系列概述LX、LXT 和 SXT 平台(07-27)
- 基于SRAM/DRAM的大容量FIFO的设计与实现(02-02)
- 基于DSP-dMAX的嵌入式FIFO数据传输系统设计(04-16)
- 一种使用USB对ADSP_TS101S进行链路口加载的方案(10-18)