Linux中有很多編程思想可以學(xué)習(xí),很多大佬把這些思想、機制運用到單片機的編程上。
下文,在STM32上模擬Linux kernel自動初始化流程。
通常我們寫程序都是按照這個套路,一個函數(shù)一個函數(shù)按照順序邏輯一個一個的執(zhí)行下去。
如果邏輯非常復(fù)雜,涉及的模塊比較多,那么這種順序執(zhí)行的代碼就會比較臃腫,各模塊耦合非常緊密。Linux kernel 中,有各種外設(shè)驅(qū)動,想按照一個順序邏輯執(zhí)行下去,幾乎是不可能的。
而kenrel 代碼能有這么大的代碼量,大而不亂,把各層次,各模塊有效的分離,而大量的代碼又有邏輯的組織在一起,和這個initcall 有至關(guān)重要的作用。
通過模仿這種方式,最后把圖片中main函數(shù)代碼清空,分離這種邏輯,又實現(xiàn)同樣的功能。
如何能實現(xiàn)這樣的功能了,需要一些背景知識:
1,程序代碼的組織
2,鏈接腳本相關(guān)的知識。
3,函數(shù)指針的應(yīng)用。
代碼的組織,如圖片需要知道變量a,b及函數(shù)指針 f,f2是存放在程序的哪些段中,可以去看一下這篇stm32 啟動代碼 實現(xiàn)|C語言,上述的a,f都是存放在bss 段中,b,f2是存放在data段中,因為已經(jīng)給定了初始值,而實現(xiàn)這個intcall會把需要自動初始化的數(shù)據(jù)放到一個自定義的段中去,如.initcall。
如何放到特定的段中了,就需要用到了attribute((section)) 關(guān)鍵字來改變的數(shù)據(jù)存放段了。
目前的程序編譯出來用到了這些個段,除了.isr_vector也是添加的,其他都是編譯器默認(rèn)的。
先加段代碼:
當(dāng)然這還不夠,還需要告訴連接器(LD) 要把 .initcall 段也鏈接到程序中,所以也需要這段修改。
這段按8字節(jié)對齊,定義兩個全局變量,及按0-5順序的鏈接這些數(shù)據(jù),這樣的兩處修改,再來看一下程序各段的情況。
如圖片:
已經(jīng)多出紅色框框為.initcalls段,這段總共是8個字節(jié),從0x80005a8除開始。
在來看一下具體的這一段的情況,用readelf 工具。
和上面的size工具是匹配的,而綠色框框的地址就是SystemInit(0x08000231,小端模式。)
所以通過attribute及修改鏈接腳本,就把函數(shù)指針變量放到了.initcall 段中。
那么如何來調(diào)用這個函數(shù)了,和之前的初始化data段數(shù)據(jù)類似,遍歷這個段,然后取出這個函數(shù)地址,然后強制把段中的地址,轉(zhuǎn)成函數(shù)指針,再直接調(diào)用即可。
實現(xiàn)的這張圖片,就是從.initcall段中取出函數(shù)地址,然后直接調(diào)用,非常容易把函數(shù)的地址及這個函數(shù)指針變量的地址搞混。
代碼這么修改,需要自動初始化函數(shù)的確是可以調(diào)到了,但是每次都寫這么長長的一段static initcall_t __ attribute__(( __ used__,__ section__(".initcall.0.init"))),就是不舒服. linux kernel中通過宏來修改。
這個也一樣。
添加 按照程序邏輯順序執(zhí)行的一些宏
0,low_level_init 比如放始化系統(tǒng)基本時鐘
1,arch_init 比如放CPU架構(gòu)d如初始化NVIC的一些初始化。
2,dev_init 外設(shè)模塊初始化,比 i2c, flash, spi等。
3,board_init 做具體硬件板及的一些設(shè)置。
4,os_init 操作系統(tǒng)的一些設(shè)置如,文件系統(tǒng),網(wǎng)絡(luò)協(xié)議棧等。
5,app_init 最后跑用戶程序。
把自己的程序也做一下修改,用宏代替。這樣子掉調(diào)用do_initcalls 就會按照0,1-到5的順序執(zhí)行了。
最后在來看一下initcall 段:
這樣只要在需要自動初始化函數(shù)加上類似于dev_init(),app_init() 就可以了,就會自動調(diào)用到,而不需要main 函數(shù)中一個一個的順序執(zhí)行。
比如i2c控制的初始化放到dev_init 中,下面掛了很多i2c的從設(shè)備,只要分別給個從設(shè)備用app_init 初始化就行,即使來了一個新的,也用這app_init初始化就行,也不需要更改原來的,高度的分離模塊間的耦合度。
這樣模擬Linux kenerl 初始化驗證成功,最后上庫。
審核編輯:湯梓紅
-
單片機
+關(guān)注
關(guān)注
6043文章
44621瀏覽量
638589 -
Linux
+關(guān)注
關(guān)注
87文章
11345瀏覽量
210403 -
STM32
+關(guān)注
關(guān)注
2272文章
10924瀏覽量
357591 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
62977 -
函數(shù)指針
+關(guān)注
關(guān)注
2文章
56瀏覽量
3835
原文標(biāo)題:在STM32上模擬Linux自動初始化
文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
RT-Thread自動初始化詳解
![RT-Thread<b class='flag-5'>自動</b><b class='flag-5'>初始化</b>詳解](https://file.elecfans.com//web2/M00/4D/5D/poYBAGK2552AP3IhAAERUWXJgTY466.png)
自動初始化機制原理詳解
![<b class='flag-5'>自動</b><b class='flag-5'>初始化</b>機制原理詳解](https://file1.elecfans.com/web2/M00/B5/DE/wKgaomV8_yuAfareAAAgNcCFK0c700.png)
LINUX系統(tǒng)引導(dǎo)和初始化-LINUX內(nèi)核解讀
Linux內(nèi)存初始化
ds1302時鐘芯片初始化,自動決定DS1302是否需要初始化程序
stm32初始化流程圖解析
![<b class='flag-5'>stm32</b><b class='flag-5'>初始化</b>流程圖解析](https://file1.elecfans.com//web2/M00/A6/E7/wKgZomUMQSmAQL2AAAAZJVsDhAw364.jpg)
在51平臺下初始化文件的引入導(dǎo)致全局變量無法初始化的問題如何解決
![<b class='flag-5'>在</b>51平臺下<b class='flag-5'>初始化</b>文件的引入導(dǎo)致全局變量無法<b class='flag-5'>初始化</b>的問題如何解決](https://file.elecfans.com/web1/M00/A4/1F/pIYBAF1bWr6AW1IIAAqjwPD92Tk888.png)
STM32執(zhí)行代碼初始化卡住,或者上電卡住,或者復(fù)位卡住,導(dǎo)致代碼不執(zhí)行
![<b class='flag-5'>STM32</b>執(zhí)行代碼<b class='flag-5'>初始化</b>卡住,或者<b class='flag-5'>上</b>電卡住,或者復(fù)位卡住,導(dǎo)致代碼不執(zhí)行](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
RT-Thread自動初始化機制
![RT-Thread<b class='flag-5'>自動</b><b class='flag-5'>初始化</b>機制](https://file.elecfans.com//web2/M00/4B/55/poYBAGKrLSKAcuheAAEs3dd2mrs036.png)
如何對PNET 模擬器進(jìn)行初始化安裝
使用STM32CubeMX生成初始化代碼
STM32 模擬Linux kernel自動初始化流程
![<b class='flag-5'>STM32</b> <b class='flag-5'>模擬</b><b class='flag-5'>Linux</b> kernel<b class='flag-5'>自動</b><b class='flag-5'>初始化</b>流程](https://file1.elecfans.com/web2/M00/8A/06/wKgaomSOyDOAJJb4AABquTDuT9Y918.jpg)
評論