1. 程式人生 > >嵌入式stm32f429上成功跑通主流Linux 4.13

嵌入式stm32f429上成功跑通主流Linux 4.13

樓主是個閒的蛋疼的大學僧,在高中和大學的社團、工作室中長期搞微控制器和嵌入式系統開發。剛接觸樹莓派時候是驚歎不已的,然後眼看香蕉派楊梅派橙子派荔枝派醋鱉派等等等等的“開源硬體”相繼登場,也是一陣的興奮,還有那些安卓電視棒路由器之類的亂七八糟的東西,也入手了不少板子來吃灰。
當然本業還是搞微控制器,之前也跑過st官方給103評估板的uclinux BSP包,可惜uclinux太大了,只能跑外擴flash上,fsmc的頻寬太低,一個ls就要等幾秒。不過當時覺得能跑Linux是微控制器的最大榮譽,也相當樂在其中。
兩年前偶然看到某部落格,說Linux核心支援stm32云云,Emcraft也猛然放出支援4.2核心的它自己的STM32 SOM的BSP。隨後翻了一下當時的主流核心發現,stm32_defconfig赫然在列,裝置樹啥的都有模有樣。想必裡面大有文章可做。

但是社群的玩法就不像基於BSP的二次開發那麼工具齊全了,東拼西湊起來的東西要不斷地試探,有時候人品不好,bug死活調不出來。大二時候好不容易將uboot在103的板子上跑通,加了nand flash之類的驅動,然後將uclinux 2.6的核心往死裡裁剪,網路、模組、sysfs、proc啥都不要了,裁到400k,並且將data段丟到外部flash中,核心總算塞進了內部flash。busybox也基本裁剪到只剩下hush,用romfs跑起來了。
在片內flash裡面xip,效能遠勝於fsmc掛的nor、sram,shell基本感覺不到延遲。。
後來就是考試、面試、比賽、實習,終於決定不浪費讀研資格,前些日子就到實驗室搬磚去了。不過我一直仍想弄出個像樣子的Linux電腦來,畢竟離它只有一步之遙了,也算是大學期間最有成就感的作品了。

等我真正開始弄的時候,最新的Linux核心是4.13,在對stm32的支援中,stm32f429是最為完整的,基本上啥都有了,USB、網絡卡、dcmi、ltdc都有了。值得一提的是,ltdc和dma2d的驅動在原始碼driver/gpu/drm/stm目錄下面是單獨的目錄,st真是志不在小。。。
stm32429-eval板子的配置是一個很好的例子,網絡卡、顯示屏、攝像頭、USB都寫了。stm32f429-disc1的支援也不錯。利用最新的arm-none-eabi工具鏈,預設配置下,編譯出來核心大小1.2MB左右,可以塞進I系列的片子裡。
按照defconfig的配置,核心起始地址0x08008000,前面還有32k的大小放bootloader。afboot是在github上開源的專門為stm32各種板子寫的Linux的bootloader,編譯出來的bin檔案只有2k左右。加上十幾kb的裝置樹,恰好放得下。
利用手上的discovery板,用elinux現成的rootfs,作為initramfs編譯進核心,進入hush可以執行一些指令,不過並沒有framebuffer,點點燈還是可以的。。。
 
emcraft只為discovery提供了uclinux的BSP,至於它的4.x系列的BSP,都只能用它那一套編譯系統,核心抽出來編譯是不行的。他們用的arm-uclinuxeabi工具鏈,gcc 4.4,也弄不了新版本的核心。
我開始構思自己的板子,stm32f429iit6晶片,帶上儘可能多的外設。用cubemx來幫忙安排引腳,主晶片,加上64MB的SDRAM、128MB的nand flash、rmii介面的網絡卡、兩個全速USB、ltdc顯示器介面、攝像頭、sdio,剩下的就當GPIO,接幾個led燈吧。
記憶體和flash都放主晶片背面,沒地方走等長線,不過線長也只有兩三釐米,時鐘也只有84MHz,不等長不做阻抗也罷orz
既然是“電腦”,就應該有個顯示器介面,之前玩
FPGA
時候有用電阻網路搭成簡易dac來做vga的例子,而ltdc就是並口rgb加上同步、使能訊號。dac加上同步訊號,這樣就可以偽裝成正經的vga了。
畫板子用的kicad。記住快捷鍵,原理圖封裝佈線都挺順手。佈線時候在OpenGL模式下面橫行,比ad流暢多了。
 

