尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Zephyr BSP: 13-Zephyr 初始化优先级

发布时间:2026/9/29 8:19:35

资讯中心
01
ARTICLE

Zephyr BSP: 13-Zephyr 初始化优先级

Zephyr BSP: 13-Zephyr 初始化优先级
摘要:本文深入解析 Zephyr 中两个同为PRE_KERNEL_2的 Driver 的初始化顺序问题。核心结论是:Zephyr 的初始化顺序由(Init Level, Init Priority)二元组共同决定——先按 Level 分阶段(PRE_KERNEL_1→PRE_KERNEL_2→POST_KERNEL→APPLICATION),同一 Level 内再按 priority 数字从小到大执行。PRE_KERNEL_2是初始化阶段而非优先级,40才是真正的 Init Priority。当两个 Driver 的 Level 与 Priority 完全相同时,不要依赖其先后顺序来表达依赖关系,而应通过调整 priority 或借助 Devicetree dependency 与device_is_ready()来保证初始化顺序正确。文章最后结合 UART/GPIO 实例,说明了 Priority 设计对大型 SoC BSP 移植的重要性。** 快速结论**初始化顺序由(Level, Priority)二元组决定:先按 Level 分阶段,同一 Level 内再按 priority 排序;同 Level 内 priority 数字小者先执行:如PRE_KERNEL_2 / 30早于PRE_KERNEL_2 / 50;Level 与 Priority 相同时不要依赖顺序表达依赖:应显式调整 priority 或改用 Devicetree dependency;大型 SoC 应优先使用 Devicetree dependency:通过clocks、pinctrl-0、interrupts等属性自动推导初始化顺序,而非手写 priority。这正好是理解 ZephyrDevice Init 系统的关键问题。Zephyr Init Priority:两个 Driver 都是 PRE_KERNEL_2,到底谁先初始化?先给结论:如果两个 Driver 都是 PRE_KERNEL_2,不能简单理解成"谁的 priority 数字小谁先"。**Zephyr 最终会根据init entry 的排序键决定顺序;而对于同一个 init level,priority 数字越小越早。如果 priority 也相同,则还存在进一步的链接/排序规则,不要依赖它来表达 Driver 之间的依赖关系。1. 先看 Zephyr Init 的四个大阶段你上一节已经看到:PRE_KERNEL_1 ↓ PRE_KERNEL_2 ↓ POST_KERNEL ↓ APPLICATION可以先把它理解成:Zephyr Boot │ ┌───────────┴───────────┐ ↓ ↓ PRE_KERNEL_1 PRE_KERNEL_2 │ ↓ POST_KERNEL │ ↓ APPLICATION因此:PRE_KERNEL_1一定早于:PRE_KERNEL_2而:PRE_KERNEL_2一定早于:POST_KERNEL但是问题来了:Driver A → PRE_KERNEL_2 Driver B → PRE_KERNEL_2谁先?2. 真正决定顺序的是 (level, priority)可以把 Zephyr 的 init entry 想象成一个排序键:(level, priority)例如:Driver A: PRE_KERNEL_2,30Driver B: PRE_KERNEL_2,50那么:PRE_KERNEL_2 /30↓ PRE_KERNEL_2 /50所以:同一个 Init Level 下,priority 数字越小,越早执行。例如:DEVICE_DT_DEFINE(DT_NODELABEL(uart0),uart_init,NULL,uart_data,uart_config,PRE_KERNEL_2,40,uart_api);另一个:DEVICE_DT_DEFINE(DT_NODELABEL(timer0), timer_init, NULL,timer_data,timer_config, PRE_KERNEL_2,60,timer_api);启动顺序就是:PRE_KERNEL_2 /40↓ uart_init()↓ PRE_KERNEL_2 /60↓ timer_init()3. 所以 PRE_KERNEL_2 本身不是一个 priority这是非常容易混淆的地方。很多初学者看到:PRE_KERNEL_2会认为:“这是初始化优先级。”其实不是。它是:Init Level而:40才是:Init Priority所以:PRE_KERNEL_2,40应该读成:初始化阶段=PRE_KERNEL_2 优先级=404. 举一个 UART + GPIO Driver 的例子假设你的 SoC 有:GPIO Driver UART Driver你定义:GPIO: PRE_KERNEL_2 /30UART: PRE_KERNEL_2 /50那么启动:Zephyr boot │ ├── PRE_KERNEL_1 │ └── PRE_KERNEL_2 │ ├── GPIO init priority30│ └── UART init priority50也就是:GPIO ↓ UART这样 UART 初始化时:uart_init()就可以假设 GPIO Driver 已经完成初始化。5. 但是这里有一个非常重要的问题假设你写成:GPIO:PRE_KERNEL_2/50UART:PRE_KERNEL_2/50现在:GPIO ──┐ ├── PRE_KERNEL_2 /50UART ──┘那么:不要把"谁先"当成稳定的 Driver 依赖机制。因为你真正表达的是:GPIO 和 UART 的 priority 完全相同而不是:UART depends on GPIO如果 UART 确实依赖 GPIO,那么正确思路应该是:GPIO priority=30UART priority=50明确表达:GPIO ↓ UART6. 这和你现在学习的 Device Model 有直接关系你前面已经学习了:Device Tree ↓ DEVICE_DT_DEFINE()↓ struct device ↓ initfunction↓ device_is_ready()现在把 Init Priority 加进来:Devicetree │ ↓ DEVICE_DT_DEFINE()│ ┌──────────┴──────────┐ ↓ ↓ struct device init entry │ ┌──────┴──────┐ ↓ ↓ level priority │ │ └──────┬──────┘ ↓ Zephyr init │ ↓ driver init()所以:DEVICE_DT_DEFINE() 不只是创建一个 struct device。它同时把 Driver 的初始化信息放进 Zephyr 的system initialization machinery。7. 再看两个不同 Level 的 Driver假设:Driver A: PRE_KERNEL_2 /90Driver B: POST_KERNEL /0很多人会误以为:B priority=0所以 B 更早。不是。真正排序首先看 Level:PRE_KERNEL_2 ↓ POST_KERNEL所以实际:A ↓ B即使:A priority=90B priority=0也不会改变 Level 的先后关系。8. 可以记成一条非常重要的规则Zephyr Driver Init 可以先记:Init Level ↓ Init Priority即:PRE_KERNEL_1 ↓ PRE_KERNEL_2 ↓ POST_KERNEL ↓ APPLICATION在同一个 Level 内:priority 小 ↓ priority 大所以:PRE_KERNEL_1 /90↓ PRE_KERNEL_2 /10↓ PRE_KERNEL_2 /50↓ POST_KERNEL /0↓ APPLICATION /0这才是比较正确的思维方式。9. 那 device_is_ready() 又是什么?这里就开始和你上一节的问题连接起来了。假设:GPIO Driver PRE_KERNEL_2 /30UART Driver PRE_KERNEL_2 /50UART:const struct device\*gpio=DEVICE_DT_GET(DT_NODELABEL(gpio0));if(!device_is_ready(gpio)){return-ENODEV;}这里:device_is_ready(gpio)不是:“帮我把 GPIO 初始化。”而是:检查这个 struct device 当前是否已经完成初始化并处于可用状态。所以:GPIO init()↓ device-state=initialized ↓ UART init()↓ device_is_ready(gpio)↓true10. 这就是为什么 Priority 设计很重要如果你写:GPIO: PRE_KERNEL_2 /50UART: PRE_KERNEL_2 /30那么:UART init()↓ device_is_ready(GPIO)此时 GPIO 可能还没有初始化。于是:UART ↓ GPIO ? ↓ not ready这时候问题并不是:device_is_ready()坏了。而是:你的 Driver Init Dependency 排错了。11. 实战:UART 依赖 GPIO 的排查与修复下面用一个完整示例,把第 9、10 节的内容串起来:UART 初始化时device_is_ready(gpio)返回false,问题出在 priority 排反了。11.1 错误写法:UART 比 GPIO 先初始化假设你的 SoC 上同时有 GPIO 和 UART,但两个 Driver 的 priority 写反了:/* gpio driver */DEVICE_DT_DEFINE(DT_NODELABEL(gpio0),gpio_init,NULL,gpio_data,gpio_config,PRE_KERNEL_2,50,/* GPIO 反而排后面 */gpio_api);/* uart driver */DEVICE_DT_DEFINE(DT_NODELABEL(uart0),uart_init,NULL,uart_data,uart_config,PRE_KERNEL_2,30,/* UART 反而排前面 */uart_api);UART 的uart_init()里这样使用 GPIO:staticintuart_init(conststructdevice*dev){conststructdevice*gpio=DEVICE_DT_GET(DT_NODELABEL(gpio0));if(!device_is_ready(gpio)){printk("uart_init: GPIO not ready!\n");return-ENODEV;}/* 配置 UART 的 TX/RX 引脚 */gpio_pin_configure(gpio,TX_PIN,GPIO_OUTPUT);gpio_pin_configure(gpio,RX_PIN,GPIO_INPUT);return0;}11.2 启动日志:修复前*** Booting Zephyr OS build zephyr-v3.7.0 ***[00:00:00.000]uart_init: GPIO not ready!-- 失败[00:00:00.000]uart0: init failed(-19)[00:00:00.000]gpio_init: GPIO ready可以看到:uart_init()先执行,此时 GPIO 还没初始化,device_is_ready()返回false,UART 初始化直接失败。11.3 修复:交换 priority把 GPIO 的 priority 调小,让它在 UART 之前完成初始化:/* gpio driver */DEVICE_DT_DEFINE(DT_NODELABEL(gpio0),gpio_init,NULL,gpio_data,gpio_config,PRE_KERNEL_2,30,/* GPIO 先初始化 */gpio_api);/* uart driver */DEVICE_DT_DEFINE(DT_NODELABEL(uart0),uart_init,NULL,uart_data,uart_config,PRE_KERNEL_2,50,/* UART 后初始化 */uart_api);11.4 启动日志:修复后*** Booting Zephyr OS build zephyr-v3.7.0 ***[00:00:00.000]gpio_init: GPIO ready[00:00:00.000]uart_init: GPIO ready, configuring pins...[00:00:00.000]uart0: init ok现在顺序正确:PRE_KERNEL_2 /30↓ gpio_init()↓ device-state=initialized ↓ PRE_KERNEL_2 /50↓ uart_init()↓ device_is_ready(gpio)→true11.5 排查思路小结遇到device_is_ready()返回false时,按这个顺序排查:确认两个 Driver 的Init Level是否相同;如果相同,检查Init Priority是否满足依赖关系(被依赖者 priority 更小);如果 Level 不同,先确认被依赖者是否在更早的 Level;如果 Level 和 Priority 都相同,不要依赖顺序,应显式调整 priority 或改用 Devicetree dependency 表达依赖。11.6 排查决策流程图下面这张 Mermaid 流程图完整展示了device_is_ready()返回false时的排查决策路径,从确认 Init Level 是否相同开始,依次检查 Init Priority、Devicetree dependency,最后给出修复建议:
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。