3. QNX SPI 驱动架构:资源管理器模型与设备注册流程
QNX 的 SPI 驱动体系建立在 资源管理器 (Resource Manager) 框架之上。理解这一架构是进行参数配置与 DMA 协同调试的前提。本章将深入剖析 SPI 驱动的分层模型、spi-master 与 spi-slave 的注册流程,以及它们如何通过路径空间与用户态交互。
3.1 资源管理器模型在 SPI 驱动中的角色
在 QNX 中,所有设备驱动都以资源管理器的形式存在。SPI 驱动也不例外——它作为一个用户态或内核态的进程,向系统注册一个路径(如 /dev/spi0),并通过 POSIX 标准接口(open、close、read、write、devctl())与上层应用通信。
核心概念: SPI 资源管理器将硬件寄存器操作封装为消息处理函数,应用层无需关心底层 SPI 时序,只需通过文件描述符发起传输请求。
调试提示: 使用
ls -l /dev/spi* 可查看系统已注册的 SPI 设备节点。若节点缺失,说明驱动未成功注册或资源管理器未启动。
3.2 spi-master 与 spi-slave 设备注册流程
SPI 驱动在资源管理器框架下,分为 spi-master(控制器端)和 spi-slave(从设备端)两个注册阶段。Master 负责管理 SPI 总线时序与片选,Slave 则代表挂载在总线上的具体外设。
3.2.1 spi-master 注册流程
- 分配并初始化 master 结构体:填充总线号、时钟频率范围、DMA 能力标志、片选极性等参数。
- 注册资源管理器路径:调用
spi_master_register()或直接使用resmgr_attach()绑定/dev/spiN路径。 - 绑定消息处理函数:将
io_devctl路由到 SPI 配置命令(如SPI_SET_MODE、SPI_SET_SPEED)。 - 硬件初始化:配置控制器寄存器、时钟门控、中断向量、DMA 通道。
- 挂载到系统设备树:在 QNX 的
devb-*或io-sock体系下注册,使上层可发现。
常见错误: 若 master 注册时未正确设置
max_speed_hz 或 mode_bits,后续 slave 配置可能因参数校验失败而无法 attach。
3.2.2 spi-slave 注册流程
- 创建 slave 实例:为每个 SPI 从设备分配
spi_slave_t结构体,指定片选 GPIO、工作模式、位宽、最大时钟。 - 绑定到 master:调用
spi_slave_attach(),将 slave 挂载到已注册的 master 总线上。 - 注册从设备路径:通常以
/dev/spiN.M格式创建节点(N=总线号,M=片选号)。 - 配置传输参数:通过
devctl()下发SPI_CS_CONFIG、SPI_XFER_MODE等命令。 - 准备 DMA 缓冲区:若启用 DMA,需注册物理连续内存并绑定 DMA 通道。
3.3 关键数据结构与参数映射
在注册过程中,驱动开发者需要填充以下核心数据结构。这些结构体直接决定了 SPI 的传输能力与兼容性。
| 数据结构 | 关键字段 | 说明 |
|---|---|---|
spi_master_t |
bus_num, max_speed_hz, mode_bits, dma_support |
定义总线编号、最高时钟、支持的模式位掩码、DMA 能力 |
spi_slave_t |
cs_gpio, mode, bits_per_word, speed_hz |
片选 GPIO、SPI 模式 (0/1/2/3)、字长、通信速率 |
spi_ioc_transfer |
tx_buf, rx_buf, len, cs_change, delay_usecs |
单次传输描述符,支持 tx/rx 分离、片选保持、帧间隔 |
spi_msg |
transfers, num_transfers, complete |
消息队列,包含多个 transfer,支持异步完成回调 |
架构要点: spi-master 是总线资源的拥有者,spi-slave 是总线资源的消费者。一个 master 可以挂载多个 slave,每个 slave 通过独立的片选线区分。在资源管理器模型中,master 负责仲裁并发访问,slave 只负责配置自身参数。
3.4 路径空间与用户态交互
注册完成后,用户态程序通过标准文件 I/O 与 SPI 驱动交互。典型的路径命名规则如下:
/dev/spi0— SPI 总线 0 的 master 控制节点(用于全局配置)/dev/spi0.0— 总线 0 上的从设备 0(片选 CS0)/dev/spi0.1— 总线 0 上的从设备 1(片选 CS1)
应用层通过 devctl(fd, SPI_CS_CONFIG, &config) 下发配置,通过 devctl(fd, SPI_XFER, &msg) 发起传输。驱动在 io_devctl 处理函数中解析命令,调用底层硬件接口完成操作。
调试技巧: 在驱动注册完成后,使用
pidin -p spi-driver -v 可查看资源管理器线程状态;使用 ioctl -v /dev/spi0.0 可测试设备节点是否响应。
3.5 注册流程中的常见问题与避坑
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
/dev/spiN 节点未出现 |
资源管理器未 attach 成功,或路径名冲突 | 检查 resmgr_attach() 返回值,确认 /dev/shmem 权限 |
slave attach 返回 ENODEV |
master 未就绪或总线号不匹配 | 确认 master 的 bus_num 与 slave 指定的 master 一致 |
| 片选 GPIO 无输出波形 | GPIO 未正确配置为 SPI 片选功能 | 检查 BSP 中 GPIO mux 设置,确认片选极性 |
| DMA 传输卡死 | DMA 通道未绑定或缓冲区未对齐 | 确保使用 mmap() 分配物理连续内存,检查 DMA 描述符链 |
架构约束: 在 QNX 中,spi-master 和 spi-slave 的注册顺序有严格依赖——必须先完成 master 注册并进入就绪状态,才能进行 slave 的 attach 操作。若在驱动初始化阶段并发注册,需使用同步原语(如
pthread_barrier)保证时序。