前言
本周筆者花了好多天的時(shí)間,計(jì)劃從多個(gè)方面對(duì)串口驅(qū)動(dòng)做個(gè)比較。下面就從以下幾個(gè)角度做個(gè)對(duì)比測(cè)試。
1. 工作模式對(duì)照
2. close open 測(cè)試
3. poll 發(fā)送測(cè)試
4. flush 支持測(cè)試
5. 非阻塞收發(fā)測(cè)試
6. 阻塞收發(fā)測(cè)試
7. 回環(huán)測(cè)試數(shù)據(jù)丟失率
其它未測(cè)試項(xiàng):stream 支持,因?yàn)?v1 v2 只有 poll 模式支持, serialX 可以全模式支持,這一項(xiàng)未進(jìn)行對(duì)比。
測(cè)試環(huán)境
- rt-thread 4.1.0
- STM32F429-ATK-APOLLO
- 串口收發(fā)緩存均設(shè)定 128 字節(jié)
工作模式對(duì)照
版本 | poll收發(fā) | 阻塞/非阻塞 | 驅(qū)動(dòng)層緩存 | DMA支持 | STREM 支持 |
v1 | Y | - | - | Y | 僅poll |
v2 | Y | * | Y | Y | 僅poll |
X | Y | Y | Y | Y | 全模式 |
> \* v2 對(duì)阻塞概念的認(rèn)識(shí),僅認(rèn)為是降低 cpu 耗用。
close & open 測(cè)試
測(cè)試過(guò)程:
1. 先用 poll 模式打開,打開失敗直接返回;成功輸出 "POLL modeopen opened\n" 。
2. 輸出 "CLOSE & REOPEN\n" 。關(guān)閉串口設(shè)備,再用中斷收發(fā)模式打開,打開失敗直接返回;成功輸出 "INT mode opened\n" 。
3. 最后循環(huán)關(guān)閉打開 1百萬(wàn)次。打開失敗直接返回。
4. 測(cè)試通過(guò),使用 poll 模式打開串口設(shè)備,并輸出 "REOPEN successfull\n"。準(zhǔn)備進(jìn)入下一項(xiàng)測(cè)試。
版本 | v1 | v2 | X |
測(cè)試結(jié)果 | 通過(guò) | 通過(guò) | 通過(guò) |
poll 發(fā)送測(cè)試
用 poll 模式打開串口,發(fā)送若干數(shù)據(jù)。
版本 | v1 | v2 | X |
測(cè)試結(jié)果 | 通過(guò) | 通過(guò) | 通過(guò) |
flush 支持測(cè)試
如果沒(méi)有 flush ,驅(qū)動(dòng)緩存的數(shù)據(jù)可能沒(méi)有完全輸出到外設(shè),這個(gè)時(shí)候 close 設(shè)備可能出現(xiàn)丟失部分?jǐn)?shù)據(jù)。
使用 flush 的目地就是保證驅(qū)動(dòng)層緩存數(shù)據(jù)完全輸出到外設(shè),之后對(duì)設(shè)備的任何操作不會(huì)影響之前的數(shù)據(jù)。
版本 | v1 | v2 | X |
測(cè)試結(jié)果 | 不支持 | 不支持 | 通過(guò) |
> 因?yàn)?v1 不支持非阻塞發(fā)送,也沒(méi)有驅(qū)動(dòng)層緩存,write 總是把最后一個(gè)字節(jié)寫到串口移位寄存器后才返回。所以 v1 不會(huì)出現(xiàn)丟失數(shù)據(jù)的現(xiàn)象。
> v2 在這一環(huán)節(jié)的表現(xiàn)和 v1 是一樣的,大家可以猜猜原因是啥。
**注:本部分為了測(cè)試 flush 特性有效性,因此 X 出現(xiàn) close 的時(shí)候出現(xiàn)丟數(shù)現(xiàn)象。使用版在 close 設(shè)備的時(shí)候應(yīng)該強(qiáng)制 flush 一下的。**
非阻塞收發(fā)測(cè)試
使用中斷非阻塞模式打開串口設(shè)備,發(fā)送 10k 左右數(shù)據(jù)量,同時(shí)測(cè)量一下時(shí)間。
數(shù)據(jù)量 | v1 | v2 | X |
102400 | 102400 / 9762ticks | 102400 / 8863ticks | 102400 / 8863ticks |
10240 | 10240 / 976ticks | 10240 / 876ticks | 10240 / 876ticks |
128 | 128 / 12ticks | 128 / 11ticks | 128 / 11ticks |
這部分測(cè)試大體上符合預(yù)期,因?yàn)橛芯彺妫瑅2 和 X 先把數(shù)據(jù)放到緩存中就返回了。這樣可以減少發(fā)送等待時(shí)間。
阻塞收發(fā)測(cè)試
數(shù)據(jù)量 | v1 | v2 | X |
102400 | 102400 / 9762ticks | 102400 / 8902ticks | 102400 / 8866ticks |
10240 | 10240 / 976ticks | 10240 / 890ticks | 10240 / 884ticks |
128 | 128 / 12ticks | 128 / 11ticks | 128 / 11ticks |
> v1 在非阻塞和阻塞兩種模式下的表現(xiàn)是一樣的,因?yàn)樗鼪](méi)有阻塞概念。
>
> v2 耗時(shí)比 v1 少,這是在預(yù)料中的,但是,它還是比 X 多了幾個(gè) tick 。這也是上文中工作模式對(duì)照部分對(duì)它的阻塞/非阻塞特性加 \* 的原因。
特別測(cè)試,當(dāng)每次寫小于串口驅(qū)動(dòng)層緩存大小的數(shù)據(jù)時(shí),
數(shù)據(jù)量 | v2 | X |
16 | 1ticks | 0ticks |
32 | 5ticks | 0ticks |
128 | 11ticks | 0ticks |
為什么出現(xiàn)了和上面表格不一樣的結(jié)果,因?yàn)檫@次測(cè)試,每次寫之前有個(gè) 1s 延時(shí),保證串口緩存是空的。**當(dāng)串口緩存大小是 N 前提下,每次 write 小于等于 N 數(shù)量的數(shù)據(jù)應(yīng)該可以直接寫到緩存,并立馬返回!**所以,對(duì)于 X 來(lái)說(shuō)耗時(shí)就是 **0**。
這個(gè)很重要,**當(dāng)我們用串口調(diào)試程序,需要打印一些信息的時(shí)候,又不希望因?yàn)榇谳敵鰯?shù)據(jù)影響到其它業(yè)務(wù)的時(shí)序,或者,最大限度地降低因串口輸出數(shù)據(jù)而影響其它程序執(zhí)行時(shí)序**。
回環(huán)測(cè)試數(shù)據(jù)丟失率
使用阻塞模式打開串口設(shè)備。這次通過(guò)串口調(diào)試助手以 20ms 的定時(shí)間隔,發(fā)送 384 字節(jié)數(shù)據(jù)。
版本 | v1 | v2 | X |
丟失率 | 671144 / 556848/17.03% | 1208816/1070464/11.45% | 2390800/2390800/0% |
> v2 在這一步表現(xiàn)很差,第一次,筆者應(yīng)用層緩存是 512 字節(jié),想 `rt_device_read(uart, -1, recvbuf, 512);` 發(fā)現(xiàn) read 不到任何數(shù)據(jù),read 也不阻塞了,而是總能返回,單步進(jìn)去看到,但接收的數(shù)據(jù)大于驅(qū)動(dòng)緩存的時(shí)候,驅(qū)動(dòng)拒絕處理,直接返回0!!!v2 的缺陷之一。
>
> 鑒于以上原因,之后改成 `rt_device_read(uart, -1, recvbuf, 128);` 應(yīng)用緩存和驅(qū)動(dòng)緩存大小相等。
>
> 手動(dòng)單次發(fā)送,一次發(fā)送 344 字節(jié)數(shù)據(jù)(多于驅(qū)動(dòng)緩沖大小),接收 256 字節(jié),再次發(fā)送,接收 384 字節(jié),第三次發(fā)送接收還是 256 字節(jié),第四次又變成 384字節(jié)。
即便考慮到 v2 的上述缺陷,最多有 127 個(gè)字節(jié)數(shù)據(jù)被“滯留”串口驅(qū)動(dòng)緩存里未及時(shí)返回。也彌補(bǔ)不了上述丟失率!
開啟 DMA 的表現(xiàn)
很遺憾,v1 只支持 DMA 接收不支持 DMA 發(fā)送(估計(jì)以后也用不上 v1 了),由以上對(duì)比測(cè)試我們發(fā)現(xiàn) v2 和 v1 很類似,在測(cè)試 v2 DMA 接收發(fā)送時(shí)也發(fā)現(xiàn)總體效果和使用中斷沒(méi)多少差異。
X 的表現(xiàn)如何呢?等待您的發(fā)現(xiàn)!
> 遺憾的是,筆者對(duì) STM32 的 HAL 極其不熟悉,又極其不想用 HAL 。花了很長(zhǎng)時(shí)間想自己通過(guò)寄存器配置實(shí)現(xiàn),最終沒(méi)成功,還是放棄了。
>
> HAL 有一個(gè)好處,那就是幾乎可以適配 STM32 所有系列芯片。但是,HAL 不是為 OS 而生的 `#error "USE_RTOS should be 0 in the current HAL release"`,在 OS 上用終究有可能遇到失鎖的問(wèn)題。
>
> 使用 HAL 還有個(gè)小小的瑕疵,那就是 `is_dma_txing` 判斷變得不友好,無(wú)奈之下,筆者在 `struct stm32_uart` 中添加了個(gè) `rt_bool_t dmaTxing;` 變量 —— ”HAL 中 gState 和 RxState 已經(jīng)夠多了“ 。算是目前的一個(gè)小遺憾吧。
結(jié)束語(yǔ)
最后,依舊公開測(cè)試代碼,本次測(cè)試使用的代碼可以在 [serialX]( https://gitee.com/thewon/serialX ) 倉(cāng)庫(kù)找到。近期,筆者也會(huì)將 serialX 提交到 rt-thread 主倉(cāng)庫(kù)。
提前預(yù)告,下次我們來(lái)聊聊 serialX 在做控制臺(tái)串口時(shí)遇到的問(wèn)題已經(jīng)解決方案(包括使用中斷 DMA 收發(fā)模式打開的串口設(shè)備)。
相關(guān)文章:
rt-thread 驅(qū)動(dòng)篇(一) serialX 框架理論
rt-thread 驅(qū)動(dòng)篇(二) serialX 理論實(shí)現(xiàn)
審核編輯:湯梓紅
-
測(cè)試
+關(guān)注
關(guān)注
8文章
5164瀏覽量
126473 -
串口驅(qū)動(dòng)
+關(guān)注
關(guān)注
2文章
82瀏覽量
18623 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1273瀏覽量
39924 -
serialX
+關(guān)注
關(guān)注
0文章
7瀏覽量
803
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論