Zephyr OS 驱动篇之设备初始化顺序

来源:互联网 发布:一级域名注册 编辑:程序博客网 时间:2024/05/18 13:24
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设备 JPRIMARY     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)排序。
原创粉丝点击