打印
[ZLG-MCU]

关于Stellaris系列UART的FIFO新认识,经典!

[复制链接]
9934|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zlgmcu|  楼主 | 2008-9-25 10:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

【经典提问】
  有没有办法去掉UART的FIFO,或者怎样才能实现每收发一个字符就中断一次呢?Stellaris系列ARM的UART好像无法做到这一点,存在缺陷!


【精妙解答】
  误解了,根本就不是缺陷,这恰恰是优点!

  看来许多人还没有真正理解FIFO的作用和优点,仍然停留在每收发一个字符就要中断处理一次的老思路上。UART收发FIFO主要是为了解决收发中断过于频繁而导致的CPU效率不高的问题。

  FIFO的必要性。在进行UART通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发FIFO,则每传输一个数据(5~8位)都要中断处理一次,效率仍然不高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率。

  接收超时问题。如果没有接收超时功能,则在对方已经发送完毕而接收FIFO未填满时并不会触发中断(FIFO满才会触发中断),结果造成最后接收的有效数据得不到处理的问题。有了接收超时功能后,如果接收FIFO未填满而对方发送已经停,则在不超过3个数据的接收时间内就会触发超时中断,因此数据会照常得到处理。

  总之,FIFO的设计是优秀而合理的,它已经帮你想到了收发过程中存在的任何问题,只要初始化配置UART后,就可以放心收发了,FIFO和中断例程会自动搞定一切!

  完全不必要担心FIFO大大减少了中断产生的次数而“可能”造成数据丢失的问题!

  发送时,只要发送FIFO不满,数据只管往里连续放,放完后就直接退出发送子程序。随后,FIFO真正发送完成后会自动产生中断,通知主程序说:我已经完成真正的发送。

  接收时,如果对方是连续不间断发送,则填满FIFO后会以中断的方式通知主程序说:现在有一批数据来了,请处理。

  如果对方是间断性发送,也不要紧,当间隔时间过长时(2~3个字符传输时间),也会产生中断,这次是超时中断,通知主程序说:对方可能已经发送完毕,但FIFO未满,也请处理。

  不知大家是否已经明白其中的自动机制?


【相关库函数】
1. UARTConfigSet()
  配置UART,例如:
    //  配置UART2:波特率9600,数据位8,停止位1,无校验
    UARTConfigSet(UART2_BASE, 9600, UART_CONFIG_WLEN_8 |
                                    UART_CONFIG_STOP_ONE |
                                    UART_CONFIG_PAR_NONE);

2. UARTFIFOLevelSet()
  设置UART收发FIFO的深度,可以设置的深度有2、4、8、12、14

3. UARTSpaceAvail()
  确认在发送FIFO里是否有可利用的空间。

4. UARTCharsAvail()
  确认在接收FIFO里是否存在字符。

5. UARTCharPutNonBlocking()
  该函数要与UARTSpaceAvail()配合使用,如果已确认发送FIFO里有可用空间,则将字符直接放入发送FIFO,不等待。

6. UARTCharGetNonBlocking()
  该函数要与UARTCharsAvail()配合使用,如果已确认接收FIFO里有字符,则直接从接收FIFO里读取字符,不等待。

7. UARTCharPut()
  将字符放到发送FIFO里,如果没有可用空间则一直等待。

8. UARTCharGet()
  从接收FIFO里读取字符,如果没有字符则一直等待。

9. UARTIntEnable()
  使能一个或多个UART中断,例如:
    //  同时使能接收中断(接收FIFO溢出)和接收超时中断
    UARTIntEnable(UART2_BASE, UART_INT_RX | UART_INT_RT);


(zlgmcu_wdx)

相关帖子

沙发
puppyh| | 2008-9-25 11:21 | 只看该作者

误导工程师

如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率????

如果一次通讯的数据只有1个,而且间隔时间很长。收到一个数据后就产生中断程序能够正常运行;如果使用FIFO,收到一个字节后,不产生中断,系统不知道已经接收到数据,搞个超时中断,就没有实时性了,那程序运行就有问题。

所以,使用时要根据实际情况,开启FIFO或关闭FIFO,才是正道!

使用特权

评论回复
板凳
id001| | 2008-9-25 12:19 | 只看该作者

