(原創(chuàng)聲明:該文是作者的原創(chuàng),面向?qū)ο笫?/em>FPGA入門者,后續(xù)會有進(jìn)階的高級教程。宗旨是讓每個想做FPGA的人輕松入門,作者不光讓大家知其然,還要讓大家知其所以然!每個工程作者都搭建了全自動化的仿真環(huán)境,只需要雙擊top_tb.bat文件就可以完成整個的仿真(前提是安裝了modelsim),降低了初學(xué)者的門檻。如需整個工程請留言(微信Blue23Light),不收任何費(fèi)用,但是僅供參考,不建議大家獲得資料后從事一些商業(yè)活動!)
前面通過計數(shù)器實(shí)現(xiàn)了UART單字節(jié)數(shù)據(jù)的發(fā)送了接收,上節(jié)課又學(xué)習(xí)了狀態(tài)機(jī),那現(xiàn)在實(shí)現(xiàn)多字節(jié)數(shù)據(jù)的通訊就相對簡單了。首先把多字節(jié)的數(shù)據(jù)拆分成多個單字節(jié)的數(shù)據(jù),然后通過UART的發(fā)送模塊一個個發(fā)送即可;接收端把接收的單字節(jié)數(shù)據(jù)組合起來,就可以得到實(shí)際的數(shù)據(jù)。
思路很簡單,但是實(shí)際工程應(yīng)用中還要考慮更多的問題。最主要的就是如何保證數(shù)據(jù)的正確性。UART線上的數(shù)據(jù)一個個的接收下來,但是有效的數(shù)據(jù)從什么位置開始,有效數(shù)據(jù)的長度是多少,數(shù)據(jù)的正確性應(yīng)該如何保證?這就要加一些冗余的信息,比如幀頭,長度,校驗(yàn),幀尾之類的。其中幀頭是必須要加的,幀頭就是一個定位,檢測到幀頭后面就可以正確采集數(shù)據(jù)了。
本節(jié)工程要求:系統(tǒng)時鐘是100MHz,低電平復(fù)位,使用UART協(xié)議完成4byte數(shù)據(jù)的傳輸,為了保證數(shù)據(jù)傳輸?shù)恼_性,每幀數(shù)據(jù)添加幀頭(5a),數(shù)據(jù)長度(4)和幀尾(a5)。UART的波特率是115200,有奇偶校驗(yàn)位,偶校驗(yàn)。
我們根據(jù)需求分析一下,由于UART單字節(jié)收發(fā)的模塊設(shè)計都設(shè)計完畢了,那新的發(fā)送模塊只需要把要發(fā)送的數(shù)據(jù)排好隊,一個個往UART發(fā)送模塊里面放即可,新的接收模塊從UART接收模塊里面收數(shù),根據(jù)協(xié)議把有效的數(shù)據(jù)解析出來即可。
如下所示,一幀的數(shù)據(jù)由幀頭,長度,數(shù)據(jù)1,數(shù)據(jù)2,數(shù)據(jù)3,數(shù)據(jù)4和幀尾組成,每個拆分的數(shù)據(jù)都是單字節(jié)。那我們可以設(shè)計發(fā)送狀態(tài)機(jī),發(fā)幀頭->發(fā)長度->發(fā)數(shù)據(jù)1->發(fā)數(shù)據(jù)2->發(fā)數(shù)據(jù)3->發(fā)數(shù)據(jù)4->發(fā)幀尾即可,但是這樣設(shè)計有個問題,如果數(shù)據(jù)不是4個字節(jié)而是100個字節(jié),難道要寫100個發(fā)送數(shù)據(jù)的狀態(tài)機(jī)?這樣既增加了代碼量,又讓設(shè)計的代碼通用性降低!因?yàn)閿?shù)據(jù)長度改變一次代碼就要重新設(shè)計一次。
其實(shí)可以把4個發(fā)數(shù)據(jù)狀態(tài)合并成發(fā)送數(shù)據(jù)的狀態(tài),在該狀態(tài)里面設(shè)置一個計數(shù)器,發(fā)送一次計數(shù)一次,根據(jù)計數(shù)值跳出發(fā)送數(shù)據(jù)狀態(tài)機(jī),進(jìn)入發(fā)送幀尾的狀態(tài)機(jī)。所以發(fā)送的狀態(tài)機(jī)應(yīng)該如下所示。當(dāng)又?jǐn)?shù)據(jù)要發(fā)送的時候先進(jìn)入發(fā)送幀頭(HEAD)狀態(tài),幀頭發(fā)送完畢后(tx_over拉高)進(jìn)入發(fā)送數(shù)據(jù)長度(LEN)的狀態(tài),數(shù)據(jù)長度發(fā)送完畢后(tx_over拉高)進(jìn)入數(shù)據(jù)發(fā)送(SEND)狀態(tài),然后進(jìn)入數(shù)據(jù)發(fā)送等待狀態(tài)(WAIT),如果一次數(shù)據(jù)發(fā)送完畢(tx_over拉高)判斷已經(jīng)發(fā)送數(shù)據(jù)的個數(shù)(send_cnt),如果有效數(shù)據(jù)沒有發(fā)送完畢跳轉(zhuǎn)到數(shù)據(jù)發(fā)送狀態(tài),如果有效數(shù)據(jù)發(fā)送完畢進(jìn)入發(fā)送幀尾的狀態(tài)(TAIL),幀尾發(fā)送完畢后(tx_over拉高)進(jìn)入IDLE狀態(tài)等待下一幀數(shù)據(jù)的發(fā)送。
接收狀態(tài)機(jī)也是一樣,當(dāng)UART線上有數(shù)據(jù)的時候狀態(tài)由IDLE跳轉(zhuǎn)到幀頭檢測(CHK_HEAD)狀態(tài),在幀頭接收完畢后(rx_over_dly),判讀幀頭是不是期望的幀頭(chk_head_flag == 2'd1),如果是,就可以繼續(xù)接收數(shù)據(jù)長度了,如果不是,那就回到IDLE狀態(tài)繼續(xù)等待接收。在數(shù)據(jù)長度檢測(CHK_LEN)狀態(tài),在數(shù)據(jù)長度接收完畢后(rx_over_dly),判讀長度是不是期望的長度(chk_head_flag == 2'd1),如果是,就可以繼續(xù)接收數(shù)據(jù)了,如果不是,那就回到IDLE狀態(tài)繼續(xù)等待接收。經(jīng)過了兩輪的考驗(yàn),終于可以接收數(shù)據(jù)了,也是將接收數(shù)據(jù)分為接收數(shù)據(jù)(RECV_DATE)和接收數(shù)據(jù)等待(RECV_WAIT)兩個狀態(tài),如果接收的數(shù)據(jù)沒有完成就會繼續(xù)接收,等接收數(shù)據(jù)完成跳轉(zhuǎn)到接收幀尾狀態(tài)。在幀尾接收完畢后(rx_over_dly),判讀幀尾是不是期望的幀頭(chk_tail_flag == 2'd1),如果是,就可以跳轉(zhuǎn)到END狀態(tài)再跳轉(zhuǎn)到IDLE狀態(tài),如果不是,那就直接回到IDLE狀態(tài)等待接收。
有了上面的狀態(tài)機(jī),其實(shí)模塊設(shè)計就很簡單了,下面進(jìn)行發(fā)送模塊的講解。通過參數(shù)傳遞的方式進(jìn)行要發(fā)送數(shù)據(jù)的長度,幀頭和幀尾的傳遞。
定義了相關(guān)的寄存器和狀態(tài)機(jī)參數(shù),本模塊采用三段式的狀態(tài)機(jī)設(shè)計方式。
第一段,用時序邏輯控制狀態(tài)機(jī)的更新。
第二段,用組合邏輯控制狀態(tài)機(jī)的跳轉(zhuǎn)。
后面的都是第三段,主要控制數(shù)據(jù)傳遞給UART發(fā)送模塊。首先是發(fā)送使能信號的產(chǎn)生,這兒之所以把發(fā)送數(shù)據(jù)分成SEND和WAIT兩個狀態(tài)就,就是為了方便tx_start信號的產(chǎn)生!
設(shè)置了發(fā)送數(shù)據(jù)的計數(shù)器send_cnt,在發(fā)送數(shù)據(jù)的狀態(tài)下每發(fā)送一個數(shù)據(jù)增加一次,在IDLE狀態(tài)清零,為下次傳輸做準(zhǔn)備。4字節(jié)的數(shù)據(jù)通過移位的方式取出來要發(fā)送的數(shù)據(jù)。
下面是產(chǎn)生UART發(fā)送模塊的數(shù)據(jù)tx_data,在不同的狀態(tài)機(jī)下賦值即可,數(shù)據(jù)采用左移動的方式,所以每次取高8位即可。一幀數(shù)據(jù)發(fā)送完畢,產(chǎn)生send_done標(biāo)志信號。
最后例化UART發(fā)送模塊即可。
數(shù)據(jù)的接收模塊類似,通過參數(shù)傳遞的方式進(jìn)行要發(fā)送數(shù)據(jù)的長度,幀頭和幀尾的傳遞。
定義了相關(guān)的寄存器和狀態(tài)機(jī)參數(shù),本模塊采用三段式的狀態(tài)機(jī)設(shè)計方式。
首先要時刻檢測UART線上的變化,如果線上由空閑態(tài)(高電平)變成低電平,說明一次UART傳輸開始,檢測到這個變化rx_signal_fedge,作為狀態(tài)機(jī)跳轉(zhuǎn)的依據(jù)。
第一段,用時序邏輯控制狀態(tài)機(jī)的更新。
第二段,用組合邏輯控制狀態(tài)機(jī)的跳轉(zhuǎn)。
后面的都是第三段,主要控制從UART接收模塊接收數(shù)據(jù)。從UART接收的幀頭,數(shù)據(jù)長度,和幀尾只要有一個校驗(yàn)不過該幀的數(shù)據(jù)就不能使用。
使用計數(shù)器recv_cnt控制數(shù)據(jù)的接收,同時接收的數(shù)據(jù)右移動進(jìn)行存儲。這兒需要說明一下為什么會有一個END的狀態(tài)機(jī),主要是方便判讀數(shù)據(jù)受否正確,狀態(tài)機(jī)能運(yùn)行到END狀態(tài)說明幀頭,數(shù)據(jù)長度和幀尾都是正確的,直接把數(shù)據(jù)鎖存即可。
為了方便管理,新建了一個頂層文件uart_top,接口信號如下所示,該文件直接對新設(shè)計的發(fā)送和接收模塊例化。
在仿真tb文件中,對uart_top文件進(jìn)行例化和參數(shù)的傳遞,并產(chǎn)生4字節(jié)的隨機(jī)數(shù)進(jìn)行仿真,仿真結(jié)果如下所示,發(fā)送的數(shù)據(jù)和接收的數(shù)據(jù)是一致的,功能設(shè)計正確。
文章來源:http://www.zghlxwxcb.cn/news/detail-757451.html
目前設(shè)計的工程再加上約束文件,編譯后下載都FPGA內(nèi)部是可以直接使用的!所以僅僅使用計數(shù)器和狀態(tài)機(jī)模塊,就可以完成大多數(shù)需求的設(shè)計!所以到現(xiàn)在為止,如果你能很快的手動寫成這個工程的所有代碼并且仿真通過,那你就入門FPGA了,而且達(dá)到一般FPGA開發(fā)者的水平!文章來源地址http://www.zghlxwxcb.cn/news/detail-757451.html
到了這里,關(guān)于孩子都能學(xué)會的FPGA:第九課——多字節(jié)數(shù)據(jù)的發(fā)送和接收的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!