基于PL022 SPI 控制器 海思3516系列芯片SPI速率慢問題深入分析與優化

海思3516系列芯片SPI速率慢問題深入分析與優化(基于PL022 SPI 控制器)
我在某個海思主控的項目中需要使用SPI接口來驅動一塊液晶屏 , 液晶屏主控為 st7789,分辨率 240x240,圖像格式 RGB565 。
查閱海思相關手冊可知,Hi3516EV200 的 SPI 最高速率為 50MHz,理論上每秒鐘可以發送 50M/8=6.25MB 數據 。假設我需要在屏幕上以30fps的速率全屏實時顯示攝像頭的預覽畫面,每秒的數據量為 240*240*2*30=3456000B=3375KB=3.296MB,假設 SPI 工作在阻塞模式 , 則 cpu 使用率為 3.296/6.25*100%=52.7%,看起來還不錯 。如果我想進一步降低cpu使用率還可以降低預覽圖分辨率 , 降低幀率 , 比如我可以按 240*180 20fps 的規格顯示縮略圖,那么cpu使用率就可以降到 240*180*2*20/1024/1024/6.25=26.4% 。
上面這些都是我在寫代碼前的理論分析,真實效果當然需要寫程序簡單測試一下 。測試代碼內容大致如下:使用原生linux提供的 SPI 接口,即/dev/spidevX.X , 主程序中一個死循環沒有sleep,使用不同的顏色不停地刷全屏,看一秒鐘能達到多少次,也就是刷新率能達到多少幀 。
實際測試結果 , 每秒大約5次!肉眼可見的慢!能很明顯看到刷屏的時候是從上到下覆蓋過來的!
這么慢的速率就算以240*180的分辨率來刷新預覽畫面也只能達到7、8幀的水平,何況cpu使用率是100%,其他業務也沒辦法正常運行,所以spi的速率必須優化 。
第一步當然是用邏輯分析儀或示波器抓實際波形,觀察是時鐘信號沒有達到50MHz,還是有其他地方浪費時間 。對于邏輯分析儀而言 , 要考慮采樣率是否足夠,例如邏輯分析儀的采樣率是100MHz , 理論上可以采集50MHz的信號,實際采集50MHz的信號很可能采集不準;示波器也一樣,示波器需要考慮的是帶寬,一般入門級示波器都有100MHz帶寬,問題不大 。對了,別拿DIY的示波器來搗亂 。
這張圖就是我通過示波器抓到的海思 SPI 時鐘線上的波形,問題非常明顯 , 發送的兩個字節之間間隔了 1.656us!開發過任意單片機的spi并實際抓過波形的朋友應該都知道,spi的時鐘幾乎是連續,正常情況下絕對不可能間隔這么長 。

基于PL022 SPI 控制器 海思3516系列芯片SPI速率慢問題深入分析與優化

文章插圖
再檢查一下spi的時鐘有沒有達到理論的50MHz,8個clk共計160ns,沒問題,達到了理論速率 。
基于PL022 SPI 控制器 海思3516系列芯片SPI速率慢問題深入分析與優化

文章插圖
題外話:為什么50MHz的方波在示波器上顯示為正弦波?因為我這款示波器的帶寬只有100MHz,50MHZ方波信號本身沒有超過示波器帶寬的上限 , 但是它的2n+1次諧波分量遠遠高于示波器帶寬 。所以想要勉強看到50MHz方波的波形 , 那么示波器至少要能采集到3次諧波信號,也就是150MHz的信號,這就需要一個200MHz帶寬的示波器(我買不起?。?
簡單計算一下,發送一個字節需要 0.16+1.656=1.816us,也就是1秒鐘可以發送 1s/1.816us=549450B=536.6KB 的數據,這個數據量甚至不足理論值的十分之一 , 換算下來確實1秒鐘也只能刷5屏 。所以接下來的目標就是找出到底是什么原因讓發送的兩個字節之間占用了足足1.6us 。
首先我的發送代碼中沒有加任何延時函數,所以這1.6us的延時只能來自于linux內核spi驅動 。
查看linux內核spi相關源碼(提前安裝好完整的海思開發環境,并下載對應版本linux內核源碼,打海思linux源碼patch)linux-4.9.y\drivers\spi\spi-pl022.c由源碼可知海思的spi使用的是 ARM PrimeCell SSP (PL022) 控制器,這些驅動代碼應該非常成熟了,不會存在這么明顯的問題,大概看了看源碼也沒發現啥耗時的地方 , 之后專門以 ssp-pl022 和 delay 作為關鍵字google一番也沒有發現類似的問題 。思索了一下,我決定放棄修改內核驅動,首先內核代碼很成熟,基本輪不到我這種小角色去debug,其次每次修改都要重新編譯并燒錄內核,太麻煩 。所以我決定自己重寫一個spi內核模塊ko驅動 。
非常幸運 , 在海思SDK的 drv.tgz\drv\extdrv\ssp-st7789 中正好有源碼 , 連芯片型號都一樣,基于這個代碼做一些簡單修改就能用 。
經過我的一番修改,實際測試下來發現這個ko模塊的性能比linux內核spi的性能有一點點提升 , 延時從1.656us降低到了1.6us以內 , 基本等于沒有優化,這里就不放截圖了 。
這個代碼就比較簡單 , 讀起來也不費勁 , 大概看了一下還是能找到一點優化的地方 , 注意看

推薦閱讀