03-5status、驱动实例化与第三章总结验证方式最终 DTS、生成宏、两套编译、native_sim/native/64验证结论源码确认 编译确认 模拟确认1. 本节目标本节把第三章前四节连接到真实驱动的常见模式compatible status binding/property - compatible instance - DT_INST_FOREACH_STATUS_OKAY() - 每实例静态配置/设备定义本节只验证 Devicetree 如何筛选并展开实例。struct device、初始化级别、初始化顺序和device_is_ready()将在第四章详细学习。2. status 的基本语义常见写法status okay; status disabled;在 Zephyr Devicetree 构建语义中okay 节点启用可以参与 status-okay 驱动实例化 disabled 节点保留在树中但不参与 status-okay 实例化此外缺少status通常按okay处理status ok是兼容但已弃用的写法其他状态值由 Devicetree 规范和 binding 约束。公共检查宏DT_NODE_HAS_STATUS(node_id,okay)DT_NODE_HAS_STATUS(node_id,disabled)DT_NODE_HAS_STATUS_OKAY(node_id)源码确认3. status 不等于硬件状态status okay;表示构建配置希望启用节点不表示芯片真实焊接存在电源正常SPI/I2C 通信成功GPIO 电平正确driver init 已返回成功设备现在 ready。同样status disabled;也不表示物理芯片消失只表示当前构建不为它生成 status-okay 实例。4. 本节三种同 compatible 节点正常 overlaylesson_config: lesson-config { compatible zephyr,devicetree-lesson; status okay; lesson-title overlay reaches the final tree; sample-count 4; }; lesson_peer: lesson-peer { compatible zephyr,devicetree-lesson; status okay; lesson-title phandle target; sample-count 2; }; lesson_disabled: lesson-disabled { compatible zephyr,devicetree-lesson; status disabled; lesson-title disabled instance; sample-count 8; };节点数量compatible 匹配节点总数3 status okay 节点数 2 status disabled 节点数 15. DT_DRV_COMPAT声明当前驱动类型实验lesson_instances.c#defineDT_DRV_COMPATzephyr_devicetree_lesson对应 DTS 字符串compatible zephyr,devicetree-lesson;转换zephyr,devicetree-lesson - zephyr_devicetree_lesson定义DT_DRV_COMPAT后驱动实例系列宏就知道应处理哪一类节点DT_DRV_INST DT_INST_PROP DT_INST_PARENT DT_INST_FOREACH_STATUS_OKAYDT_DRV_COMPAT只在当前 C translation unit 的预处理上下文中起作用通常定义在 driver.c文件顶部。6. compatible instance number同一个 compatible 的节点会被分配从 0 开始的 instance number。本地devicetree.h明确说明每个相同 compatible 的节点都有一个 instance number包括 disabled 节点enabled 节点从 0 开始排列disabled 节点的 instance number 大于 enabled 节点instance number 不等于 node label、unit address、alias 或芯片文档编号不保证同一节点在不同构建中拥有相同 instance number。如果应用需要稳定的物理角色应使用 node label、alias、专用 property 或明确的映射而不是依赖 instance number。源码确认7. DT_DRV_INST 和 DT_INST_PROPDT_DRV_INST(inst)等价于DT_INST(inst,DT_DRV_COMPAT)它把当前 compatible 的 instance number 转换为 node identifier。DT_INST_PROP(inst,sample_count)等价于DT_PROP(DT_DRV_INST(inst),sample_count)所以 instance 宏不是另一套数据它们是上一节 node/property 公共宏的 driver-friendly 包装。8. DT_INST_FOREACH_STATUS_OKAY常见模式#defineDEFINE_ONE(inst)/* 使用 inst 生成一份静态定义 */DT_INST_FOREACH_STATUS_OKAY(DEFINE_ONE)如果当前 compatible 有两个 okay 节点宏展开为DEFINE_ONE(0)DEFINE_ONE(1)被调用的DEFINE_ONE自己负责添加逗号分号变量名拼接结构体初始化。disabled 节点不会出现在该 foreach 展开中。Zephyr 公共实现位置zephyr/include/zephyr/devicetree.h:4985源码确认9. 本节静态实例表为了暂时不进入 Device Model本实验只生成普通静态结构体数组structlesson_instance_info{constchar*path;constchar*title;constchar*mode;intsample_count;};每实例 initializer#defineLESSON_INSTANCE_ENTRY(inst)\{\.pathDT_NODE_PATH(DT_DRV_INST(inst)),\.titleDT_INST_PROP(inst,lesson_title),\.modeDT_INST_PROP(inst,mode),\.sample_countDT_INST_PROP(inst,sample_count),\},生成数组staticconststructlesson_instance_infoenabled_instances[]{DT_INST_FOREACH_STATUS_OKAY(LESSON_INSTANCE_ENTRY)};编译期检查BUILD_ASSERT(ARRAY_SIZE(enabled_instances)DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT));如果 foreach 展开数量和 Devicetree 生成的 okay instance 数量不一致构建会失败。10. 实验一两个 okay一个 disabled构建cd~/project/exportZEPHYR_SDK_INSTALL_DIR/home/yff/zephyr-sdk/zephyr-sdk-0.17.1sourcezephyr/zephyr-env.sh west build\-bnative_sim/native/64\/mnt/c/study/1-zephyr/labs/ch03_devicetree\--build-dir /mnt/c/study/1-zephyr/work/ch03_status_normal\-palways生成头文件#defineDT_COMPAT_HAS_OKAY_zephyr_devicetree_lesson1#defineDT_N_INST_zephyr_devicetree_lesson_NUM_OKAY2#defineDT_FOREACH_OKAY_INST_zephyr_devicetree_lesson(fn)fn(0)fn(1)实际输出okay_instance_count2 okay_instance[0]/lesson-config titleoverlay reaches the final tree modefast sample_count4 okay_instance[1]/lesson-peer titlephandle target modeslow sample_count2lesson-disabled没有出现在静态数组中。模拟确认11. 实验二用额外 overlay 禁用 peer额外 overlaylesson_peer { status disabled; };构建west build\-bnative_sim/native/64\/mnt/c/study/1-zephyr/labs/ch03_devicetree\--build-dir /mnt/c/study/1-zephyr/work/ch03_status_peer_disabled\-palways\---DEXTRA_DTC_OVERLAY_FILEstatus_peer_disabled.overlay构建日志确认输入顺序Found devicetree overlay: .../app.overlay Found devicetree overlay: status_peer_disabled.overlay最终zephyr.dtslesson_peer: lesson-peer { status disabled; /* 其他属性仍然存在 */ };生成头文件#defineDT_N_INST_zephyr_devicetree_lesson_NUM_OKAY1#defineDT_FOREACH_OKAY_INST_zephyr_devicetree_lesson(fn)fn(0)实际输出okay_instance_count1 okay_instance[0]/lesson-config titleoverlay reaches the final tree modefast sample_count4只修改一个 status静态实例表从两个 entry 变为一个 entry。模拟确认12. disabled 节点仍然存在第二套构建中main 仍然能打印peer_path/lesson-peer peer_titlephandle target peer_has_optional1 peer_optional_or7原因DT_NODELABEL(lesson_peer) 定位树中的节点不自动检查 status DT_PROP(lesson_peer, ...) 读取生成属性不自动要求 status okay DT_INST_FOREACH_STATUS_OKAY(...) 才明确过滤 status因此node exists ! node status okay ! driver device object exists ! runtime device ready这是本节最重要的结论之一。13. 生成头文件中的全部 instance 映射正常构建#defineDT_N_INST_0_zephyr_devicetree_lessonDT_N_S_lesson_config#defineDT_N_INST_1_zephyr_devicetree_lessonDT_N_S_lesson_peer#defineDT_N_INST_2_zephyr_devicetree_lessonDT_N_S_lesson_disabled说明 disabled 节点仍然有 instance number 2。禁用 peer 后仍能看到三份 instance mapping但 okay foreach 只调用fn(0)。不要把存在 instance number误解为会被 DT_INST_FOREACH_STATUS_OKAY 实例化编译确认14. 真实 Zephyr 驱动的常见展开模式典型驱动#defineDT_DRV_COMPATvendor_device#defineDRIVER_DEFINE(inst)\staticstructdriver_datadata_##inst;\staticconststructdriver_configconfig_##inst{\/* DT_INST_PROP / GPIO_DT_SPEC_INST_GET 等 */\};\DEVICE_DT_INST_DEFINE(inst,...)DT_INST_FOREACH_STATUS_OKAY(DRIVER_DEFINE)每个 okay node 通常产生一份 mutable runtime data一份 const hardware config一个 Zephyr device object一条初始化记录一组 API table 关联。本节只需要识别这个框架。下一章会逐项解释DEVICE_DT_INST_DEFINE()参数、初始化函数、级别、优先级和 ready 状态。15. Kconfig、CMake、Devicetree 三重条件驱动真正进入系统通常需要多层条件Kconfig symbol y - CMake 进入驱动目录并编译 driver.c driver.c 中 DT_DRV_COMPAT - 选择匹配 compatible Devicetree node status okay - foreach 为该 node 展开实例定义 binding - 校验属性并生成 property 宏 DEVICE_DT_INST_DEFINE - 创建 Device Model 对象与初始化记录所以常见排查顺序是1. .config 中驱动 Kconfig 是否为 y 2. compile_commands.json 中 driver.c 是否编译 3. zephyr.dts 中节点 compatible/status 是否正确 4. devicetree_generated.h 中 compatible instance/属性宏是否存在 5. ELF/map 中 device object 和 init entry 是否存在 6. 运行时 device_is_ready() 与 init 返回值前四项已经由第二、第三章覆盖后两项是第四章重点。18. 常见错误18.1 认为 disabled node 从最终树消失它通常仍在zephyr.dts和生成头文件中只是不参与 status-okay foreach。18.2 把 instance number 当物理编号instance number 不保证与 unit address、node label 或产品传感器编号一致。18.3 只检查 compatible不检查 statuscompatible 匹配但 status disabled仍不会被DT_INST_FOREACH_STATUS_OKAY()展开。18.4 只修改子节点不检查父总线实际设备通常还依赖父控制器 status、pinctrl、clock 等资源。子节点 okay 不能自动使整个硬件链路有效。18.5 认为 DT foreach 会自动编译 driver.c如果 Kconfig/CMake 没有把 driver translation unit 编进去里面的宏根本不会被预处理。18.6 认为 node okay 就等于 device readyready 是初始化完成后的运行期状态还要看 init 返回值和依赖设备。19. 第三章知识地图03-1输入到最终树board DTS/DTSI overlay - zephyr.dts.pre - zephyr.dts - edt.pickle - devicetree_generated.h03-2节点定位和引用DT_PATH DT_NODELABEL DT_ALIAS DT_PHANDLE03-3compatible 与 bindingcompatible 匹配 binding - required/type 校验 - property 宏生成03-4公共 DT 宏DT_PROP DT_PROP_LEN DT_PROP_BY_IDX DT_NODE_HAS_PROP DT_PROP_OR DT_ENUM_IDX03-5status 与实例展开DT_DRV_COMPAT DT_INST_PROP DT_NUM_INST_STATUS_OKAY DT_INST_FOREACH_STATUS_OKAY - 每实例静态定义第三章完整主线DTS/overlay 输入 - 最终树 - compatible 匹配 binding - node/property 生成宏 - status-okay compatible instances - driver per-instance definitions20. 第三章最重要的六句话overlay 是输入zephyr.dts是最终合并结果node label、path、alias 和labelproperty 不是一回事compatible 标识一类 node并用于匹配 binding 和 driverbinding 决定自定义 property 的类型、必填约束和宏生成公共DT_*API 是源码接口DT_N_S_*是生成实现细节node 存在、status okay、device object 存在、device ready 是四个不同阶段。21. 配置问题的最终排查清单当驱动“没有实例化”时[ ] build_info.yml 中选中了正确 DTS/overlay 吗 [ ] zephyr.dts 中 node 存在吗 [ ] compatible 拼写正确吗 [ ] status 是 okay 吗父节点是否启用 [ ] 节点匹配了正确 binding 吗 [ ] required/type 校验是否通过 [ ] devicetree_generated.h 中是否有 instance/property 宏 [ ] .config 中驱动开关是 y 吗 [ ] driver.c 是否在 compile_commands.json 中 [ ] driver 是否使用 DT_INST_FOREACH_STATUS_OKAY [ ] ELF 中是否有 device/init 对象 [ ] init 是否成功device_is_ready 是否为 true22. 练习与自测比较两套生成头文件rg-nDT_N_INST_zephyr_devicetree_lesson_NUM_OKAY|DT_FOREACH_OKAY_INST_zephyr_devicetree_lesson\/mnt/c/study/1-zephyr/work/ch03_status_normal/zephyr/include/generated/zephyr/devicetree_generated.h\/mnt/c/study/1-zephyr/work/ch03_status_peer_disabled/zephyr/include/generated/zephyr/devicetree_generated.h然后回答peer disabled 后为什么DT_PROP(peer, lesson_title)仍能使用但 foreach 不再包含 peer三个相同 compatible 节点中只有两个 okayDT_NUM_INST_STATUS_OKAY()应是多少为什么不能把inst 0永久解释为某个固定物理传感器如果.config已经开启 USS但tdk_icu30201.c不在compile_commands.json问题在哪一层如果 driver.c 已编译、node 也存在但 status disabledDT_INST_FOREACH_STATUS_OKAY()会怎样status okay与device_is_ready()分别属于构建期还是运行期下一章第 4 章 Device Model 与驱动初始化。