imx6芯片通过EIM总线外扩多路sja1000 CAN控制器
有時(shí)會(huì)需要擴(kuò)展多個(gè)CAN接口,在CAN設(shè)備比較多的時(shí)候作分組控制。這里使用imx6q芯片,它本身已經(jīng)自帶了兩個(gè)CAN接口,如果需再擴(kuò)展4個(gè)接口,就要想想辦法了。sja1000是一個(gè)經(jīng)典的CAN控制器,穩(wěn)定可靠,由于它在業(yè)界使用方案比較成熟,用它來擴(kuò)展再好不過。imx6q作為一款性能強(qiáng)大的處理器,擴(kuò)展sja1000這種相對慢速的芯片,著實(shí)有點(diǎn)屈才。可是沒辦法,項(xiàng)目需要,就像PCIE轉(zhuǎn)ISA,或者USB轉(zhuǎn)PCIE一樣,效率并不是最重要的,硬件的兼容性和軟件的易維護(hù)性同樣重要。
這篇文檔分硬件部分和軟件部分來介紹下imx6q如何來與sja1000芯片組合應(yīng)用起來,主要實(shí)現(xiàn)了通過imx6芯片的eim總線外擴(kuò)4個(gè)sja1000 can控制器的功能。
一、硬件部分
首先來一張sja1000芯片的經(jīng)典電路,是與8051單片機(jī)配合使用的。
看到這張圖,是不是首先就想到了8051單片機(jī)的P0腳,還記得當(dāng)時(shí)剛剛接觸51單片機(jī)時(shí),還會(huì)對P0與P1/P2/P3引腳的特性不同有些困惑。P0腳是3態(tài)的,可以應(yīng)用在地址/數(shù)據(jù)總線。51單片機(jī)就是通過P0接口來擴(kuò)展些SRAM、ROM啥的。這個(gè)電路圖中,就是一個(gè)典型的外擴(kuò)SRAM的接法:P0做地址/數(shù)據(jù)總線,P2.7獨(dú)立GPIO控制CS腳(CS腳為低SJA1000芯片才工作),ALE/RO/WE是讀寫控制信號,INT中斷腳接到P3.2接口上。從而可以看出,sja1000芯片留給外部的接口就是一個(gè)SRAM接口(CPU通過總線讀寫sja1000芯片的寄存器來控制),只要CPU有能夠擴(kuò)展SRAM的總線接口,那么就能外擴(kuò)sja1000芯片。那么imx6芯片有沒有類似的總線呢?
答案是肯定的,imx6系列芯片功能豐富,性能爆表,區(qū)區(qū)一個(gè)SRAM總線接口,怎會(huì)沒有。imx6芯片帶有WEIM接口,支持16/32bit的地址/數(shù)據(jù)總線混合模式,不過地址線最高為27bit,這個(gè)接口可靈活配置地址/數(shù)據(jù)端口,支持外接SRAM、NorFalsh和OneNAND等設(shè)備,先來看一張典型的imx6芯片的EIM接口圖。
EIM總線地址總線引腳范圍為EIM_DA0_15、EIM_A16_26,數(shù)據(jù)總線引腳范圍為EIM_DA0_15、EIM_D16_31(圖中有些引腳沒有引出)。sja1000與之相連,可以是地址/數(shù)據(jù)總線復(fù)用的方式,也可以是地址總線與數(shù)據(jù)總線分離的方式(通過配置地址和數(shù)據(jù)引腳端口)。從電路簡潔性上講,當(dāng)然采用復(fù)用的方式,就像51單片機(jī)的P0接口一樣。有些芯片的SRAM接口并不支持地址/數(shù)據(jù)總線復(fù)用,與sja1000芯片相接時(shí)需要在電路上加邏輯器件,這個(gè)在另一篇文檔中再寫吧。
imx6芯片手冊中指出,EIM總線只支持16/32bit的復(fù)用方式,通過EIM_CSnGCR1寄存器來配置,如下圖。
EIM總線與sja1000這種8位的SRAM接口類型芯片相連,用16bit的multiplexing模式搓搓有余。可以16位的總線來訪問8位總線存儲(chǔ)器時(shí),會(huì)有地址無法對齊的尷尬情況。舉個(gè)例子說,16位總線讀地址0x0000時(shí)(忽略基地址),read_byte()讀的是D0_7這一組的電平值,讀地址0x0001時(shí),read_byte(),讀的是D8_15這一組的電平值,反之寫操作也是一樣。那么16位總線與sja1000相連時(shí),如果只用DA0_7腳,必然導(dǎo)致雖偶地址訪問正常,奇地址訪問不到的情況。這個(gè)也好解決,我們用DA1_8引腳就可以了。整個(gè)連接起來如下圖的樣子。
其中EIM_nOE、EIM_nWE和EIM_LBA與51單片機(jī)的WR、RD和ALE類似,DA1_8為地址/數(shù)據(jù)復(fù)用總線的0_7位,DA9_12則用來當(dāng)4個(gè)CS信號線用(接了4片SJA1000芯片),EIM總線有CS0_3,不過被其它功能引腳復(fù)用占了,這里就只能這么干了。至于RST和INT線,隨便找?guī)讉€(gè)GPIO就行。
接下來簡單分析下硬件時(shí)序,先看sja1000芯片的讀時(shí)序。
從圖中可以看出,讀操作周期中,主機(jī)端先給出要讀的地址(AD0_7上產(chǎn)生),然后拉低ALE信號,提示sja1000設(shè)備進(jìn)行地址鎖存,拉低CS信號,使能sja1000設(shè)備,最后拉低RD信號,釋放地址/數(shù)據(jù)總線。sja1000設(shè)備在t_RLQV時(shí)間內(nèi)準(zhǔn)備好數(shù)據(jù),然后寫在數(shù)據(jù)總線上。主機(jī)在t_W/R時(shí)間后,拉高RD信號,讀取地址/總線上的數(shù)據(jù),拉高CS線,完成一個(gè)讀操作周期。整個(gè)讀操作周期中WR信號為高。寫操作周期與之類似,如下圖所示。
同樣,主機(jī)端準(zhǔn)備好地址信號,拉低ALE信號、CS信號,然后拉低WR信號,提示sja1000設(shè)備將進(jìn)行寫操作。之后主機(jī)端在地址/總線上寫數(shù)據(jù)信號,等待t_DVWH后,拉高WR信號線,在t_WHDX時(shí)間后釋放總線。sja100設(shè)備在拉高WR信號的時(shí)候進(jìn)行接收數(shù)據(jù)。
二、軟件部分
這里使用的是3.14.28版本linux內(nèi)核,由于支持設(shè)備樹,為驅(qū)動(dòng)程序的編寫帶來了很多便利。首先修改dts文件,使能WEIM總線,并配置需要用到的功能引腳、GPIO、中斷引腳。
weim總線中配置的引腳有 EIM_DA0_15(只用到DA1_12)、EIM_OE、EIM_RW、EIM_LBA、EIM_CS0(cs線由高位地址線取代,這里無用),sja1000驅(qū)動(dòng)中添加了四個(gè)中斷引腳(對應(yīng)4個(gè)sja1000芯片)、4個(gè)LED gpio(CAN通信指示燈用)、RST GPIO(產(chǎn)生硬復(fù)位信號,一般不用)。接下來看sja1000驅(qū)動(dòng)需要添加的dts文件內(nèi)容。
/ {sja1000@08001C00 {compatible = "weim,sja1000";reg = <0x08001C00 0x1FF>;nxp,external-clock-frequency = <16000000>;nxp,tx-output-config = <0x16>;nxp,no-comparator-bypass;interrupt-parent = <&gpio4>;interrupts = <16 0>;int-gpios = <&gpio4 16 0>;rst-gpios = <&gpio2 28 0>;led-gpios = <&gpio4 26 0>;};sja1000@08001A00 {compatible = "weim,sja1000";reg = <0x08001A00 0x1FF>;nxp,external-clock-frequency = <16000000>;nxp,tx-output-config = <0x16>;nxp,no-comparator-bypass;interrupt-parent = <&gpio4>;interrupts = <17 0>;int-gpios = <&gpio4 17 0>;led-gpios = <&gpio4 27 0>;};sja1000@08001600 {compatible = "weim,sja1000";reg = <0x08001600 0x1FF>;nxp,external-clock-frequency = <16000000>;nxp,tx-output-config = <0x16>;nxp,no-comparator-bypass;interrupt-parent = <&gpio4>;interrupts = <18 0>;int-gpios = <&gpio4 18 0>;led-gpios = <&gpio4 28 0>;};sja1000@08000E00 {compatible = "weim,sja1000";reg = <0x08000E00 0x1FF>;nxp,external-clock-frequency = <16000000>;nxp,tx-output-config = <0x16>;nxp,no-comparator-bypass;interrupt-parent = <&gpio4>;interrupts = <19 0>;int-gpios = <&gpio4 19 0>;led-gpios = <&gpio4 29 0>;}; };四片sja1000芯片的基地址計(jì)算方式:weim總線的基地址為0x08000000,第一片sja1000芯片讀寫時(shí)DA1_8 對應(yīng)地址/數(shù)據(jù)總線的D0_7,地址范圍為 0x08000000~0x080001FF(忽略DA0的信號),由于DA9_12充當(dāng)CS信號,讀寫第一片sja1000芯片時(shí),需要保持DA9為0、DA10為1、DA11為1、DA12為1,從而第一片sja1000芯片的基地址為0x08001C00。同理,第二三四片sja1000芯片的基地址分別為 0x08001A00 、0x08001600、0x08000E00。
dts資源配置好后,需要在對應(yīng)的驅(qū)動(dòng)程序中正確引用。linux內(nèi)核中已經(jīng)有了sja1000_platform驅(qū)動(dòng)(位于driver/net/can/sja1000目錄下),直接在它的基礎(chǔ)上修改下就行。
1. of_device_id添加
這里是為了驅(qū)動(dòng)能與dts文件中“weim,sja1000”資源匹配。
2. 初始化weim總線
這里通過修改寄存器完成,程序在加載驅(qū)動(dòng)程序時(shí)調(diào)用,主要配置weim時(shí)鐘、中斷、地址/數(shù)據(jù)總線端口、時(shí)序控制等,詳見imx6數(shù)據(jù)手冊。
3、probe函數(shù)修改
probe函數(shù)中主要針對添加了rst引腳和led引腳,其它未做改變。可以看到,probe函數(shù)中,申請了sja1000設(shè)備的總線資源,根據(jù)GPIO中斷引腳號申請了終端,然后將platform設(shè)備注冊到sja1000驅(qū)動(dòng)中。
4. read/write 地址偏移
由于使用的是DA1_8引腳(DA9_12充當(dāng)了CS信號),其讀寫地址肯定不能直接在基地址上了。修改sja100_platform中的write8和read8函數(shù),完成讀寫的地址偏移。
完整的驅(qū)動(dòng)程序見https://gitee.com/westlor/imx6_sja1000。
如有錯(cuò)誤請指正。
總結(jié)
以上是生活随笔為你收集整理的imx6芯片通过EIM总线外扩多路sja1000 CAN控制器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最强的志愿军战俘:炸掉一飞机美军后逃离
- 下一篇: 液晶显示屏行业信息汇总