FIFO功能还是相比AVR,51的强大了许多多~~~~~~~

使用特权

评论回复
地板
teddeng| | 2008-9-25 14:13 | 只看该作者

lm的FIFO可以配置成1字节BUF啊?

lm3s9616 datasheet page 288:
Programmable FIFO length, including 1-byte deep operation providing conventionaldouble-buffered interface

另外ZLG的9616中文翻译关于UART有个错误:
中文版 PAGE292:
在UARTLCRH的位1、位2和位7置位时,发送奇偶校验位,且检测结果
为0。在位1和位7都置位且位2清零时,发送奇偶校验位,且检测结果为
1。
英文版PAGE 305
When bits 1, 2, and 7 of UARTLCRH are set, the parity bit is transmitted and checked as a 0. When bits 1 and 7 are set and 2 is cleared, the parity bit is transmitted and checked as a 1.

这里意思是当bit7置1时,根据bit2强制发送效验位为1或0。
也就是通用串口常用奇偶效验位配置中的 MARK、 SPACE方式。

使用特权

评论回复
5
seeokok| | 2008-9-25 18:43 | 只看该作者

FIFO可以关掉

Stellaris系列资料不是很详细,用起很费劲。这几天恰巧也在研究UART,说一下我的心得:
    1。FIFO可以关掉
    FIFO有FIFO的用处,但也有必须关掉FIFO用处。别关不掉FIFO就强词夺理非说有FIFO比没FIFO好。就像一有人问LM Link下载有Unable to open device错怎么解决,就非让人重装,还非要装C盘一样。(呵呵..满腹牢骚,是因为对zlg现在的技术支持实在是不敢恭维)。
    像我们的设备,UART0用于和电脑连接,进行监测和调试,用FIFO就很不错。但UART1和UART2需要和别的设备进行通讯,而在通讯协议中必须检测两个字符之间的间隔,这时就不能开FIFO。所以,一个设计得好的CPU应该既能开FIFO也能关掉。
    Datasheet上也说,复位完成后,两个FIFO都被禁能,提供传统双缓冲接口的1字节深的操作,那为什么很多人感觉FIFO关不掉呢?其实的原因很简单:在初始化UART时的一些功能调用打开了FIFO,最主要的是UARTEnable,而ConfigSetExpClk在完成了速率等配制后,又调用了UARTEnable。所以要关掉FIFO很简单,只要在初始化UART的最后加一句:
  HWREG(UART1_BASE + UART_O_LCRH) &= ~(UART_LCRH_FEN);

下班了回家吃饭了,其他以后有时间再说。

使用特权

评论回复
6
ATmega32L| | 2008-9-25 23:54 | 只看该作者

竟然没有FIFO空中断

竟然没有FIFO空中断,
LM串口中看不中用。

使用特权

评论回复
7
seeokok| | 2008-9-26 12:40 | 只看该作者

FIFO的空中断倒是用不着。

关掉FIFO,发中断就相当于空中断了。
如果使用FIFO,在快要发完的时候产生中断,赶紧往FIFO里头填不是更好吗?

使用特权

评论回复
8
wlq_9| | 2008-9-26 13:15 | 只看该作者

就是用的16c550的硬件ip嘛.都差不多的,谈不上什么特点.
fifo有用处,stm32的dma也有自己的用处.串口又不是什么十分高速的设备,随便整整.

使用特权

评论回复
9
zlgmcu|  楼主 | 2008-9-28 08:46 | 只看该作者

Luminary在设计时借鉴了16C550的思路,但并不兼容

使用特权

评论回复
10
talent8791| | 2008-10-11 16:04 | 只看该作者

使用特权

评论回复
11
ather2180| | 2008-10-14 22:02 | 只看该作者

这个URAT确实要和实际应用结合才知道

我也遇到这个情况,曾经有一次发数据,在串口调试工具里看到所有的码都发送了,但接受方就是不动作,百思不得其解。后来用逻辑分析仪一看,发现发出的码在最后有一个延时。这就是FIFO设置不当造成的,最后填入的字符是由串口的超时中断发出的,晚了一点。这种情况应该不常见,但在现实中确实也存在,特别是接受方在程序逻辑上设定了接收超时的时候。所以能不能用FIFO只能根据实际情况来决定了。

