您的位置:首页 > 其它

UART的FIFO功能

2015-09-08 18:21 197 查看
经常听到UART的FIFO功能,但是从来没有真正使用过和认真思考过它的作用。正好有客户用到这个功能,在这里做个总结。

FIFO 是“First-In First-Out”的缩写,它是一个具有先入先出特点的缓冲区。串口设计FIFO的目的是为了提高串口的通讯性能。如果没有FIFO或者说缓冲区的长度只有1字节,那么使用接收中断,就意味着每次收到一个字节的数据就要进一次中断,这样频繁进中断会占用CPU资源。另外如果没有及时读走数据,那么下一个字节数据就会覆盖之前的数据,导致数据丢失,这在通讯速率高的场合很有可能出现。

使用FIFO,可以在连续接收若干个数据后才产生一次中断,然后一起进行处理。这样可以提高接收效率,避免频繁进中断,适用于大数据传输。你可能会想到如果FIFO中的数据没有达到指定长度而无法产生中断怎么办,通常MCU会有接收超时中断,即在一定的时间内没有接收到数据会进入中断,可以利用这个中断把不足FIFO长度的数据最后都读取完。



但是使用FIFO接收多字节数据进中断不好的地方是实时性会受到一定的影响,对某些实时性要求高的场合,比如说要求UART收到某个特定字符就立刻停止发送数据这样一个场合,使用FIFO每多个字节进一次中断就不合适了。

所以说使用FIFO好处是1)避免频繁进中断,提高吞吐率 2)避免数据因没有及时处理而丢失。不好的地方是实时性受影响。

此客户要求使用FIFO的原因是他们担心在接收中断处理过程中数据来的太快没有及时处理而丢失。

针对这个问题采取的解决方法是:还是一个字节进一次接收中断,这样可以保证实时性,把FIFO打开,这样可以防止数据被覆盖而丢失,在接收中断处理完接收数据之后去判断缓冲区中是否有数据,如果有的话把数据读走,这样就防止了数据丢失,同时保证了实时性。

对于Kinetis M4 MCU操作也非常简单。

以K60为例,UART0和UART1缓冲区长度为8,其他UART缓冲区长度为1.



只要配置UARTx_PFIFO寄存器即可。



软件上是:

UART_EnableRxFIFO(UART_InitStruct->instance, true);
UART_FlushRxFifo(UART_InitStruct->instance);
UART_FlushTxFifo(UART_InitStruct->instance);


需要注意的是:配置此寄存器 C2[RE] 和C2[TE] 位为0,另外在设置完RXFE位之后,应立刻向UARTx_CFIFO的TXFLUSH和RXFLUSH位写1.

这样配置完之后就打开了接收FIFO功能。在中断处理函数中,最后去判断UARTx_SFIFO 寄存器的RXEMPT位是否为1即可。



while(!((UART_InstanceTable[HW_UART0]->SFIFO  \
& UART_SFIFO_RXEMPT_MASK) >> UART_SFIFO_RXEMPT_SHIFT))
{
ch = (uint8_t)UART_InstanceTable[HW_UART0]->D;
.
.
.
}


前面提到的接收多个字节进一次中断该如何实现呢。

只需要设置一下UARTx_RWFIFO寄存器即可。



UART_SetRxFIFOWatermark(UART_InitStruct->instance, 0x4); // 每4个字节进一次中断


前面还提到超时中断,在Kinetis MCU里是叫做IDLE Line 中断。

只需要设置UARTx_C2的ILIE为1,使能IDLE LINE中断。



另外设置UARTx_C1的ILT位





在中断服务函数中

/*  IDLE interrupt */
if(UART1_S1&UART_S1_IDLE_MASK)// if IDLE Line interrupt occured
{
// clear interrupt flag; To clear IDLE, read UART       status S1 with IDLE set and then read D
UART1_S1 |= UART_S1_IDLE_MASK;
Receive_data=(uint8_t)(UART1_BASE_PTR->D);
printf("\r\nGo to Idle line\r\n");
}


前面一直说的接收过程,对于发送过程也是类似的。不用FIFO,如果使用中断方式发送的话,那么就是一个字节发送完进一次中断,然后发送另外一字节数据。使用FIFO的话,每次中断处理可以多个字节的数据。



注意在中断服务里发送的字节数并没有限制,进发送中断的核心条件是





TXWATER默认值为0. 当FIFO为空时,即所有数据都发送出去时进中断。

假设我想在每次中断服务函数中发送4个字节,程序设置如下:

首先初始化时打开TX的FIFO功能

UART_EnableTxFIFO(UART_InitStruct->instance, true);
UART_FlushRxFifo(UART_InitStruct->instance);
UART_FlushTxFifo(UART_InitStruct->instance);


在中断处理函数中

/* Tx */
if((UART_InstanceTable[HW_UART0]->S1 & UART_S1_TDRE_MASK) && (UART_InstanceTable[HW_UART0]->C2 & UART_C2_TIE_MASK))
{
/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '1';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '2';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '3';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '4';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '5';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '6';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = '7';

/* buffer is used */
while(UART_InstanceTable[HW_UART0]->TCFIFO >= UART_GetTxFIFOSize(HW_UART0));
UART_InstanceTable[HW_UART0]->D = ' ';


.

.

.

}

在网上看到一篇很好的文章,下载链接为:http://download.csdn.net/detail/wangwenxue1989/9089861
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: