[ZLG-MCU] 关于Stellaris系列UART的FIFO新认识,经典!

[复制链接]
11712|25
 楼主| zlgmcu 发表于 2008-9-25 10:52 | 显示全部楼层 |阅读模式
<big><br />【经典提问】<br />  有没有办法去掉UART的FIFO,或者怎样才能实现每收发一个字符就中断一次呢?Stellaris系列ARM的UART好像无法做到这一点,存在缺陷!<br /><br /><br />【精妙解答】<br />  误解了,根本就不是缺陷,这恰恰是优点!<br /><br />  看来许多人还没有真正理解FIFO的作用和优点,仍然停留在每收发一个字符就要中断处理一次的老思路上。UART收发FIFO主要是为了解决收发中断过于频繁而导致的CPU效率不高的问题。<br /><br />  FIFO的必要性。在进行UART通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发FIFO,则每传输一个数据(5~8位)都要中断处理一次,效率仍然不高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率。<br /><br />  接收超时问题。如果没有接收超时功能,则在对方已经发送完毕而接收FIFO未填满时并不会触发中断(FIFO满才会触发中断),结果造成最后接收的有效数据得不到处理的问题。有了接收超时功能后,如果接收FIFO未填满而对方发送已经停,则在不超过3个数据的接收时间内就会触发超时中断,因此数据会照常得到处理。<br /><br />  总之,FIFO的设计是优秀而合理的,它已经帮你想到了收发过程中存在的任何问题,只要初始化配置UART后,就可以放心收发了,FIFO和中断例程会自动搞定一切!<br /><br />  完全不必要担心FIFO大大减少了中断产生的次数而“可能”造成数据丢失的问题!<br /><br />  发送时,只要发送FIFO不满,数据只管往里连续放,放完后就直接退出发送子程序。随后,FIFO真正发送完成后会自动产生中断,通知主程序说:我已经完成真正的发送。<br /><br />  接收时,如果对方是连续不间断发送,则填满FIFO后会以中断的方式通知主程序说:现在有一批数据来了,请处理。<br /><br />  如果对方是间断性发送,也不要紧,当间隔时间过长时(2~3个字符传输时间),也会产生中断,这次是超时中断,通知主程序说:对方可能已经发送完毕,但FIFO未满,也请处理。<br /><br />  不知大家是否已经明白其中的自动机制?<br /><br /><br />【相关库函数】<br />1.&nbsp;UARTConfigSet()<br />  配置UART,例如:<br />&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;配置UART2:波特率9600,数据位8,停止位1,无校验<br />&nbsp;&nbsp;&nbsp;&nbsp;UARTConfigSet(UART2_BASE,&nbsp;9600,&nbsp;UART_CONFIG_WLEN_8&nbsp;|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_CONFIG_STOP_ONE&nbsp;|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_CONFIG_PAR_NONE);<br /><br />2.&nbsp;UARTFIFOLevelSet()<br />  设置UART收发FIFO的深度,可以设置的深度有2、4、8、12、14<br /><br />3.&nbsp;UARTSpaceAvail()<br />  确认在发送FIFO里是否有可利用的空间。<br /><br />4.&nbsp;UARTCharsAvail()<br />  确认在接收FIFO里是否存在字符。<br /><br />5.&nbsp;UARTCharPutNonBlocking()<br />  该函数要与UARTSpaceAvail()配合使用,如果已确认发送FIFO里有可用空间,则将字符直接放入发送FIFO,不等待。<br /><br />6.&nbsp;UARTCharGetNonBlocking()<br />  该函数要与UARTCharsAvail()配合使用,如果已确认接收FIFO里有字符,则直接从接收FIFO里读取字符,不等待。<br /><br />7.&nbsp;UARTCharPut()<br />  将字符放到发送FIFO里,如果没有可用空间则一直等待。<br /><br />8.&nbsp;UARTCharGet()<br />  从接收FIFO里读取字符,如果没有字符则一直等待。<br /><br />9.&nbsp;UARTIntEnable()<br />  使能一个或多个UART中断,例如:<br />&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;同时使能接收中断(接收FIFO溢出)和接收超时中断<br />&nbsp;&nbsp;&nbsp;&nbsp;UARTIntEnable(UART2_BASE,&nbsp;UART_INT_RX&nbsp;|&nbsp;UART_INT_RT);<br /></big><br /><br />(zlgmcu_wdx)
puppyh 发表于 2008-9-25 11:21 | 显示全部楼层

