原文地址:?https://bbs.elecfans.com/jishu_2489801_1_1.html?
作者:@王釗
引言:FPGA開發,思路先行!
玩FPGA板子,讀代碼是基本功!尤其對從C語言轉戰FPGA的“寶貝們”來說,適應流水線(pipeline)編程可能需要點時間。
上篇點燈代碼解讀了基礎,而如果能親手寫出串口通訊代碼,恭喜你,FPGA的大門算是真正踏入了!
本文旨在幫初學者梳理FPGA開發的核心思維流程——思路對了,后面的路才順暢,這可是重中之重!
一:感性認知 - 燒錄 & 看效果
廢話不多說,先燒程序,眼見為實!

在Ubuntu下,等程序燒錄完成后,打開gtkterm,通過USB轉串口設備節點與板子通訊。
本次燒錄的實例實現的是“回顯”(Echo):你鍵盤輸入什么,板子就原樣發回什么。
這種時候我們可能會以為出現了幻覺(這效果對嗎?)
好辦!在回顯代碼里“加個1”,把接收到的數據+1再發送
再次燒錄以后,測試發現,按鍵輸入123變成了234。果然不是幻覺,我們可以繼續看代碼了。
經驗上講以上步驟還是必要的,這證明代碼是對的,以免被坑。
二:硬件連接 - 原理圖 & 管腳對一對
回到代碼,Top頂層模塊走起!
輸入腳有個25m的時鐘,輸出有個燈,這跟點燈程序一樣。然后串口有收發兩個腳。然后我去對一下原理圖。
找到原理圖第三頁,底板的原理圖,供電的Type-C口其實連到了CH340 USB轉串口芯片(單片機玩家老朋友了?。?/p>
這個原理圖其實看著有點暈,反正大致意思就是串口發送接收接到了H10和H11這兩個腳上。
管腳配置瞧一瞧:外部時鐘腳和led的腳跟之前點燈的程序一樣,下面就是多了H10和H11兩個腳,分別對于串口的RX和TX。
然后它們的電平是3.3V的。如果這里看著難受的話可以把它改到其他腳上,然后接一個自己的USB轉串口的板子上,自己的串口板只需要多接個GND地線,無需接3.3V電源,加上RX和TX一共3根線,注意RX和TX可能需要反一下。
三:協議基礎 - 磨刀不誤砍柴工
到這里又要啰嗦一下,FPGA調一個接口,首先就是我們需要清楚的知道接口有個的數據定義,協議等知識。不能上來就研究代碼,否則可能會迷糊。
(圖片來源:https://zhuanlan.zhihu.com/p/689643287)
這里是我搜索出來知乎的帖子,講串口協議的,有需要的話可以補充一下底層知識。
當然相信沒幾個人不知道串口的,但FPGA開發它還是蠻多套路的,比如接收一幀數據該如何接收。
大致的思路是這樣的,我們需要用一個比串口波特率更高的采樣信號去采集,串口的RX上什么時候出現起始位,然后接收每個數據位,最后延時一個停止位,再循環檢測起始位,接收下一幀數據。
四:代碼解析 - 接收模塊的奧秘
然后代碼我就不再講倍頻和reset邏輯了,點燈程序已經講過了。
直接看接收的代碼:這里看到模塊的調用,可以想象成我們在板子上焊了一塊芯片,它有一個clk腳rst_n腳;然后連到了top頂層的UART的RX上;收到數據后會返回一個接收完成的標志,8位的接收到的數據;最后還需要一個比波特率大的,這里是大16倍的采樣時鐘。
進入接收模塊的代碼里,我們看看芯片內部是怎樣實現的。這里作者用ASCCII碼畫了一個時序圖,這個太有用了,看代碼的時候需要反復的看這個圖。
簡單說一下這個時序圖,IDLE的時候是檢測起始位的狀態,起始位start是bit0,這里看著它是低電平的;然后到接收數據的狀態,也就是bit1到bit8這8位;最后是end停止位,回到IDLE。
所以程序的思路就有了,我們需要在16倍波特率的采樣周期上,不停的檢測RX腳上的電平,完成串口通訊一幀數據的接收。
接著看代碼,作者大神首先把RX腳做了個同步,這個套路不看代碼是學不到的,久了看見這種代碼腦袋里面會浮現出一個時序圖,大概就能看到clk和rx信號的時序,然后理解到為什么要同步。
注意這個模塊有兩個時鐘,一個是系統時鐘,一個是16倍的波特率的時鐘,它這同步的是系統時鐘。咱們先別暈在這里,繼續往下看。
后面的代碼是個狀態機,這代碼還有點多,我抓屏一爪還抓不完。大家可以打開代碼自己對著看,反正行號可以看出是講到哪里了。狀態機跟作者的時序圖是一致的,就是那些IDLE,start,end之類的狀態。
這里還有個特別玄乎的套路,本人也不是大神,所以也沒看明白。就是這個狀態機是用系統時鐘來檢測的,那個16倍波特率的采樣時鐘是在下面用個if來判斷的,就是采樣信號為高的時候去檢測數據信號的高低。本寶認為,為什么不直接把采樣信號放在always語句上面用呢。手賤的同學可以改一下試試,看看串口會不會丟數據,試完記得告訴我結論。
IDLE狀態沒什么看頭,我們看看start狀態。它這里有個采樣的計數,一個bit采樣16次。這里首先是從IDLE進入START狀態需要rx管腳為低電平,并且在16次采樣的中間那會不變成低電平,才認為起始信號有效。(為什么不判斷全部為高?或者前半段為高?)
反正最重要的是數到16個采樣就切到下一個狀態,不能快也不能慢,保證時序要求。
這里還有一個套路是我們會看到那些a=a,b=b的語句,其實我感覺是可以刪掉的,不知道是不是作者年級比較大,或許以前古時候的綜合器不寫else后面的東西,它會亂綜合一些東西出來。好奇寶寶們可以寫個測試程序,看看RTL電路有什么區別,同樣,測試出結論以后記得告訴我……
采樣狀態的邏輯看了半天,也沒真正做采樣的事情,只是輸出了一個變量rxd_cnt,這個變量表示采樣的是第幾個bit,還要注意的是這個變量在什么時候被鎖存改變的,我們注意到是在采樣計數為最后一個的時候鎖存的。
停止狀態啥也沒干,只是保證延時一個波特率的時間而已。
接著看代碼,上面采樣狀態輸出了一個變量rxd_cnt,然后這里才進行真正的采樣操作,它同時判斷了采樣計數器cmp_cnt,保證是在波形中部進行采樣??赡苓@么做是增加魯棒性。相信看到這里有些人會表示不服,我們可以把串口線接長一點,中間再加點電磁干擾,這樣比較一下如果不在中間采樣會不會導致丟數據的比率變高。同樣,如果有人測試了,記得把結論告訴我!??!
最后一段代碼是輸出一幀率數據接收完成的標志,可以看到它的鎖存邏輯是在停止位發送完畢的時候持續了一個采樣時鐘的高電平。同時鎖存輸出數據。
五:發送模塊 - 相對簡單
再往下就是看發送邏輯了,這塊邏輯跟接收邏輯幾乎一樣。其實發送邏輯大可不必這么精細,因為接收才需要高頻率的采樣,發送只要保證時序就可以了。如果實在看不懂接收邏輯,我建議大家還是直接寫一下發送邏輯,比如就按作者畫的時序圖,先用pll生成一個波特率的時鐘,再按照時鐘調整TX管腳的高低電平即可。最后用上面講的接長串口線的方法測試一下數據傳輸的效率。
大半夜的不知道誰拍了我一下,我就突然看到這塊代碼有點不對……這個case里面的語句的等于符號前面居然沒有小于符號了。這種情況奶奶沒教過啊,而且它always語句里面是個*號。其實verilog我也是只學了三天,所以不太確定這是不是就是個組合邏輯電路。哎,這個迷哪位好心人回帖告訴我一聲好不好。
萬一有人整篇文章都看不懂,這里有個好玩的東西,test_io這個腳是接到燈上的,它這里的邏輯是TX和RX上只要有數據變化,燈就會閃爍,實測我一直往串口輸入字符a,這個燈是可以看到閃爍的,閃的比較暗,大家可以關燈看看。
終極總結:FPGA接口開發心法
總結一下,關于接口的實現,無論接口多復雜,其實也是邏輯電平的控制,但前提是需要對協議非常的熟悉,再就是一下FPGA代碼的套路了,這些套路都是一點一點看眾大神的代碼悟出來的。
-
FPGA
+關注
關注
1643文章
21967瀏覽量
614185 -
串口通信
+關注
關注
34文章
1636瀏覽量
56549 -
開發板
+關注
關注
25文章
5531瀏覽量
102374
發布評論請先 登錄
【技術經典下載】《深入淺出玩轉FPGA》-珍貴的學習經驗和筆記
特權同學新書《勇敢的芯伴你玩轉Altera FPGA》電子版 下載 (FPGA初學者首選)
賽靈思FPGA初學者 必備圖書 特權同學新書《勇敢的芯伴你玩轉賽靈思 FPGA》
MATLAB串口調試助手應用程序和基于MATLAB開發USB的串口通信源代碼

單片機——串口通信(從串口接收多位數據保存到數組,發送多位數據到串口)

評論