Android SPI DMA驱动开发与HAL联调 - 第1节
1.1 SPI 协议概述
SPI(Serial Peripheral Interface,串行外设接口)是一种由 Motorola 公司提出的全双工、同步、主从式串行通信总线。在嵌入式系统中,SPI 因其高速、简单、硬件开销低的特点,被广泛用于连接传感器、ADC/DAC、LCD 控制器、Flash 存储器、RF 模块等外设。
1.1.1 SPI 总线物理层与信号线
SPI 总线使用四根信号线实现主从设备之间的通信:
| 信号线 | 全称 | 方向(主→从) | 功能描述 |
|---|---|---|---|
| SCLK | Serial Clock | 主→从 | 由主设备产生的同步时钟,决定数据传输速率 |
| MOSI | Master Out Slave In | 主→从 | 主设备发送数据至从设备的数据线 |
| MISO | Master In Slave Out | 从→主 | 从设备发送数据至主设备的数据线 |
| CS/SS | Chip Select / Slave Select | 主→从 | 片选信号,低电平有效,用于选中目标从设备 |
关键概念:SPI 是全双工协议——在每个时钟周期内,主设备通过 MOSI 发送一位数据,同时从设备通过 MISO 返回一位数据。这意味着 SPI 的每一次传输都同时完成发送和接收。
1.1.2 SPI 四种工作模式(CPOL & CPHA)
SPI 协议通过时钟极性(CPOL)和时钟相位(CPHA)的组合定义四种模式,决定了数据采样和切换的时序边界:
| 模式 | CPOL | CPHA | 时钟空闲电平 | 数据采样边沿 | 典型应用 |
|---|---|---|---|---|---|
| 模式 0 | 0 | 0 | 低电平 | 上升沿采样 | 多数 SPI Flash、SD 卡 |
| 模式 1 | 0 | 1 | 低电平 | 下降沿采样 | 某些 ADC 器件 |
| 模式 2 | 1 | 0 | 高电平 | 下降沿采样 | 部分 LCD 控制器 |
| 模式 3 | 1 | 1 | 高电平 | 上升沿采样 | 某些 RF 模块 |
联调要点:在 Android 驱动开发中,SPI 设备树节点必须正确配置
spi-cpol 和 spi-cpha 属性。模式不匹配将导致数据错位或通信失败,这是联调中最常见的低级错误之一。
1.2 DMA 传输优势
DMA(Direct Memory Access,直接存储器访问)是一种允许外设与内存之间直接传输数据的硬件机制,无需 CPU 逐字节干预。在 SPI 驱动中引入 DMA,可以显著降低 CPU 占用率并提升吞吐量。
1.2.1 PIO 模式 vs DMA 模式对比
| 对比维度 | PIO(Programmed I/O) | DMA(Direct Memory Access) |
|---|---|---|
| CPU 参与度 | 每个字节/字都需要 CPU 读写 FIFO | CPU 仅初始化传输,之后由 DMA 控制器接管 |
| 吞吐量 | 受限于 CPU 频率和中断响应延迟 | 接近总线带宽,适合高速外设 |
| CPU 占用率 | 高(传输期间 CPU 被占用) | 极低(CPU 可执行其他任务) |
| 适用场景 | 小数据量(< 64 字节)、低频率 | 大数据块(≥ 256 字节)、高频率 |
| 实时性 | 受中断延迟影响 | 硬件级传输,延迟可预测 |
联调陷阱:在 Android 系统中,如果 SPI 传输使用 PIO 模式处理大块数据(如摄像头 RAW 数据或 LCD 帧缓冲),会导致 CPU 长时间处于忙等状态,引发系统卡顿、音频断流甚至 ANR(Application Not Responding)。DMA 是解决此类问题的关键手段。
1.2.2 DMA 传输的典型流程
- 配置阶段:CPU 设置 DMA 源地址、目的地址、传输宽度(8/16/32 位)、传输计数和触发源(SPI 的 DMA 请求信号)。
- 启动阶段:CPU 使能 DMA 通道,DMA 控制器进入等待触发状态。
- 传输阶段:SPI 外设发出 DMA 请求,DMA 控制器从内存读取数据写入 SPI 发送 FIFO,同时从 SPI 接收 FIFO 读取数据写入内存。整个过程无需 CPU 介入。
- 完成阶段:传输计数归零后,DMA 控制器产生完成中断,通知 CPU 数据已就绪。
1.3 Android 驱动架构简介
Android 基于 Linux 内核,其驱动架构在标准 Linux 驱动模型之上增加了 Android 特有的 HAL(Hardware Abstraction Layer)和 HIDL(HAL Interface Definition Language)层,以实现硬件抽象、权限隔离和框架兼容。
1.3.1 Android 驱动分层模型
| 层级 | 组件 | 运行空间 | 职责 |
|---|---|---|---|
| 应用层 | App / Framework | Java 空间 | 调用 Android API 访问硬件功能 |
| 框架层 | System Server / Service | Java 空间 | 管理硬件服务,如 SensorService |
| HAL 层 | HAL Module / HIDL Server | Native (C++) | 封装内核驱动接口,提供稳定 ABI |
| 内核层 | Linux Kernel Driver | 内核空间 | 直接操作硬件寄存器,实现 SPI/DMA |
联调核心:SPI 驱动联调主要涉及内核层(SPI 控制器驱动、DMA 引擎驱动)和HAL 层(封装 SPI 传输接口、处理数据格式转换)。HAL 层是 Android 特有的关键环节,它决定了上层应用能否稳定访问 SPI 外设。
1.3.2 SPI 在 Android 内核中的驱动栈
- SPI 核心层(spi.c):提供通用的 SPI 总线注册、设备匹配、消息队列管理。
- SPI 控制器驱动:实现具体 SoC 的 SPI 控制器操作,如配置时钟、模式、FIFO、DMA 触发。
- SPI 设备驱动:挂载在 SPI 总线上的具体外设驱动,如
spi-sensor.c、spi-flash.c。 - DMA 引擎驱动:提供 dmaengine API,用于 SPI 控制器与内存之间的 DMA 传输。
1.4 联调目标与课程安排
1.4.1 联调核心目标
本课程围绕“SPI 协议 + DMA 传输 + Android 驱动”三条主线,旨在帮助学员掌握以下实战能力:
- 目标一:理解 SPI 协议时序与模式配置,能够在设备树中正确描述 SPI 从设备。
- 目标二:掌握 Linux DMA 引擎框架(dmaengine),实现 SPI 控制器驱动的 DMA 传输路径。
- 目标三:编写 Android HAL 模块,封装 SPI 传输接口,实现内核与框架的解耦。
- 目标四:完成从内核驱动到 HAL 层的全链路联调,使用逻辑分析仪和 trace 工具验证数据正确性。
1.4.2 课程章节总览
| 章节 | 主题 | 核心内容 |
|---|---|---|
| 第 1 章 | 课程导论 | SPI 协议、DMA 优势、Android 驱动架构、联调目标 |
| 第 2-4 章 | SPI 协议深入 | 时序分析、设备树配置、SPI 控制器驱动框架 |
| 第 5-7 章 | DMA 传输技术 | dmaengine API、SG 模式、环形缓冲区 |
| 第 8-10 章 | Android HAL 开发 | HIDL 接口定义、HAL 实现、权限管理 |
| 第 11-13 章 | 联调实战 | 环境搭建、调试技巧、性能优化、案例分析 |
学习建议:本课程采用“理论 + 代码 + 实验”三合一模式。建议学员在阅读每章正文后,同步在开发板上完成对应的驱动编译、加载和测试步骤,以加深对 SPI 和 DMA 硬件行为的理解。