误导工程师

如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率????<br /><br />如果一次通讯的数据只有1个,而且间隔时间很长。收到一个数据后就产生中断程序能够正常运行;如果使用FIFO,收到一个字节后,不产生中断,系统不知道已经接收到数据,搞个超时中断,就没有实时性了,那程序运行就有问题。<br /><br />所以,使用时要根据实际情况,开启FIFO或关闭FIFO,才是正道!<br />
id001 发表于 2008-9-25 12:19 | 显示全部楼层

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

  
teddeng 发表于 2008-9-25 14:13 | 显示全部楼层

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

lm3s9616&nbsp;datasheet&nbsp;page&nbsp;288:<br />Programmable&nbsp;FIFO&nbsp;length,&nbsp;including&nbsp;1-byte&nbsp;deep&nbsp;operation&nbsp;providing&nbsp;conventionaldouble-buffered&nbsp;interface<br /><br />另外ZLG的9616中文翻译关于UART有个错误:<br />中文版&nbsp;PAGE292:<br />在UARTLCRH的位1、位2和位7置位时,发送奇偶校验位,且检测结果<br />为0。在位1和位7都置位且位2清零时,发送奇偶校验位,且检测结果为<br />1。<br />英文版PAGE&nbsp;305<br />When&nbsp;bits&nbsp;1,&nbsp;2,&nbsp;and&nbsp;7&nbsp;of&nbsp;UARTLCRH&nbsp;are&nbsp;set,&nbsp;the&nbsp;parity&nbsp;bit&nbsp;is&nbsp;transmitted&nbsp;and&nbsp;checked&nbsp;as&nbsp;a&nbsp;0.&nbsp;When&nbsp;bits&nbsp;1&nbsp;and&nbsp;7&nbsp;are&nbsp;set&nbsp;and&nbsp;2&nbsp;is&nbsp;cleared,&nbsp;the&nbsp;parity&nbsp;bit&nbsp;is&nbsp;transmitted&nbsp;and&nbsp;checked&nbsp;as&nbsp;a&nbsp;1.<br /><br />这里意思是当bit7置1时,根据bit2强制发送效验位为1或0。<br />也就是通用串口常用奇偶效验位配置中的&nbsp;MARK、&nbsp;SPACE方式。
seeokok 发表于 2008-9-25 18:43 | 显示全部楼层

FIFO可以关掉

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

竟然没有FIFO空中断

竟然没有FIFO空中断,<br />LM串口中看不中用。
seeokok 发表于 2008-9-26 12:40 | 显示全部楼层

FIFO的空中断倒是用不着。

关掉FIFO,发中断就相当于空中断了。<br />如果使用FIFO,在快要发完的时候产生中断,赶紧往FIFO里头填不是更好吗?
wlq_9 发表于 2008-9-26 13:15 | 显示全部楼层

就是用的16c550的硬件ip嘛.都差不多的,谈不上什么特点.<br />fifo有用处,stm32的dma也有自己的用处.串口又不是什么十分高速的设备,随便整整.
 楼主| zlgmcu 发表于 2008-9-28 08:46 | 显示全部楼层

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

  
talent8791 发表于 2008-10-11 16:04 | 显示全部楼层
ather2180 发表于 2008-10-14 22:02 | 显示全部楼层

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

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

FIFO是很好用的!