板子到手,焊接、測試。。值得一提的是電源引腳附近的104電容、vcap的2.2u電容一個也不能少,剛焊好主晶片、電源,就可以用jlink識別了,但是燒不了程式,電容焊齊了,就可以了。

 
 
 
 
 
 
然後就開始了漫長的裁剪和驅動搬磚了。。。
剛開始時,先移植一個能跑的uboot去測試記憶體、flash和網路。主頻設為168MHz。之所以不將主頻拉到180MHz,就是因為USB需要48M的時鐘,不能整除180。在84MHz的時鐘頻率下,cas設為2,記憶體順序讀寫速度大約能到70MB每秒。nand flash讀寫就有點慢了。至於網絡卡,焊好了,而且主機不用WiFi的話,tftp是又快又準的。
剛加上網路,核心就猛增到2MB。。。為了測通核心的驅動,核心只能先放在SDRAM上跑吧,到時候弄核心模組再說。奇怪的是,uboot的tftp好好的,核心的網絡卡初始化就死了。單步調、看暫存器,折騰了許久,發現原始碼裡一個暫存器寫錯了,以至於mii介面的沒問題,rmii的就不行,怪不得eval板子上能用網絡卡。。
網絡卡初始化時候沒有使能phy晶片。。。
預設配置是tickless核心,這會導致網絡卡初始化時候卡死。。。
yaffs的補丁打進去之後編譯不過,後來發現是新版核心為解決y2038千年蟲問題而去掉了一些介面。。。
USB暫存器配置順序不對,導致初始化失敗。。。
因為在SDRAM上跑的核心效能太低了,USB外接的裝置都跑的比stm32快,以至於u盤鍵盤什麼的幾乎總是列舉失敗。。。
ltdc驅動忘了註冊時鐘,導致核心最後將ltdc關掉,以至於沒有顯示。。。
sdio驅動更新了,資料結構變了,然後用不了了。。。
攝像頭初始化時候沒有使能。。。
。。。
驅動搬好了,核心就爆到快5MB了,然後要想辦法裁剪到2MB以下,而且核心的網路是不能模組化的。。。
核心載入模組失敗,後來發現是gcc的引數沒用長跳轉,無法從0x08000000的片內flash跳到0x80000000的SDRAM那裡。。。
還有日常hardfault:記憶體沒調好,hardfault;裝置樹寫錯了,hardfault;還沒進start_kernel(),hardfault。。。
我記得的最弔詭的hardfault是,自己編譯的gcc6.4的arm-uclinuxeabi工具鏈,短跳轉的地址算錯了,翻了binutils的原始碼發現新版的as為了支援armv8-m的cpu改了一些東西,導致往前跳的地址多了1,導致PC值為偶數就進入arm模式,然後報用法錯誤,上訪hardfault。。。
也碰到過幾次imprecise的bus fault,有的是因為寫訪問了片內flash,有的是外設暫存器沒設好,有的發生在初始化中斷向量表時候。。。
這一堆亂七八糟的問題解決了,終於,Linux跑起來了。。。
之前在SDRAM裡跑,BogoMIPS是9;在片內flash裡跑,BogoMIPS暴漲到110。。。
 
更多視訊:www.makeru.com.cn/?t=12  
不過回味起來,這隻能說業餘時間弄的玩具。可以說如今搞自動化的都搞slam,搞計算機的都搞ai,搞系統開發這玩意的早就不那麼吃香了罷。