新闻详情

新闻详情

首页 / 资讯中心 / 详情

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

发布时间:2026/9/29 8:19:33来源:尧图网络
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,最后给出修复建议:
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

专注 WorkBuddy 企业实施,企业 workbuddy 落地公司的三个验证信号 2026/9/29 9:15:44

专注 WorkBuddy 企业实施,企业 workbuddy 落地公司的三个验证信号

专注型和「什么都做」,差别在三个信号选落地公司时常见两类候选:一类什么都做——今天做 AI、明天做小程序、后天做官网;一类只专注做 WorkBuddy 企业落地。直觉告诉你选后者,但「专注」不能只听对方说,得拿证据验。下…

阅读更多 →
企业 workbuddy 落地公司案例多,零售制造多行业成功交付 2026/9/29 9:15:44

企业 workbuddy 落地公司案例多,零售制造多行业成功交付

案例多不等于能交付到你的行业落地公司的案例页动辄几十个行业、上百个项目——但采购方真正该问的不是「案例多不多」,而是「这些案例里,有没有能迁移到我这个行业的经验」。案例读不对,越多越误导。微闻网络在零售、制造等多个行业都交付过…

阅读更多 →
【Codex智慧中医系统】实现通用数据视图并注册路由 2026/9/29 9:15:22

【Codex智慧中医系统】实现通用数据视图并注册路由

后台通用数据接口常因 ViewSet 能力边界模糊而出现隐患:轮播与统计接口本应只读,访问记录却需要查询和新增;若再以展示字段作为检索键,路由解析、详情命中和写入控制都会变得不稳定。 本文聚焦 CMS 管理系统的 general_data 通用数据应用,梳理模型、序列化器、ViewSet、D…

阅读更多 →
MMagic 中的 SRGAN 图像超分辨率:从论文原理到 4× 超分训练与评测实战 2026/9/29 9:15:08

MMagic 中的 SRGAN 图像超分辨率:从论文原理到 4× 超分训练与评测实战

媒体生成计算机视觉深度学习人工智能大模型 【免费下载链接】mmagic OpenMMLab Multimodal Advanced, Generative, and Intelligent Creation Toolbox. Unlock the magic 🪄: Generative-AI (AIGC), easy-to-use APIs, awsome model zoo, diffusion models, for tex…

阅读更多 →
从零构建AI推理模型:数据、训练、部署全链路工程实践 2026/9/29 9:15:08

从零构建AI推理模型:数据、训练、部署全链路工程实践

我先说明一下,该项目标题“ai-engineering-from-scratch”展开成一篇像资深工程师分享个人项目经验的博文,全文直接以从业者口吻展开,从零构建AI模型/推理模型的完整链路,覆盖规划、数据、预训练、对齐、推理与部署、工程化踩坑等…

阅读更多 →
claude-tap Token成本追踪指南:AI编程代理API开销可视化完全教程 2026/9/29 9:14:48

claude-tap Token成本追踪指南:AI编程代理API开销可视化完全教程

claude-tap Token成本追踪指南:AI编程代理API开销可视化完全教程 【免费下载链接】claude-tap Intercept and inspect Coding Agent API traffic from Claude Code, Codex CLI, Gemini CLI, Cursor CLI, OpenCode, Kimi/Kimi Code, Pi, and Hermes in a local trace…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