使用特权

评论回复
12
hyhmh| | 2008-10-20 10:22 | 只看该作者

FIFO是很好用的!

当然,有时也会有点小麻烦。
当ARMx(有FIFO)与MCU(无FIFO)进行UART通信时,如果MCU的UART接收软件写得不好,ARMx发送字节间隔时间短,存在MCU接收不完整的可能。

声明只是可能而已。

使用特权

评论回复
13
zlgmcu|  楼主 | 2008-10-25 09:06 | 只看该作者

FIFO不需要禁止

新版《Stellaris外设驱动库》新增一个函数UARTBusy(),可以探测发送FIFO是否为空,因此完全不必要禁止FIFO。

使用特权

评论回复
14
汽车电子| | 2008-10-31 14:28 | 只看该作者

我的FIFO永远都是开启的

   还嫌它太短了呢,怎么不搞个128字节呀什么的,那就爽了
   如果支持DMA,更爽了...

使用特权

评论回复
15
zlgmcu|  楼主 | 2008-10-31 17:45 | 只看该作者

2008年新出的DustDevil系列(LM3S3000/5000等)已支持DMA!

使用特权

评论回复
16
AIRWILL| | 2008-11-7 17:58 | 只看该作者

我也禁止 FIFO

因为我的通信协议要求检测到数据错误, 要重发这个数据

使用特权

评论回复
17
zlgmcu|  楼主 | 2008-11-8 10:13 | 只看该作者

使能错误处理中断即可,出错后整包重发

在一个典型应用当中,数据往往是按包发送的(包的长度自己定义,一般几B至几百B),如果出错,整包重发。

使用特权

评论回复
18
chunk| | 2008-11-20 14:28 | 只看该作者

这不过是个基础知识,怎么

成了经典理解了?

CPU有一些智能,应该努力让它做一些智慧化的工作,而不是体力活儿。那什么是体力活儿?

memcpy,怎么样?典型的体力活儿对吗?这里需要什么智慧?同样的,把数据在内存与外设之间搬来挪去也是体力活儿,这些都应该用专门的电路去做,于是怎么样?DMA就有了吧?

DMA有点复杂,要考虑成本问题不好弄。CPU呢?能力有点富裕,搬数据这事还得让CPU干,能者多劳嘛。可又不能总为搬数据麻烦CPU。于是呢?FIFO是个好东西。对吧?

那还有什么活儿是体力活儿?
void delay(int time)
{
  while(time--);
}
没错吧?这个函数除了费电之外有其它什么智商吗?没有。于是就有了“操作系统”,你想等一会儿啊?行,把CPU交给我分给其它任务。CPU就是出租车,任务是司机,操作系统就是出租车公司:“人权要求我不能压榨司机,你们俩司机白天晚上两班倒,歇人不歇车,我压榨那车行不?”

然而有时候这些精妙的想法并不总适用,比如16楼,他不分组交换,而是字符交换,虽然理论上应该充分利用硬件的特性做成分组交换,人家的协议是沿袭下来的,范不着改。CPU又是个ARM,能力大大的富裕。

delay是费电,可我就想等1uS,您操作系统还没切换完任务呢5uS都过去了,算了不劳您大驾我自助吧。

使用特权

评论回复
19
wftyy| | 2008-11-20 22:22 | 只看该作者

LM3S的串口发送FIFO不好用

必须添满,才能有发送中断。比较失败呀。

如果发送到最后几个字节,不够发送FIFO的长度,怎么能够知道发送完成了呢??
比如,用RS485,发送完是要及时设置为接收状态的。

使用特权

评论回复
20
zlgmcu|  楼主 | 2008-11-21 08:48 | 只看该作者

19楼还是有误解,LM3S的UART是完善的

“必须添满,才能有发送中断”——并非这样,不填满也能产生中断。
“怎么能够知道发送完成了呢”——库函数UARTBusy()可以探知。

19楼的担心完全没有必要。详见这里的UART**和例程,有非常详细的讲解:
【Luminary开发工具及开发指南】
http://www.zlgmcu.com/luminary/exploitation_guide.asp

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

81

主题

1146

帖子

0

粉丝