IIC總線是一個(gè)雙向的兩線連續(xù)總線,它為集成電路之間提供通信線路。其意思是完成集成電路或功能單元之間信息交換的協(xié)議。
01IIC協(xié)議時(shí)序介紹
IIC協(xié)議的時(shí)序簡(jiǎn)單來(lái)說(shuō)就是兩條線之間的關(guān)系,分別為時(shí)鐘線SCL和數(shù)據(jù)線SDA,先看IIC協(xié)議的時(shí)序圖。
上圖為IIC的時(shí)序圖,該時(shí)序圖的狀態(tài)分為空閑態(tài)、起始位、停止位還有數(shù)據(jù)的讀/寫狀態(tài)。
1、空閑狀態(tài):數(shù)據(jù)線SDA為高電平,時(shí)鐘線SCL為高電平;
2、起始位:時(shí)鐘線SCL為高電平,數(shù)據(jù)線SDA出現(xiàn)一個(gè)下降沿,由此產(chǎn)生一個(gè)起始位;
3、停止位:時(shí)鐘線SCL為高電平,數(shù)據(jù)線SDA出現(xiàn)一個(gè)上升沿,由此產(chǎn)生一個(gè)停止位;
4、數(shù)據(jù)讀/寫狀態(tài):數(shù)據(jù)的讀寫狀態(tài)主要包括串行數(shù)據(jù)的輸入和輸出以及應(yīng)答信號(hào),讀寫數(shù)據(jù)的具體的時(shí)序圖如下所示。
當(dāng)兩個(gè)設(shè)置之間采用IIC通信時(shí)(其中一個(gè)為主機(jī),另一個(gè)為從機(jī)),當(dāng)主機(jī)向從機(jī)寫入數(shù)據(jù)時(shí),SDA上的每一位數(shù)據(jù)均在SCL的高電平期間被寫入從機(jī)中。因此在主機(jī)需要在數(shù)據(jù)線SCL為低電平期間改變SDA上要寫入的數(shù)據(jù)。當(dāng)主機(jī)需要讀取從機(jī)上的數(shù)據(jù)時(shí),從機(jī)則需要在SCL為低電平期間將數(shù)據(jù)輸出到SDA數(shù)據(jù)線上,在SCL為高電平期間保持?jǐn)?shù)據(jù)的穩(wěn)定,而主機(jī)則需要在SCL為高電平時(shí)將SDA線上的數(shù)據(jù)讀取并存儲(chǔ)起來(lái)。
每當(dāng)一個(gè)字節(jié)的數(shù)據(jù)傳輸完成時(shí),數(shù)據(jù)接收方都會(huì)向數(shù)據(jù)發(fā)送方發(fā)送一位的應(yīng)答信號(hào),即響應(yīng)位。在響應(yīng)應(yīng)答位時(shí),數(shù)據(jù)發(fā)送方將SDA線設(shè)置為三態(tài)門輸入,在IIC總線上,數(shù)據(jù)線SDA都有一個(gè)上拉電阻,即一般情況下SDA都默認(rèn)為高電平,若數(shù)據(jù)接收方正確接收到數(shù)據(jù)后,則數(shù)據(jù)接收方將會(huì)將SDA線的電平拉低,表示正確應(yīng)答。
02IIC程序設(shè)計(jì)
首先來(lái)看需要定義的端口,分別為時(shí)鐘源clk,復(fù)位端rst,cmd為指定此次傳輸是否需要加起始位或停止位,go為啟動(dòng)IIC的信號(hào),rx_data為發(fā)送的數(shù)據(jù),tx_data為接收的數(shù)據(jù),trans_done為IIC數(shù)據(jù)傳輸完成標(biāo)志,ack_o為應(yīng)答信號(hào),i2c_scl為時(shí)鐘線SCL,i2c_sda為數(shù)據(jù)線SDA。定義如下圖所示。
接下來(lái)便是分配上述端口的輸入、輸出類型。
首先clk和rst都為輸入端口。cmd為我們自己設(shè)置,但是我們這里寫的不是頂層文件,cmd具體的值需要在頂層文件中設(shè)置,所以此處也為input輸入類型。同理控制IIC啟動(dòng)的go端口也是在頂層文件中設(shè)置,此處為input輸入。發(fā)送數(shù)據(jù)存儲(chǔ)器tx_data中的數(shù)據(jù)也是在頂層文件中寫進(jìn)去,為input輸入。rx_data為接收到的數(shù)據(jù),在頂層文件中接收,接收到后這里再將其輸出來(lái)查看處理,所以為output輸出端。
其它端口信號(hào),發(fā)送完成標(biāo)志位和應(yīng)答信號(hào)還有時(shí)鐘信號(hào)都是輸出的信號(hào)。數(shù)據(jù)線SDA的端口i2c_sda,因?yàn)槠溆忠獙憯?shù)據(jù)也要讀數(shù)據(jù),所以為inout,輸入輸出端,即可輸入又可輸出。
然后此處定義系統(tǒng)外接的50M系統(tǒng)時(shí)鐘,定義IIC的工作速度為400K(這里IIC的工作速度分三種,標(biāo)準(zhǔn)模式為100K,快速模式為400K,高速模式為3.4M),然后計(jì)算計(jì)數(shù)器計(jì)數(shù)的最大值SCL_CNT_M。
然后此處定義的便是數(shù)據(jù)線SDA的三態(tài)門輸入,當(dāng)i2c_sda_oe為1時(shí)i2c_sda輸出i2c_sda_o的值,當(dāng)i2c_sda_oe為0時(shí)i2c_sda輸出高阻抗。
此處寫的是計(jì)數(shù)器,用來(lái)書寫時(shí)鐘線SCL,當(dāng)計(jì)數(shù)值div_cnt未達(dá)到IIC工作速度的最大值時(shí),div_cnt自加,達(dá)到最大值時(shí)則清零,該計(jì)數(shù)器由使能端en_div_cnt控制。下面的sclk_plus則是一次計(jì)數(shù)滿后置1,用作一個(gè)標(biāo)志信號(hào)。
接下來(lái)便是狀態(tài)機(jī)的書寫,首先定義如下幾個(gè)常量。
上面的一組分別為,wr為寫請(qǐng)求,sta為起始位請(qǐng)求,rd為讀請(qǐng)求,sto為停止位請(qǐng)求,ack為應(yīng)答位請(qǐng)求,nack為無(wú)應(yīng)答請(qǐng)求,當(dāng)系統(tǒng)符合相應(yīng)位請(qǐng)求時(shí)便會(huì)跳轉(zhuǎn)到相應(yīng)的狀態(tài)。
下面的一組數(shù)據(jù)則是對(duì)應(yīng)相應(yīng)的狀態(tài),idle為默認(rèn)初始狀態(tài),gen_sta則為產(chǎn)生起始信號(hào)狀態(tài),wr_data則為寫數(shù)據(jù)狀態(tài),rd_data則為讀數(shù)據(jù)狀態(tài),check_ack為核對(duì)應(yīng)答位信號(hào)狀態(tài),gen_ack為產(chǎn)生應(yīng)答信號(hào)狀態(tài),gen_sto為產(chǎn)生停止信號(hào)狀態(tài)。
首先看在狀態(tài)idle下的時(shí)序,首先將傳輸完成標(biāo)志信號(hào)清零,然后打開(kāi)三態(tài)輸出端i2c_sda_oe置1,等待IIC開(kāi)啟信號(hào)go置1,開(kāi)啟信號(hào)go置1后打開(kāi)計(jì)數(shù)器的使能端en_div_cnt,計(jì)數(shù)器開(kāi)始為時(shí)鐘信號(hào)SCL計(jì)時(shí)。然后便開(kāi)始匹配選擇有沒(méi)有起始信號(hào),以及是寫狀態(tài)還是讀狀態(tài),當(dāng)有起始信號(hào)時(shí),狀態(tài)機(jī)便跳轉(zhuǎn)置產(chǎn)生起始信號(hào)的狀態(tài),即gen_sta。
此處為產(chǎn)生起始信號(hào)狀態(tài),在cnt的計(jì)數(shù)值下書寫每一個(gè)信號(hào)的狀態(tài),cnt為0初始時(shí)打開(kāi)三態(tài)輸入端,i2c_sda輸出i2c_sda_o的狀態(tài)高電平1,cnt為1時(shí),將時(shí)鐘線SCL拉高為1,cnt為2時(shí)將數(shù)據(jù)線SDA拉低,產(chǎn)生下降沿,數(shù)據(jù)線SCL持續(xù)為高,如此便產(chǎn)生了起始信號(hào),cnt為3時(shí)將SCL拉低,如此為時(shí)鐘線SCL的時(shí)鐘周期。
接下來(lái)當(dāng)cnt為3時(shí)便判斷下一個(gè)狀態(tài)為寫狀態(tài)或者讀狀態(tài)。此處需要說(shuō)明一下,因?yàn)榇颂帪闀r(shí)序邏輯,賦值方式采用的是非阻塞賦值,所以賦值的狀態(tài)有點(diǎn)特殊,即當(dāng)前賦的值都是在下一個(gè)時(shí)鐘周期才生效。
此處為讀寫狀態(tài),上面為寫狀態(tài),當(dāng)sclk_plus為1時(shí)cnt自加1,cnt計(jì)數(shù)4次為一個(gè)SCL時(shí)鐘周期,在寫數(shù)據(jù)時(shí),一個(gè)數(shù)據(jù)為8位(二進(jìn)制),逐次將每一位數(shù)據(jù)存儲(chǔ)到i2c_sda_o中,然后打開(kāi)三態(tài)門i2c_sda_oe,cnt加1后將SCL時(shí)鐘線拉高,cnt再加1SCL時(shí)鐘線電平保持高電平,此時(shí)根據(jù)IIC主從機(jī)協(xié)議,數(shù)據(jù)線SDA上的數(shù)據(jù)將被從機(jī)讀取,然后cnt再加1便將SCL時(shí)鐘線上的電平拉低。寫數(shù)據(jù)完成之后狀態(tài)機(jī)便跳轉(zhuǎn)到等待應(yīng)答信號(hào)的狀態(tài)check_ack。
下面的便是讀數(shù)據(jù),讀數(shù)據(jù)和寫數(shù)據(jù)類似,也是cnt逐次自加,cnt從0自加到3,中間四次便是一個(gè)SCL時(shí)鐘線的周期。首先關(guān)閉SDA的三態(tài)門,將i2c_sda_oe置0,將時(shí)鐘線scl拉低,cnt自加1之后將SCL時(shí)鐘線拉高,cnt在此自加之后SCL時(shí)鐘線保持高電平,將SDA上讀取到的數(shù)據(jù)通過(guò)移位的方式存儲(chǔ)到rx_data存儲(chǔ)器中,cnt再次自加后便將SCL時(shí)鐘線拉低。
這里便是等待應(yīng)答的狀態(tài),等待應(yīng)答的過(guò)程也相當(dāng)于等待接收1位的數(shù)據(jù),當(dāng)cnt為0時(shí),關(guān)閉i2c_sda的三態(tài)門,將i2c_sda_oe置0,時(shí)鐘線SCL置0,cnt自加1后將SCL時(shí)鐘線拉高,cnt再次自加1之后便開(kāi)始讀取SDA數(shù)據(jù)線上接收到的數(shù)據(jù),將接收到的數(shù)據(jù)賦給端口ack_o,用來(lái)判斷應(yīng)答信號(hào)是否正確,cnt再次自加之后便將SCL時(shí)鐘線拉低。cnt自加到3之后,便開(kāi)始判斷當(dāng)前的IIC通信是否需要加停止位。
產(chǎn)生應(yīng)答的過(guò)程也為一次輸出的過(guò)程,cnt為0時(shí)打開(kāi)三態(tài)使能端,將i2c_sda_oe置1,將時(shí)鐘線SCL拉低,然后判斷應(yīng)答信號(hào)是否發(fā)送,需要發(fā)送則i2c_sda的取值i2c_sda_o賦0,無(wú)應(yīng)答則將i2c_sda_o賦1。因?yàn)閼?yīng)答信號(hào)ack為0有效。cnt自加后將時(shí)鐘線SCL拉高,cnt再次自加后時(shí)鐘線SCL保持高電平,cnt自加到3時(shí),將時(shí)鐘線SCL拉低。cnt為3后開(kāi)始判斷是否需要停止位,用來(lái)判斷下一個(gè)跳轉(zhuǎn)狀態(tài)。
根據(jù)停止位的時(shí)序,當(dāng)SCL時(shí)鐘線為高電平時(shí),SDA數(shù)據(jù)線產(chǎn)生一個(gè)上升沿便為停止位,即當(dāng)cnt為0時(shí)打開(kāi)i2c_sda的三態(tài)使能端,將i2c_sda_oe置1,將i2c_sda_o置0,這樣SDA數(shù)據(jù)線便先輸出低電平,cnt自加1后將時(shí)鐘線SCL拉高,cnt再次自加后將i2c_sda_o的值賦1,使SDA數(shù)據(jù)線輸出高電平,如此便產(chǎn)生了一個(gè)上升沿,cnt再次自加置3時(shí),SCL數(shù)據(jù)線保持高電平,如此IIC的停止位便產(chǎn)生了。
03 IIC仿真波形
首先便是老生常談的例化該程序。
定義相匹配的寄存器,然后例化過(guò)程寫的文件,這里pullup是將引腳上拉的意思,在電路中都存在上拉電路,SDA在電路中都是被上拉電阻拉至高電平狀態(tài)。
然后此處便是產(chǎn)生50M的時(shí)鐘源。
這里還寫了task調(diào)用程序,首先寫的是寫字節(jié)的task,輸入三個(gè)數(shù)據(jù),每一個(gè)數(shù)據(jù)都是8位,然后分別仿真了有起始位、無(wú)起始位無(wú)停止位、和有停止位的過(guò)程,先將開(kāi)始IIC的信號(hào)go拉高開(kāi)啟,然后將需要寫入的數(shù)據(jù)賦給寄存器tx_data中保存,然后關(guān)閉go,延時(shí)一段時(shí)間后便開(kāi)始捕獲發(fā)送完成信號(hào)trans_done的上升沿,下面兩組數(shù)據(jù)的方式同理。
然后便是讀取數(shù)據(jù)的task語(yǔ)句仿真,這里輸入兩個(gè),同樣也是仿真是否需要起始位、停止位,然后開(kāi)啟IIC開(kāi)始信號(hào)go,開(kāi)始時(shí)給go賦1,然后將數(shù)據(jù)存入寄存器,延時(shí)后關(guān)閉開(kāi)啟信號(hào)go,然后再延時(shí)等待捕捉傳輸完成標(biāo)志的上升沿。
下面是仿真波形圖
整體波形如圖所示。接下來(lái)為發(fā)送一個(gè)數(shù)據(jù)的仿真波形圖。
首先最頭上的光標(biāo)表示的是本次發(fā)送的數(shù)據(jù)為10100000,第二個(gè)光標(biāo)處表示的是起始位,SCL為高,SDA產(chǎn)生下降沿,后面兩個(gè)光標(biāo)之間便是傳輸?shù)臄?shù)據(jù),SCL高電平時(shí)看SDA上發(fā)送的數(shù)據(jù)。
然后這個(gè)圖便是接收數(shù)據(jù)的波形圖,SCL為高電平時(shí)讀取SDA上的數(shù)據(jù),并通過(guò)移位的方式將讀取的數(shù)據(jù)存儲(chǔ)到rx_data寄存器中。
評(píng)論