LWIP
今天要談的不是LWIP協議棧的內容,只是簡單談談關於STM32F407快速使用LWIP做網絡通訊的一些經歷。
我是一個網絡小白,對網絡知識一竅不通,僅僅是知道有IP地址、網關這玩意,也從來沒有做過嵌入式網絡這塊內容,那么要如何在2周內實現網絡通訊呢,我要實現的功能很簡單,只有幾十字節的數據量,而且發送不頻繁,但是要做到隨時拔插網線,隨時連接網絡,網絡中斷能盡快連接。
首先,LWIP已經被廣泛應用,在網上有很多教程,我個人偏愛上淘寶找,因為在淘寶找對應的開發板,可以快速地驗證驅動程序是否能用。我使用的是原子哥的探索者開發板,正點原子的配套教程資料非常齊全,我學stm32也是一路跟着他們的教程走過來的,真心感謝正點原子對嵌入式教育的貢獻。這次的實驗是把開發板作為TCP的客戶端,直接把例程燒到對應的開發板上,非常完美地與服務器通訊了,驗證完畢,接下來不要急着去看程序,先去看人家錄制的教學視頻。第一次看視頻的時候,不急於求成,快速瀏覽一邊,知道個大致的框架,如果仔細的看每一個知識點,保證你中途就睡着了。看了第一遍視頻后,了解了整個硬件流程,就是STM32F407自帶了一個MAC介質層,具體是什么,我也不知道暫時也不用知道,只需要知道LWIP協議棧需要通過MAC層來讀取數據,而MAC層的數據是通過幾根線,用MII或者RMII協議來從PHY層讀取數據,PHY又是什么?同樣,不理會它,只要知道這次用的PHY芯片型號叫做LAN8720,聽起來這么牛逼的芯片當然要配置一下,這個芯片是通過2根線叫SMI接口與STM32通訊。再然后這個PHY層的數據就是從水晶頭(帶變壓器)那里得來的了。大致流程就是這樣。
整理了數據流向后,開始分模塊去學習,最開始程序是通過LWIP協議棧讀取,這個協議棧是瑞典計算機科學院(SICS)的Adam Dunkels 開發的一個小型開源的TCP/IP協議棧,驅動呢就是去人家官網下。然后LWIP怎么操作MAC層,這個是STM32的東西,自然是去ST官網下載MAC的驅動,而操作PHY是通過SMI接口的,這個國際通用的接口ST給出來的驅動有了。到這里用到的文件大致就清楚了。
接下來可以去看程序了,認真的再回去看視頻,仔細分析怎么移植這兩個驅動文件,不需要明白文件的內容,但必須得知道哪些文件是屬於哪個驅動的,這個可以慢慢品味兩三天了。了解驅動移植之后就從main函數開始跟蹤,去查看怎么實現LWIP和各種硬件的初始化,還有怎么發數據接收數據。
最后開始改造工程,原子哥的例程里,如果上電沒有插網線,程序就會死掉,先解決這個最大的問題,如圖1-1,這是源程序,初始化一直在死循環,所以把死循環去掉就好。
圖1-1
程序是不死了,但是初始化的過程好久啊,那得改一下官方驅動了,如圖1-2,把LAN8720初始化等待時間改小了,如圖1-3,把LWIP的DHCP等待時間改小了。
圖1-2
圖1-3
現在速度快了,但是還是不能上電后隨時插網線隨時上網,后來發現網上說的讀取LAN8720的BSR寄存器中的bit2位或者bit4位可以檢測網線,那都是鬼扯,我每個位都試過了,發現是bit1位叫jabber檢測才有用。通過檢測這個可以實現網線拔插的監控,如圖1-4是jabber位讀取函數。
圖1-4
可以正常檢測了,但發現連不上網,這個就一言難盡了,需要注意的是原子哥使用的是動態內存管理,有申請就要有釋放,可以把動態內存換為靜態的,但是要改的地方有點多,也就不想去搞它了,如圖1-5,把一直需要用的兩個內存申請放外面,不再釋放和申請,LWIP內核就初始化一次,因為重復初始化鬼知道它會鬧出什么事來,因為LWIP里面也有使用動態內存。
圖1-5
最后,tcp_client_open函數就是初始化成功后進去申請一個PCB塊的,斷網就要釋放PCB塊太麻煩了,所以我這里把這部分改成了靜態的。斷網之后其實只要重新申請一個PCB塊就能連接上,但是考慮到拔網線很長時間或者重置了路由器,PCB塊可能連接不上,所以斷網后直接退出tcp_client_open函數,重新進行初始化和DHCP獲取。因為我不懂DHCP和LWIP內核,所以經常重連失敗,最后瞎摸出幾個函數,如圖1-6。斷網后要斷開PCB塊的連接,停止DHCP,移除lwip_netif網卡。我也不知道是否正確,這是試出來沒有問題的,缺乏理論依據,治標不治本,到最后的最后要去學習一下網絡知識,深入學習LWIP內核才能把網絡通訊這塊靈活運用。
圖1-6
以上就是快速上手STM32F407的LWIP網絡通訊,首先能粗糙地運用,后面才會有信心去優化,去做得更好,不要一次就最求完美。有空的話就去圖書館看看原子哥推薦的那本書《嵌入式網絡那些事:LWIP協議深度剖析與實戰演練》作者朱升林。