新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 在mini2440上面搞定CC2500物理層驅動

        在mini2440上面搞定CC2500物理層驅動

        作者: 時間:2016-11-19 來源:網絡 收藏
        1. 寫在前面

        最近基本搞定了CC2500在linux下面的驅動,在這個過程中遇到了好多問題,特此總結出來和大家分享。但是需要注意的事情是:
        第一,本文不負責程序的具體講解,諸如每一行程序都講什么:這個在程序的里面有注釋。本篇文章更側重于從整體結構上讓大家對于linux下的CC2500DE驅動有一個整體的了解,如果到時候需要深入研究的時候,再來看具體的代碼;
        第二,很多師弟師妹沒有習慣在linux下編程,或曰,在操作系統下面寫程序;并且,對于本專業的東西理解并不扎實。但是,文章中不可能就每一個涉及到的概念都大加講解。因此,這篇文章還是需要有一些基礎才能來閱讀的,如果遇到什么不明白的地方,請及時來問我,或者跟帖,或者自己查資料。畢竟,這個驅動花費了我半個多月的時間,其中遇到的問題,不可能在一篇文章中就講得清清楚楚。


        1. 背景知識

        如果大家看過實驗室的WSN方面的程序,可能會被其中的架構搞得天昏地暗。這里,簡單的幫助大家把實驗室的WSN的軟件、硬件方面捋一捋。
        說到軟件,就不能不說硬件。我們的節點由兩部分組成,一個是單片機,一個是CC2500的射頻模塊。射頻模塊通過SPI接口和單片機進行通信。除了SPI模塊用到的4條線,實際上CC2500還需要告訴單片機“我接收到一個數據”,這個地方CC2500可以通過配置GDO來實現。我們這里采用的CC2500的GDO0作為單片機的一個外部中斷,當接收到數據的時候,GDO0就會變為低電平,然后觸發CC2500的中斷,從而接收數據。
        那么,CC2500究竟是如何來進行數據發送、接收的呢?其實很簡單。如果大家稍微用過一點可以控制的芯片就會知道,很多芯片內部都有寄存器,CC2500之所以能夠完成發送、接收的功能,就是通過配置寄存器來完成的。比較重要的配置有信道、波特率、信號強度等等,另外,CC2500還有64bytes的RXFIFO和64bytes的TXFIFO,他們的作用就是用來發送和接收。當配置CC2500結束之后,如果用來發送,那么就把數據放在TXFIFO里面,然后把CC2500的狀態變為發射狀態,數據就自動發送出去了。同樣的道理,當RXFIFO里面接收到了數據之后,CC2500就會如前所說,發出一個中斷,通知單片機來讀取數據。
        單片機通過SPI接口讀出了CC2500中的數據,就需要進行簡單的處理了。我們的節點是遵循802.15.4協議的,如果有興趣,大家可以去看一看這個協議的內容。對于我們來說,比較重要的就是幀的結構。下面這個是物理層幀的結構:
        字節:4
        1
        1
        可變
        先導碼
        幀定界符

        幀長度(7位)

        保留位(1位)
        負載內容

        同步頭

        PHY頭

        PHY負載

        簡單的講,因為是無線通信,沒有一個時鐘的存在,因此本質上所有的無線通信都是一個異步的通信。那么,就需要發送和接收的雙方首先對數據進行同步——這個就是同步頭的作用。隨后的是PHY的頭,很簡單,就是一個長度。換句話說,每個幀不能夠超過2的8次方減一個數據(127個)。隨后就是負載的內容了,簡單吧?另外,由于CC2500是一個802.15.4兼容的芯片,這一部分內容都已經固化在芯片里面了,像同步頭這種東西,都是芯片幫我們完成(當然也可以自行配置)。我們只需要把寫入的數據大小和數據內容寫入即可。
        雖然簡單,但是還有一個問題:每次從CC2500中讀取了數據,存放到哪里呢?有的同學可能想的比較簡單,比如建立一個大數組,收到多少個數,放在里面就行了。但是,這樣就會遇到問題:如果收到了兩個包,上層來不及處理怎么辦?建立兩個大數組?更多的包呢?當然,我們可以通過建立好多個數組來解決這個問題。但是,從效率上講,這個是非常笨的一個辦法。因此,我們建立了一個環形緩沖區PHY_RX_BUFFER,來解決這個問題。環形緩沖區的具體原理不過多涉及,可以自行百度。
        另外一個問題就是,如果我們從CC2500中接收到了數據,那么應該怎樣才能告訴上層來進行處理呢?這里就要用到操作系統的消息機制了。如果確定接收到了一個數據,那么就給上層發送一個消息,來通知上層。上層接收到這個消息,就會知道接收到了數據。
        當從CC2500讀取到了數據,因為物理層沒有什么東西,我們就直接通知MAC層來處理數據。MAC層的結構如下:
        字節:2
        1
        0/2
        0/2/8
        0/2
        0/2/8
        可變
        2
        幀控制域
        序列號
        目的PAN標示符
        目的地址
        源PAN標示符
        源地址
        幀負載
        FCS
        地址域
        MAC幀頭
        MAC負載
        MFR

        具體內容可以參見老師的《無線傳感器網絡技術與工程應用》這本書,這里不再詳細的講,大概內容就是,會有一系列的幀頭,然后是幀數據,最后有校驗。而我們最關心的就是幀的內容。但是,幀頭也比較麻煩,因此我們需要首先對幀頭進行處理,把數據給“剝離”出來,這也是基本上所有的協議棧解析協議的方法。


        1. 硬件結構

        硬件上,我們采用的是mini2440開發板,和實驗室的CC2500節點(把單片機焊掉,然后把mini2440的相應管腳接到上面)。


        Mini2440方面,我們用的是CON8這個引腳,具體連線如下:
        EINT8對應S3C2440的GPG0引腳,連接到了CC2500的GDO2
        EINT11對應S3C2440的GPG3引腳,連接到了CC2500的CSN
        EINT13對應S3C2440的GPG5引腳,連接到了CC2500的SO
        EINT14對應S3C2440的GPG6引腳,連接到了CC2500的SI
        EINT15對應S3C2440的GPG7引腳,連接到了CC2500的CLK
        EINT19對應S3C2440的GPG11引腳,連接到了CC2500的GDO0
        除此之外,還有3.3V電源和GND


        1. Linux下驅動編寫

        為什么要用驅動呢?簡單的說,就是為了在linux下完成用戶空間和內核空間的交互。本質上,驅動就是完成了兩件事情:第一,初始化SPI接口,并且通過SPI和CC2500完成通信。第二,完成讀寫函數,read和write,通過讀寫函數的接口來對CC2500進行操作。
        附件里面有幾個文件,這里簡單講解一下:
        Common.h主要是包含了很多linux的頭文件,并且對一些數據類型做了定義
        CC2500.h里面主要是對CC2500的寄存器做了一些定義,沒啥東西
        Driver.h主要是定義了很多和CC2500進行通信,并且利用CC2500進行發送和接收的內容
        Phy.h主要是完成了一些諸如信道設定、通信速率等功能,并且把CC2500里的數據讀到環形緩沖區里面
        CC2500.c這個就是完成設備注冊、讀寫函數、iocontrol等功能
        這樣有了一個整體的把握之后,不用看很多代碼,學會使用就好。


        1. 驅動接口使用

        那么,這個驅動怎樣使用呢?主要是通過read/write/ioctl三個接口來實現的。
        在應用程序中read/dev/CC2500這個文件,如果有數據,會返回相應的數據。其中,返回的數據中第一個字節為數據的長度(不包括該字節本身),后面為相應的數據。
        如果是寫文件的話,只需要向/dev/CC2500中寫入相應的數據即可。寫入的時候需要注意,第一個字節同樣為數據長度(不包括該字節本身),后面跟相應的數據。當寫入的字節合適的時候,驅動會自動執行發送函數。如果寫入的字節數量和寫入的數據第一個字節不匹配的時候,會返回錯誤。
        ioctl主要有這樣幾種命令:


        CC2500_IOC_PHY_DETECT_STATUS
        表示將CC2500的狀態變為RX
        CC2500_IOC_PHY_GET_BAUDRATE
        讀取CC2500的波特率,返回的是1,2,3,4,分別是2.4k,10k,250k,500k的波特率
        CC2500_IOC_PHY_SET_BAUDRATE
        設定CC2500的波特率,后面的參數是1,2,3,4,分別是2.4k,10k,250k,500k的波特率
        CC2500_IOC_PHY_GET_TXPOWER
        獲取發送功率,返回的是在發送功率表{0x00, 0x50, 0x44, 0xC0, 0x84, 0x81, 0x46, 0x93, 0x55, 0x8D, 0xC6,0x97, 0x6E, 0x7F, 0xA9, 0xBB, 0xFE, 0xFF }中的數組下標
        CC2500_IOC_PHY_SET_TXPOWER
        設定發送功率,參數的是在發送功率表{0x00, 0x50, 0x44, 0xC0, 0x84, 0x81, 0x46, 0x93, 0x55, 0x8D, 0xC6,0x97, 0x6E, 0x7F, 0xA9, 0xBB, 0xFE, 0xFF }中的數組下標
        CC2500_IOC_PHY_GET_CHANNEL
        獲取頻段,參數是頻段表{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,0xB0, 0xC0, 0xD0, 0xE0, 0xF0 }中的數組下標
        CC2500_IOC_PHY_SET_CHANNEL
        設定頻段,參數是頻段表{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,0xB0, 0xC0, 0xD0, 0xE0, 0xF0 }中的數組下標


        1. 應用層程序編寫

        這里的應用層主要是將mac層實現了。其實,mac層的作用也很簡單,主要是對要發送的包進行封裝,接收回來的包進行包的解析。這一部分的內容還不全面,僅僅是將原來的程序移植過來,還有很多需要改動的地方,有待補充。因此,這里只是提供源代碼,具體的說明請參見程序內部


        1. 如何配置內核文件

        1首先修改/opt/FriendlyARM/mini2440/linux-2.6.32.2/drivers/char/Kconfig
        加入如下幾句話:
        config CC2500_DRIVER


        tristate "CC2500 driverfor FriendlyARM Mini2440 development boards"


        depends on MACH_MINI2440


        default m if MACH_MINI2440


        help


        this is CC2500 driver forFriendlyARM Mini2440 development boards




        2修改Makefile,讓CC2500的驅動可以編譯。
        加入如下幾句話:


        obj-$(CONFIG_CC2500_DRIVER) +=CC2500inuse.o


        CC2500inuse-objs :=./CC2500.in_use/cc2500.o ./CC2500.in_use/phy.o./CC2500.in_use/driver.o


        其中,CONFIG_CC2500_DRIVER需要和Kconfig中的configCC2500_DRIVER
        保持一致。
        CC2500inuse-objs這句話,意思是CC2500inuse.ko是由哪幾個文件組成的。這樣就實現了模塊化的處理。
        需要注意的是,CC2500inuse-objs和冒號之間需要有個空格,不然會出錯誤。這個地方我搞了好久。
        具體的Makefile的格式也可以參考這兩篇文章:
        http://blog.csdn.net/tommy_wxie/article/details/7282463
        http://hi.baidu.com/wjq_qust/blog/item/97ddbdfdfb2e541309244d30.html


        1. 調試過程中的一些問題

        CC2500驅動調試的過程中,遇到的一些問題
        第一,在調試的過程中,發現板子和2500沒有辦法進行通信。一開始懷疑是2500芯片的問題,后來確認2500芯片沒有問題之后,用示波器看了一下波形,發現SPI引腳上沒有輸出。進而發現,對SPI寄存器進行讀寫的時候,無論寫入是什么,讀出的都是0。后來發現,原來是PCLK(也就是SPI模塊的時鐘)沒有使能,囧。設置了寄存器之后,問題就解決了。
        第二,CC2500驅動沒有辦法自動在/dev/目錄下面創建節點。這個問題可以參考下面幾篇文章:
        http://blog.csdn.net/cjok376240497/article/details/6848536
        整體來說,創建節點的工作是這樣的:
        我們通過udev來創建節點。但是,udev是應用層的東東,不要試圖在內核的配置選項里找到它;加入對udev的支持很簡單,只要在驅動初始化的代碼里調用class_create為該設備創建一個class,再為每個設備調用class_device_create創建對應的設備。
        換句話說,首先要為每一個設備創建一個類。然后用這個類去申請一個設備節點。
        第三,在調試的過程中,發現只要一啟動CC2500,那么液晶屏就熄滅了。調試了半天也沒有找到原因。
        最后發現,在配置S3C2440中GPGCON寄存器的時候,對寄存器直接進行了覆蓋性的修改;而該寄存器還管理著LCD的電源...于是,對寄存器進行覆蓋性修改的時候,悲劇了...
        總結一下吧,在linux下2500驅動編寫的過程中,如果涉及到寄存器級別的操作,和單片機一樣,必須十分注意各個模塊之間的關系,以及相關模塊的寄存器配置,不要認為linux會全部給你配好!


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 岑巩县| 古交市| 涡阳县| 繁峙县| 中超| 黎平县| 伊川县| 高雄市| 监利县| 阳城县| 鹤岗市| 宜阳县| 宁明县| 文山县| 银川市| 和政县| 维西| 昌吉市| 盖州市| 海城市| 灵璧县| 大连市| 喀喇| 墨竹工卡县| 密山市| 乐亭县| 温泉县| 达州市| 溧阳市| 长顺县| 富阳市| 谢通门县| 龙海市| 三都| 珠海市| 纳雍县| 大厂| 伊宁县| 花莲市| 赣榆县| 绥滨县|