当然,有时也会有点小麻烦。<br />当ARMx(有FIFO)与MCU(无FIFO)进行UART通信时,如果MCU的UART接收软件写得不好,ARMx发送字节间隔时间短,存在MCU接收不完整的可能。<br /><br />声明只是可能而已。<br /><br />
 楼主| zlgmcu 发表于 2008-10-25 09:06 | 显示全部楼层

FIFO不需要禁止

新版《Stellaris外设驱动库》新增一个函数UARTBusy(),可以探测发送FIFO是否为空,因此完全不必要禁止FIFO。
汽车电子 发表于 2008-10-31 14:28 | 显示全部楼层

我的FIFO永远都是开启的

&nbsp;&nbsp;&nbsp;还嫌它太短了呢,怎么不搞个128字节呀什么的,那就爽了<br />&nbsp;&nbsp;&nbsp;如果支持DMA,更爽了...
 楼主| zlgmcu 发表于 2008-10-31 17:45 | 显示全部楼层

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

  
AIRWILL 发表于 2008-11-7 17:58 | 显示全部楼层

我也禁止 FIFO

因为我的通信协议要求检测到数据错误,&nbsp;要重发这个数据
 楼主| zlgmcu 发表于 2008-11-8 10:13 | 显示全部楼层

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

在一个典型应用当中,数据往往是按包发送的(包的长度自己定义,一般几B至几百B),如果出错,整包重发。
chunk 发表于 2008-11-20 14:28 | 显示全部楼层

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

成了经典理解了?<br /><br />CPU有一些智能,应该努力让它做一些智慧化的工作,而不是体力活儿。那什么是体力活儿?<br /><br />memcpy,怎么样?典型的体力活儿对吗?这里需要什么智慧?同样的,把数据在内存与外设之间搬来挪去也是体力活儿,这些都应该用专门的电路去做,于是怎么样?DMA就有了吧?<br /><br />DMA有点复杂,要考虑成本问题不好弄。CPU呢?能力有点富裕,搬数据这事还得让CPU干,能者多劳嘛。可又不能总为搬数据麻烦CPU。于是呢?FIFO是个好东西。对吧?<br /><br />那还有什么活儿是体力活儿?<br />void&nbsp;delay(int&nbsp;time)<br />{<br />&nbsp;&nbsp;while(time--);<br />}<br />没错吧?这个函数除了费电之外有其它什么智商吗?没有。于是就有了“操作系统”,你想等一会儿啊?行,把CPU交给我分给其它任务。CPU就是出租车,任务是司机,操作系统就是出租车公司:“人权要求我不能压榨司机,你们俩司机白天晚上两班倒,歇人不歇车,我压榨那车行不?”<br /><br />然而有时候这些精妙的想法并不总适用,比如16楼,他不分组交换,而是字符交换,虽然理论上应该充分利用硬件的特性做成分组交换,人家的协议是沿袭下来的,范不着改。CPU又是个ARM,能力大大的富裕。<br /><br />delay是费电,可我就想等1uS,您操作系统还没切换完任务呢5uS都过去了,算了不劳您大驾我自助吧。
wftyy 发表于 2008-11-20 22:22 | 显示全部楼层

LM3S的串口发送FIFO不好用

必须添满,才能有发送中断。比较失败呀。<br /><br />如果发送到最后几个字节,不够发送FIFO的长度,怎么能够知道发送完成了呢??<br />比如,用RS485,发送完是要及时设置为接收状态的。
 楼主| zlgmcu 发表于 2008-11-21 08:48 | 显示全部楼层

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

“必须添满,才能有发送中断”——并非这样,不填满也能产生中断。<br />“怎么能够知道发送完成了呢”——库函数UARTBusy()可以探知。<br /><br />19楼的担心完全没有必要。详见这里的UART**和例程,有非常详细的讲解:<br />【Luminary开发工具及开发指南】<br /><a href="http://www.zlgmcu.com/luminary/exploitation_guide.asp" target=_blank>http://www.zlgmcu.com/luminary/exploitation_guide.asp</a><br />
您需要登录后才可以回帖 登录 | 注册

本版积分规则

81

主题

1146

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部