自動初始化機制是指初始化函數不需要被顯式調用,只需要在函數定義處通過宏定義的方式進行申明,就會在系統啓動過程中被執行。
例如在串口驅動中調用一個宏定義告知系統初始化需要調用的函數,代碼如下:
int rt_hw_usart_init(void) /* 串口初始化函數 */
{
... ...
/* 註冊串口 1 設備 */
rt_hw_serial_register(&serial1, "uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
return 0;
}
INIT_BOARD_EXPORT(rt_hw_usart_init); /* 使用組件自動初始化機制 */
示例代碼最後的 INIT_BOARD_EXPORT(rt_hw_usart_init) 表示使用自動初始化功能,按照這種方式,rt_hw_usart_init() 函數就會被系統自動調用,那麼它是在哪裏被調用的呢?
在系統啓動流程圖中,有兩個函數:rt_components_board_init() 與 rt_components_init(),其後的帶底色方框內部的函數表示被自動初始化的函數,其中:
-
“board init functions” 爲所有通過 INIT_BOARD_EXPORT(fn) 申明的初始化函數。
-
“pre-initialization functions” 爲所有通過 INIT_PREV_EXPORT(fn)申明的初始化函數。
-
“device init functions” 爲所有通過 INIT_DEVICE_EXPORT(fn) 申明的初始化函數。
-
“components init functions” 爲所有通過 INIT_COMPONENT_EXPORT(fn)申明的初始化函數。
-
“enviroment init functions” 爲所有通過 INIT_ENV_EXPORT(fn) 申明的初始化函數。
-
“application init functions” 爲所有通過 INIT_APP_EXPORT(fn)申明的初始化函數。
rt_components_board_init() 函數執行的比較早,主要初始化相關硬件環境,執行這個函數時將會遍歷通過 INIT_BOARD_EXPORT(fn) 申明的初始化函數表,並調用各個函數。
rt_components_init() 函數會在操作系統運行起來之後創建的 main 線程裏被調用執行,這個時候硬件環境和操作系統已經初始化完成,可以執行應用相關代碼。rt_components_init() 函數會遍歷通過剩下的其他幾個宏申明的初始化函數表。
RT-Thread 的自動初始化機制使用了自定義 RTI 符號段,將需要在啓動時進行初始化的函數指針放到了該段中,形成一張初始化函數表,在系統啓動過程中會遍歷該表,並調用表中的函數,達到自動初始化的目的。
用來實現自動初始化功能的宏接口定義詳細描述如下表所示:
初始化順序 | 宏接口 | 描述 |
---|---|---|
1 | INIT_BOARD_EXPORT(fn) | 非常早期的初始化,此時調度器還未啓動 |
2 | INIT_PREV_EXPORT(fn) | 主要是用於純軟件的初始化、沒有太多依賴的函數 |
3 | INIT_DEVICE_EXPORT(fn) | 外設驅動初始化相關,比如網卡設備 |
4 | INIT_COMPONENT_EXPORT(fn) | 組件初始化,比如文件系統或者 LWIP |
5 | INIT_ENV_EXPORT(fn) | 系統環境初始化,比如掛載文件系統 |
6 | INIT_APP_EXPORT(fn) | 應用初始化,比如 GUI 應用 |
初始化函數主動通過這些宏接口進行申明,如 INIT_BOARD_EXPORT(rt_hw_usart_init),鏈接器會自動收集所有被申明的初始化函數,放到 RTI 符號段中,該符號段位於內存分佈的 RO 段中,該 RTI 符號段中的所有函數在系統初始化時會被自動調用。