Zephyr OS 驅動篇之設備初始化順序




Zephyr OS 驅動篇之設備初始化順序
在前面的 Zephyr OS 驅動篇之設備驅動模型 中已講解了 Zephyr OS 中的設備驅動模型。Zephyr OS 將設備分爲 PRIMARY、SECONDARY、NANOKERNEL 等五個等級,並在系統啓動的相應階段初始化該等級內的所有設備。那麼問題來了,每個等級內有很多設備,它們的初始化時有依賴關係嗎,即它們需要按照某個順序初始化嗎?

答案是:YES!

再看看設備的定義:
  1. #define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \
  2.                 level, prio, api) \
  3.     \
  4.     static struct device_config __config_##dev_name __used \
  5.     __attribute__((__section__(".devconfig.init"))) = { \
  6.         .name = drv_name, .init = (init_fn), \
  7.         .config_info = (cfg_info) \
  8.     }; \
  9.     \
  10.     static struct device (__device_##dev_name) __used \
  11.     __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
  12.          .config = &(__config_##dev_name), \
  13.          .driver_api = api, \
  14.          .driver_data = data \
  15.     }
複製代碼
在這個宏定義中,有兩個參數至關重要,level 和 prio。這兩個參數沒有出現在具體的代碼中,而是出現在 __attribute__ 屬性中:
  1. __attribute__((__section__(".init_" #level STRINGIFY(prio))))
複製代碼
編譯器在預編譯的時候會將 “#” 後面到參數轉換爲字符串,例如 #PRIMARY 將被轉換爲 “PRIMARY”。
TRINGIFY(s) 的作用也是將參數 s 轉換爲字符串 “s”, 其代碼如下:
  1. #define _STRINGIFY(x) #x
  2. #define STRINGIFY(s) _STRINGIFY(s)
複製代碼
舉個例如,如果在調用 DEVICE_AND_API_INIT 時傳入的參數 level 和 prio 分別爲 PRIMARY 和 50,那麼編譯器就會將上面那段代碼放到名爲 .init_PRIMARY50 的段中。



現在轉移視線,在 linker-defs.h 中有如下代碼
  1. #define    DEVICE_INIT_SECTIONS()            \
  2.         __device_init_start = .;        \
  3.         DEVICE_INIT_LEVEL(PRIMARY)        \
  4.         DEVICE_INIT_LEVEL(SECONDARY)    \
  5.         DEVICE_INIT_LEVEL(NANOKERNEL)    \
  6.         DEVICE_INIT_LEVEL(MICROKERNEL)    \
  7.         DEVICE_INIT_LEVEL(APPLICATION)    \
  8.         __device_init_end = .;        \
  9.         DEVICE_BUSY_BITFIELD()        \

  10. DEVICE_INIT_LEVEL 的定義如下:
  11. #define DEVICE_INIT_LEVEL(level)                \
  12.         __device_##level##_start = .;            \
  13.         KEEP(*(SORT(.init_##level[0-9])));        \
  14.         KEEP(*(SORT(.init_##level[1-9][0-9])));    \
複製代碼
在鏈接腳本文件 linker.ld 中將會調用上述代碼。上面代碼的大意是將所有的設備定義的代碼按照設備等級(level)依次排列,且在每個等級中,按數字(prio)的大小從小到大依次排列。

假設系統一共定義了十個設備,它們的參數如下:

devicelevelprio
設備 APRIMARY     
32
設備 BPRIMARY     
24
設備 CNANOKERNEL     
50
設備 DPRIMARY     
30
設備 EMICROKERNEL     
30
設備 FAPPLICATION     
3
設備 GSECONDARY     
18
設備 HPRIMARY     
0
設備 ISECONDARY     
44
設備 JPRIMARY     
20


編譯器會按照下面的順序依次存放各個設備的代碼:

devicelevelprio
設備 HPRIMARY     
0
設備 J
PRIMARY     
20
設備 BPRIMARY     
24
設備 DPRIMARY     
30
設備 APRIMARY     
32
設備 GSECONDARY     
18
設備 ISECONDARY     
44
設備 CNANOKERNEL     
50
設備 EMICROKERNEL     
30
設備 FAPPLICATION     
3

所以系統啓動時,各設備的初始化順序是 H, J, B, D, A, G, I, C, E, F。

總結一下,在系統初始化設備時,除了要按照設備等級(level)排序外,在每個等級內部還要按照優先級(prio)排序。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章