3.5.12 PRE_DEVICE 阶段详解
2026/4/29大约 3 分钟启动流程初始化PRE_DEVICE驱动注册控制台硬件定时器
3.5.12 PRE_DEVICE 阶段详解
📚 本节导读
学习时长: 约 25 分钟
难度级别: ⭐⭐⭐☆☆(中级)
前置知识:
- 3.5.11 POST_KERNEL 阶段详解
- 3.5.2.5 __driver_stm32_usart_early_driver_init 函数详解
- 了解 OS_DRIVER_DEFINE 驱动注册机制
🎯 学习目标
- 理解 PRE_DEVICE 级别的定位和目的
- 掌握驱动注册与设备注册的先后关系
- 理解 10 个 PRE_DEVICE 函数的职责
- 理解子级别的执行顺序和依赖关系
一、阶段概述
1.1 阶段定位
PRE_DEVICE 是设备注册前的驱动初始化级别。它通过 driver_match_devices 机制将驱动程序与设备信息进行匹配(probe),为后续 DEVICE 级别的设备注册做好准备。
1.2 基本信息
| 属性 | 值 |
|---|---|
| 初始化级别 | OS_INIT_LEVEL_PRE_DEVICE(值 4) |
| 调用位置 | _k_sys_task_entry 第 200 行 |
| 调用时机 | POST_KERNEL 初始化之后 |
| 前置条件 | 设备框架已初始化(device_core_init) |
| 总函数数 | 11 个(1 个标记 + 10 个实际函数) |
1.3 从 project.map 看实际注册
.init_call.4."" → pre_device_start ← 标记函数
.init_call.4.1 → __driver_soft_i2c_bus_driver_init ← 软件 I2C 总线驱动
.init_call.4.1 → __driver_stm32_usart_driver_init ← 串口驱动(正式)
.init_call.4.2 → os_console_init ← 控制台设备初始化
.init_call.4.2 → __driver_stm32_tim_driver_init ← 硬件定时器驱动
.init_call.4.2 → __driver_stm32_spi_driver_init ← SPI 驱动
.init_call.4.3 → os_hrtimer_init ← 高精度定时器
.init_call.4.3 → __driver_stm32_can_driver_init ← CAN 驱动
.init_call.4.3 → __driver_stm32_dac_driver_init ← DAC 驱动
.init_call.4.3 → __driver_stm32_iwdt_driver_init ← 独立看门狗驱动
.init_call.4.3 → __driver_stm32_rtc_driver_init ← RTC 驱动二、子级别结构
2.1 三个子级别
| 子级别 | 函数 | 职责类型 |
|---|---|---|
| 4.1 | soft_i2c_bus, stm32_usart | 基础通信总线驱动(I2C、串口) |
| 4.2 | os_console, stm32_tim, stm32_spi | 关键外设驱动(控制台、定时器、SPI) |
| 4.3 | os_hrtimer, stm32_can, dac, iwdt, rtc | 其他外设驱动 |
2.2 依赖关系
4.1(基础通信总线)
└─ 4.2(关键外设:控制台、定时器、SPI)
└─ 4.3(其他外设:CAN、DAC、IWDG、RTC、hrtimer)三、各函数详解
3.1 4.1 子级别:基础通信总线驱动
__driver_soft_i2c_bus_driver_init — 软件 I2C 总线驱动
| 属性 | 值 |
|---|---|
| 源文件 | drivers/i2c/soft_i2c_bus.c |
| 作用 | 注册软件 I2C 总线驱动,匹配 I2C 设备 |
通过 OS_DRIVER_DEFINE 生成,内部调用 driver_match_devices 匹配所有 "soft_i2c_bus" 类型的设备。
__driver_stm32_usart_driver_init — 串口驱动(正式注册)
| 属性 | 值 |
|---|---|
| 源文件 | drivers/hal/st/drivers/drv_usart.c |
| 作用 | 注册 STM32 串口驱动,匹配 UART 设备 |
与早期初始化的区别
在 3.5.2.5 中,__driver_stm32_usart_early_driver_init(PRE_KERNEL_1)只保存了控制台串口句柄。这里的 __driver_stm32_usart_driver_init(PRE_DEVICE)才是正式注册串口驱动,此时设备框架已完全就绪,可以注册完整的串口设备。
3.2 4.2 子级别:关键外设驱动
os_console_init — 控制台设备初始化
| 属性 | 值 |
|---|---|
| 源文件 | drivers/console/console.c |
| 作用 | 初始化控制台设备,关联硬件串口与 os_kprintf |
完成后,os_kprintf 的输出路径从 __os_hw_console_output(直接操作硬件)切换到 os_device_write_nonblock(通过设备框架)。
__driver_stm32_tim_driver_init — 硬件定时器驱动
| 属性 | 值 |
|---|---|
| 源文件 | drivers/hal/st/drivers/drv_hwtimer.c |
| 作用 | 注册 STM32 硬件定时器驱动 |
__driver_stm32_spi_driver_init — SPI 驱动
| 属性 | 值 |
|---|---|
| 源文件 | drivers/hal/st/drivers/drv_spi.c |
| 作用 | 注册 STM32 SPI 驱动 |
3.3 4.3 子级别:其他外设驱动
| 函数 | 源文件 | 职责 |
|---|---|---|
os_hrtimer_init | drivers/timer/hrtimer.c | 高精度定时器框架初始化 |
__driver_stm32_can_driver_init | drivers/hal/st/drivers/drv_can.c | CAN 总线驱动 |
__driver_stm32_dac_driver_init | drivers/hal/st/drivers/drv_dac.c | DAC 驱动 |
__driver_stm32_iwdt_driver_init | drivers/hal/st/drivers/drv_iwdg.c | 独立看门狗驱动 |
__driver_stm32_rtc_driver_init | drivers/hal/st/drivers/drv_rtc.c | RTC 实时时钟驱动 |
四、启动流程上下文
_k_sys_task_entry()
├─ POST_KERNEL 初始化 ← 3.5.11
│
├─ PRE_DEVICE 初始化 ← 本节(3.5.12)
│ ├─ 4.1: soft_i2c_bus, stm32_usart(驱动注册)
│ ├─ 4.2: os_console, stm32_tim, stm32_spi
│ └─ 4.3: os_hrtimer, stm32_can, dac, iwdt, rtc
│
├─ DEVICE 初始化 ← 3.5.13
├─ COMPONENT 初始化 ← 3.5.14
├─ APPLICATION 初始化 ← 3.5.15
└─ app_entry() → main()💡 本节总结
重点回顾
- PRE_DEVICE 是设备注册前的驱动初始化:通过
driver_match_devices匹配设备和驱动 - 10 个实际函数分 3 个子级别:基础总线 → 关键外设 → 其他外设
- 串口有两次注册:早期(PRE_KERNEL_1)只保存控制台句柄,正式(PRE_DEVICE)注册完整驱动
- os_console_init 是关键节点:之后
os_kprintf走设备框架路径
关键函数速查
| 子级别 | 函数数 | 典型函数 |
|---|---|---|
| 4.1 | 2 | soft_i2c_bus, stm32_usart |
| 4.2 | 3 | os_console, stm32_tim, stm32_spi |
| 4.3 | 5 | os_hrtimer, stm32_can, dac, iwdt, rtc |
下一步
接下来请学习:
- 3.5.13 DEVICE 阶段详解 - 设备注册与初始化