近期完成了CAN模塊數(shù)據(jù)收發(fā)的調(diào)試,用到的芯片有CAN控制器:MCP2518FD和CAN收發(fā)器:ADM3057E。通過FPGA-XC7A35T開發(fā)板的SPI接口與分別與兩個MCP2518FD相連,分別對其進行寄存器的讀寫以及RAM的讀寫,控制其中一個發(fā)送數(shù)據(jù),另一個接收數(shù)據(jù),從而實現(xiàn)了CAN協(xié)議數(shù)據(jù)發(fā)送與接收功能的調(diào)試。
一、SPI通信:
首先要實現(xiàn)FPGA與MPC2518FD的SPI通信,從而實現(xiàn)對其寄存器的讀寫配置。新建vivado工程,Creat block design,添加軟核以及兩個自己的SPI核,進行連線等后續(xù)工作。最終的block design如圖所示

為兩個SPI核分配地址。Generate output products,然后Create HDL wapper,生成HDL頂層文件,將PS端當做一個IP核來使用。新建V文件,例化Wrapper核并添加ILA進行兩組SPI 8個信號的監(jiān)控。創(chuàng)建XDC文件,將物理引腳進行管腳約束和時鐘約束。
編譯綜合后生成bit文件,Export Hardware,Launch SDK,啟動 SDK 開發(fā)環(huán)境。在SDK里進行C語言的編程,實現(xiàn)通過SPI對MCP2518FD寄存器的讀和寫。將自己的SPI核對應(yīng)的C語言讀寫函數(shù)直接拿來用,發(fā)現(xiàn)無法進行讀寫,仔細對比芯片手冊的SPI讀寫時序和自己的SPI讀寫時序,發(fā)現(xiàn)并解決了問題:
手冊SPI時序:

錯誤(寫不進去):

正確(能寫進去):

錯誤原因:數(shù)據(jù)位最后一位末與cs信號上升沿重合,正確的時序為cs信號再過至少半個周期再拉高。
解決方法:ps端發(fā)數(shù)的時候要多發(fā)一位,即數(shù)據(jù)位要發(fā)9位(2進制表示時)或者12位(16進制表示時),即可將前8位正確寫入寄存器中。(該方法僅針對自己的SPI IP核)
二、芯片初始化:
實現(xiàn)了FPGA與MPC2518FD的SPI通信后,我們可以對其寄存器進行讀寫配置了。接下來要做的是閱讀MPC2518FD的芯片手冊,找到需要配置的寄存器,將其功能配置為一個發(fā)送數(shù)據(jù),一個接收數(shù)據(jù)。芯片手冊上有每個寄存器具體到每一個位的功能,然而只看這些對于直接寫整個程序還是有一定難度的。于是我去微芯的官網(wǎng)www.microchip.com上下載了該芯片的開發(fā)手冊,以及底層驅(qū)動的C語言庫。
開發(fā)手冊上介紹了芯片初始化、發(fā)送數(shù)據(jù)、接收數(shù)據(jù)的步驟。如圖是初始化的例子

雖然手冊上給了初始化步驟和例程代碼,但是沒有具體告訴你需要配哪個寄存器以及每個位怎么配置,所以我們要看官網(wǎng)上下載的底層驅(qū)動的C語言庫,看懂他例程代碼底層具體配了哪個寄存器,每個位具體怎么配的,然后轉(zhuǎn)換成自己SPI讀寫的代碼。我們按手冊的步驟配置每個需要配置的寄存器,將兩個芯片初始化,并且將兩個寄存器C1FIFOCON1的TXEN位分別置1和0,其功能配置為一個發(fā)送數(shù)據(jù),一個接收數(shù)據(jù)。
三、數(shù)據(jù)的發(fā)送:
發(fā)送數(shù)據(jù)有兩種方式:FIFO發(fā)送和隊列發(fā)送,這里我們采用FIFO發(fā)送。不管哪種發(fā)送方式,都要將待發(fā)送的數(shù)據(jù)存入RAM里。RAM起始地址為0x400,待發(fā)送數(shù)據(jù)的地址為:

當然我們也可以自己計算數(shù)據(jù)的起始地址。如圖所示,RAM里存放數(shù)據(jù)的位置是根據(jù)TEF,TX Queue,F(xiàn)IFOn的順序排列的,TEF的起始地址永遠為0x400,TX Queue地址為0x400地址加上TEF中數(shù)據(jù)的字節(jié)數(shù),F(xiàn)IFO1的起始地址為0x400地址加上TEF和TX Queue中數(shù)據(jù)的字節(jié)數(shù)。我們這里只采用FIFO1發(fā)送數(shù)據(jù),所以我們配置C1CON寄存器,關(guān)閉TEF和TX Queue使能位,此時它們不再占用RAM的空間。所以我們用FIFO1發(fā)送數(shù)據(jù)的起始地址就是0x400。

找到了RAM的起始地址后,我們要將數(shù)據(jù)寫進RAM里,這里和寫寄存器不一樣,必須要一次性寫4或4的倍數(shù)個字節(jié),才能將數(shù)據(jù)寫入RAM里。我們對SPI底層讀寫代碼進行了修改,將第二行改為了(value>>32)&0xffffffff000fffff,成功的一次性寫和讀了4個字節(jié),將數(shù)據(jù)寫進了RAM并能成功讀出來。注意寫的時候也是要在4個字節(jié)后多寫一位才能寫進去。

接下來查看需要發(fā)送的數(shù)據(jù)的CAN幀格式,如圖所示:

這里我們發(fā)送標準幀,將SID配置為0x300。FDF位置1將幀類型選擇為CAN FD,置0則選擇為CAN 2.0 。DLC位配置為8,即令數(shù)據(jù)字節(jié)一共有8個。數(shù)據(jù)字節(jié)我們發(fā)送01-08的遞增數(shù)。這樣一個完整的標準幀就拼好了,我們將其寫到RAM里。

接來下將發(fā)送使能位:寄存器C1FIFOCON1的TXREQ位置1,完成數(shù)據(jù)發(fā)送。

四、數(shù)據(jù)的接收:
數(shù)據(jù)接收采用另一個芯片的FIFO1,也是先配置C1CON寄存器,關(guān)閉TEF和TX Queue使能位,此時它們不再占用RAM的空間。所以我們用FIFO1接收數(shù)據(jù)的起始地址也是0x400。
數(shù)據(jù)接收時,還需要配置一個過濾器,只接收指定ID的CAN報文。根據(jù)手冊例程,配置相應(yīng)寄存器,使能過濾器,只接收SID為0x300-0x30F的CAN報文。

接收時的CAN幀格式如圖所示

R2只有在CiFIFOCONm.RXTSEN置1時存在,這里我們置0,即R2不存在。所以我們發(fā)送的數(shù)據(jù)幀格式也符合接收的數(shù)據(jù)幀格式。
我們從RAM里4個字節(jié)一組讀發(fā)送的數(shù)據(jù),并存在rxd這個數(shù)組里。

五、調(diào)試與結(jié)果
我們將兩個ADM3057E芯片的CAN_H腳互連,CAN_L腳互連,CAN_GND腳互連,F(xiàn)PGA通過8個腳分別連兩個MCP2518芯片的SPI接口,并且共地。兩個MCP2518芯片的MCP25_*INT腳互連。給FPGA下載verilog程序,SDK里加載C語言程序。C語言要注意先初始化兩個芯片,再使能數(shù)據(jù)發(fā)送,最后進行數(shù)據(jù)讀取。

最終我們成功的在rxd數(shù)組里讀取到了發(fā)送的數(shù)據(jù)。

發(fā)送的數(shù)據(jù)

接收的數(shù)據(jù)
如圖所示,可見收到的數(shù)據(jù)和發(fā)送的數(shù)據(jù)是一樣的,成功實現(xiàn)了CAN協(xié)議數(shù)據(jù)一發(fā)一收的功能。
0755-83660119