首页 / 资讯中心 / 文章详情

SPI技术系列 04 · SPI 协议与时序详解(CPOL/CPHA)

SPI技术系列 04 · SPI 协议与时序详解(CPOL/CPHA) ★ FEATURED ARTICLE
SPI 技术系列 · 持续更新中本系列从推挽电气层一路打到 Linux spi 子系统,把四根线背后的电气/协议/控制器/驱动/实战全拧成一根线。 想系统追更戳这里查看完整专栏【SPI 技术系列】 其他技术系列专栏欢迎关注、交流、共同成长【I2C 技术系列】 【串口技术系列】【RISC-V 架构系列】【Linux内核系列】本篇定位:SPI 协议核心就两个参数——CPOL(时钟极性)和 CPHA(时钟相位),组合出四模式。器件手册写法不统一(有的写 Mode 0,有的写 CPOL0 CPHA0,有的画波形),本篇把四模式彻底讲透,你看到任何器件手册都能正确配置控制器。CPOL/CPHA 错配是 SPI 第一大坑SPI 不通,90% 是 CPOL/CPHA 配错。器件要 Mode 0,你配 Mode 1,数据全错或全 0。四模式的本质是SCK 空闲电平 采样沿的两个选择,理解了原理,任何写法都能翻译。本篇是 SPI 协议的根,务必吃透。目录一、SPI 移位寄存器原理1.1 主从移位寄存器环1.2 移位方向1.3 全双工的副作用二、CPOL(时钟极性)2.1 CPOL 定义2.2 CPOL0 波形2.3 CPOL1 波形2.4 CPOL 的物理意义三、CPHA(时钟相位)3.1 CPHA 定义3.2 CPHA0(前沿采样)3.3 CPHA1(后沿采样)3.4 CPHA 的物理意义四、四模式对照4.1 四模式定义4.2 四模式波形4.3 模式选择原则4.4 主从模式必须一致五、位序 MSB/LSB5.1 MSB first(多数)5.2 LSB first(少数)5.3 配置5.4 软件反转六、完整传输时序6.1 一次完整传输6.2 关键时序参数6.3 多字节 burst七、器件手册翻译7.1 手册写法不一7.2 翻译流程7.3 常见器件模式八、关键问题 QAQ1:器件支持 Mode 0 和 Mode 3,选哪个?Q2:CPHA0 为什么建立时间紧?Q3:数据全是 0xFF 或 0x00,什么问题?Q4:数据位反(0xB5 变 0xAD),怎么办?Q5:SCK 空闲电平不对会怎样?Q6:Mode 0 的前沿采样是不是边沿驱动边采?九、实战案例案例 1:W25Q 读 ID 全 0xFF案例 2:ADC 数据位反案例 3:OLED 刷屏花,Mode 3 改 Mode 0 好了案例 4:SD 卡 SPI 模式不通案例 5:多从模式不一,切换出错案例 6:CPHA0 高速出错,改 CPHA1 好十、本篇小结与速查核心要点四模式速查排查速查延伸阅读参考资料一、SPI 移位寄存器原理1.1 主从移位寄存器环SPI 的本质是两个移位寄存器(主、从)首尾相接成环,靠 SCK 同步移位:主机移位寄存器 从机移位寄存器 ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │ │ │ │ │ │ │ │ │ MOSI→ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ↑ ←MISO ↑ └───────────────────────────────┘ SCK 同步移位每个 SCK 边沿,主从各移一位主机 MSB → MOSI → 从机 LSB(进入),同时从机 MSB → MISO → 主机 LSB8 个 SCK 后,主从寄存器内容互换SPI 是全双工:每次主发一位,从也发一位1.2 移位方向多数 SPI:MSB first(最高位先移)部分 IP/器件:LSB first(可配)主从必须一致,否则数据反1.3 全双工的副作用主想只读从:主也必须发(发什么不重要,从忽略)主想只写从:主也必须读(读到的可能是 0 或无效,丢弃)SPI 读写是同时的,没有纯读或纯写嵌入式视角:SPI 读寄存器的假写你读 SPI 传感器寄存器,要发读命令 寄存器地址,然后读数据。发命令时 MISO 上的数据是无效的(从机还没响应),你要继续发 dummy 字节(0xFF 或 0x00)产生 SCK,从机才会把数据放在 MISO 上。SPI 读 发 dummy 收数据,这是和 I2C 最大的不同。二、CPOL(时钟极性)2.1 CPOL 定义CPOL(Clock Polarity):SCK 空闲时的电平。CPOLSCK 空闲电平SCK 第一个边沿0低(0)上升沿(0→1)1高(1)下降沿(1→0)2.2 CPOL0 波形SCK ________/‾‾‾‾\___/‾‾‾‾\___/‾‾‾‾\___/‾‾‾‾\___ 空闲低 ↑ ↑ ↑ ↑ ↑ ↑ 上升 下降 上升 下降 上升 下降空闲(不传输)时 SCK0传输时 SCK 跳变(0→1→0→1…)CS 拉低时 SCK 已是低2.3 CPOL1 波形SCK ‾‾‾‾‾‾‾‾‾‾‾‾‾\___/‾‾‾‾\___/‾‾‾‾\___/‾‾‾‾ 空闲高 ↓ ↓ ↓ ↓ ↓ ↓ 下降 上升 下降 上升 下降 上升空闲时 SCK1传输时 SCK 跳变(1→0→1→0…)CS 拉低时 SCK 已是高2.4 CPOL 的物理意义CPOL 决定 SCK 空闲电平,影响CS 拉低到首边沿的初始状态器件 datasheet 会指定空闲电平 → 决定 CPOL三、CPHA(时钟相位)3.1 CPHA 定义CPHA(Clock Phase):数据在 SCK 的哪个边沿采样。CPHA采样边沿移位边沿0第一个边沿(CPOL0 上升,CPOL1 下降)第二个边沿1第二个边沿(CPOL0 下降,CPOL1 上升)第一个边沿3.2 CPHA0(前沿采样)CPOL1, CPHA0: SCK ‾‾‾‾‾‾‾\_____/‾‾‾‾‾‾\_____/‾‾‾‾‾‾\_____/‾‾‾‾‾‾‾ ↑采样 ↑移位 ↑采样 ↑移位 MOSI ‾‾‾‾X‾‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾X‾‾‾ (CS拉低后,数据在首个下降沿前就要准备好)数据在 SCK 第一个边沿采样数据必须在 CS 拉低后、首边沿前就准备好(MOSI 提前驱动)也叫前沿采样3.3 CPHA1(后沿采样)CPOL1, CPHA1: SCK ‾‾‾‾‾‾‾\_____/‾‾‾‾‾‾\_____/‾‾‾‾‾‾\_____/‾‾‾‾ ↑移位 ↑采样 ↑移位 ↑采样 MOSI ‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾X‾‾‾‾‾‾‾ (CS拉低后,SCK首个边沿驱动数据,第二个边沿采样)数据在 SCK 第二个边沿采样数据在第一个边沿被驱动,第二个边沿采样(有半周期建立时间)也叫后沿采样3.4 CPHA 的物理意义CPHA0:数据预先准备好,首边沿就采(快,但建立时间紧)CPHA1:首边沿驱动数据,次边沿采(有半周期建立,稳)CPHA1 更宽松,多数器件支持;CPHA0 对驱动时序要求严四、四模式对照4.1 四模式定义模式CPOLCPHA空闲电平采样边沿Mode 000低上升沿(第一个)Mode 101低下降沿(第二个)Mode 210高下降沿(第一个)Mode 311高上升沿(第二个)4.2 四模式波形Mode 0(CPOL0, CPHA0):CS: ‾‾‾‾‾‾‾\___________________________/‾‾‾‾‾‾‾ SCK: ________/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\______ 空闲0 ↑ ↓ ↑ ↓ ↑ ↓ D: ----[bit0] [bit1] [bit2] [bit3]--------Mode 1(CPOL0, CPHA1):CS: ‾‾‾‾‾‾‾\___________________________/‾‾‾‾‾‾‾ SCK: ________/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\______ 空闲0 ↑ ↓ ↑ ↓ ↑ ↓ D: ---------[bit0] [bit1] [bit2] [bit3]---Mode 2(CPOL1, CPHA0):CS: ‾‾‾‾‾‾‾\___________________________/‾‾‾‾‾‾‾ SCK: ‾‾‾‾‾‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾‾‾‾ 空闲1 ↓ ↑ ↓ ↑ ↓ ↑ D: ----[bit0] [bit1] [bit2] [bit3]----------Mode 3(CPOL1, CPHA1):CS: ‾‾‾‾‾‾‾\___________________________/‾‾‾‾‾‾‾ SCK: ‾‾‾‾‾‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾‾‾‾ 空闲1 ↓ ↑ ↓ ↑ ↓ ↑ D: --------[bit0] [bit1] [bit2] [bit3]----4.3 模式选择原则看器件 datasheet:器件会指定支持的模式(可能 1 个或多个)多数器件支持 Mode 0 和 Mode 3(最常用)Mode 0 是事实标准(空闲低,上升采样)4.4 主从模式必须一致主机 CPOL/CPHA 必须和从机一致不一致 → 采样错位 → 数据全错四模式速记Mode 0/Mode 3 最常用(空闲低上升采 / 空闲高上升采)Mode 0:空闲低,前沿(上升)采Mode 3:空闲高,后沿(上升)采两者采样边沿都是上升沿,区别在空闲电平和驱动时机五、位序 MSB/LSB5.1 MSB first(多数)最高位先移出/移入例:0xB5 1011 0101,先发 1,再 0,1,1,0,1,0,1多数 SPI 器件用 MSB first5.2 LSB first(少数)最低位先移例:0xB5 1011 0101,先发 1,0,1,0,1,1,0,1部分器件(某些 ADC、传感器)用 LSB first5.3 配置控制器寄存器配位序(STM32 CR1.LSBFIRST / DesignWare CTRLR0.SPI_SCPOL… 实为位序位)必须和器件一致配错 → 数据位反(0xB5 变 0xAD)5.4 软件反转若控制器不支持 LSB,软件预先反转:uint8_treverse_bits(uint8_tb){b(b0xF0)4|(b0x0F)4;b(b0xCC)2|(b0x33)2;b(b0xAA)1|(b0x55)1;returnb;}六、完整传输时序6.1 一次完整传输CS ‾‾‾‾‾‾‾\_______________________________/‾‾‾‾ ↑ ↑ CS下降 CS上升 (选中) (释放) SCK ‾‾‾‾‾‾‾‾‾‾\___/‾\_/‾\_/‾\_/‾\_/‾\_/‾‾‾‾‾‾‾ 空闲 ←─ 8 个 SCK 周期 ─→ 空闲 MOSI ‾‾‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ (主机发 8 位数据) MISO ‾‾‾‾‾‾‾‾X‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ (从机发 8 位数据)6.2 关键时序参数参数含义tCSSCS 下降到首 SCK 边沿(建立)tCST末 SCK 边沿到 CS 上升(保持)tSUMOSI 到 SCK 采样沿(建立)tHDSCK 采样沿后 MOSI 保持tDISCS 上升到 MISO 高阻tDAVSCK 移位沿到 MISO 驱动6.3 多字节 burstCS ‾‾‾‾\________________________________/‾‾‾ SCK /‾\_/‾\_/.../‾\_/‾\_/‾\_/‾\_/‾\_/‾\_ MOSI D0 D1 ... D7 D8 ...CS 一直低,连续传多字节每字节 8 个 SCK,字节间无间隔(或短间隔)Flash 读取常用(命令 地址 数据连续传)七、器件手册翻译7.1 手册写法不一器件手册对 SPI 模式的描述多种:写法 A:“SPI Mode 0”→ CPOL0, CPHA0写法 B:“CPOL0, CPHA0”→ Mode 0写法 C:“SCLK idle low, sample on rising edge”→ 空闲低(CPOL0),上升沿采(CPHA0,Mode 0)写法 D:画 SCK 波形 “sample”→ 看波形判断空闲电平和采样沿写法 E:“Mode 0 and Mode 3 supported”→ 两种都行,任选7.2 翻译流程1. 找空闲电平(空闲时 SCK 高/低?)→ CPOL 2. 找采样沿(上升/下降?)→ 配合 CPOL 推 CPHA - 采样沿 第一个边沿 → CPHA0 - 采样沿 第二个边沿 → CPHA1 例:空闲低(CPOL0),上升沿采样 上升沿是 CPOL0 的第一个边沿 → CPHA0 → Mode 0 例:空闲低(CPOL0),下降沿采样 下降沿是第二个边沿 → CPHA1 → Mode 1 例:空闲高(CPOL1),上升沿采样 上升沿是 CPOL1 的第二个边沿 → CPHA1 → Mode 37.3 常见器件模式器件模式W25Q FlashMode 0 / Mode 3SD 卡(SPI)Mode 0ILI9341 OLEDMode 3MCP3008 ADCMode 0/1LIS3DHMode 0/3MAX6675Mode 1nRF24L01Mode 0八、关键问题 QAQ1:器件支持 Mode 0 和 Mode 3,选哪个?A:任选,数据一致。但Mode 3 有时更稳:空闲高,CS 拉低时 SCK 已高,首边沿是下降(驱动数据),上升(采样),有半周期建立。Mode 0 空闲低,CS 拉低后数据要立即准备好等上升采,建立紧。高频时 Mode 3 稍优。实际多数用 Mode 0(习惯)。Q2:CPHA0 为什么建立时间紧?A:CPHA0 在第一个边沿采样。CS 拉低后,主机要在第一个 SCK 边沿前就把 MOSI 驱动好(tSU)。这意味着 MOSI 几乎和 CS 下降同时驱动,建立时间只有 CS 到 SCK 的间隔(tCSS)。CPHA1 则第一个边沿驱动数据,第二个边沿采,有半个 SCK 周期建立,宽松。Q3:数据全是 0xFF 或 0x00,什么问题?A:① CPOL/CPHA 错(采样时刻数据未稳定,采到空闲电平);② CS 没拉低(从机未选中,MISO 高阻读 0xFF);③ MISO 接错线;④ 器件未上电/未初始化。先查 CS 和模式。Q4:数据位反(0xB5 变 0xAD),怎么办?A:位序错。0xB5 1011 0101,反转 1010 1101 0xAD。改控制器 LSBFIRST 配置,或软件反转。MSB/LSB 主从必须一致。Q5:SCK 空闲电平不对会怎样?A:CPOL 配错,SCK 空闲电平和器件期望不符。可能导致:① CS 拉低时 SCK 跳变被误识别为时钟,多采一位;② 采样沿相反,数据错;③ 某些器件要求空闲电平严格,会不工作。Q6:Mode 0 的前沿采样是不是边沿驱动边采?A:不是同时。Mode 0:数据在 CS 拉低后就驱动好(数据先于 SCK 边沿),第一个上升沿采样。所以数据预先准备好,SCK 上升沿只是读。Mode 1 才是边沿驱动 边沿采(下降驱动,上升采)。九、实战案例案例 1:W25Q 读 ID 全 0xFF现象:W25Q SPI Flash 读 ID(0x9F),返回 0xFF FF FF。排查:CS 拉低了没?(示波器看 CS 波形)→ 拉低了CPOL/CPHA 对吗?→ 配的 Mode 1,但 W25Q 要 Mode 0/3改 Mode 0,正常读到 0xEF 40 18教训:模式错配,采样时刻错,采到空闲电平 0xFF。案例 2:ADC 数据位反现象:MCP3008 读 ADC,数值跳变不连续,像位反了。分析:MCP3008 是 LSB first,控制器配 MSB first,位序反。解决:控制器改 LSB first,数据正常。案例 3:OLED 刷屏花,Mode 3 改 Mode 0 好了现象:ILI9341 配 Mode 3 刷屏偶发花,改 Mode 0 正常。分析:ILI9341 实际支持 Mode 0/3,Mode 3 在该走线下建立时间紧,Mode 0 半周期建立更稳。解决:用 Mode 0。案例 4:SD 卡 SPI 模式不通现象:SD 卡 SPI 初始化返回 0xFF。排查:SD 卡 SPI 模式要 Mode 0,确认配了SD 卡初始化要降速到 400kHz 以下(发 CMD0)降速后初始化通过,再提频解决:初始化阶段强制降速 400kHz。案例 5:多从模式不一,切换出错现象:SPI 总线挂 Flash(Mode 0) OLED(Mode 3),切换器件后首字节错。分析:切换器件时没重新配 CPOL/CPHA,前器件的模式残留。解决:每次选中从机前,重新配控制器 CPOL/CPHA/速度/位序。Linux spi 框架支持每 transfer 配模式。案例 6:CPHA0 高速出错,改 CPHA1 好现象:30MHz SPI,Mode 0 偶发错,Mode 1 稳定。分析:Mode 0(CPHA0)建立时间紧,30MHz 采样窗口小,数据来不及稳定。Mode 1(CPHA1)有半周期建立,宽松。解决:器件支持 Mode 0/1,选 Mode 1。十、本篇小结与速查核心要点SPI 本质:主从移位寄存器环,SCK 同步,全双工CPOL:SCK 空闲电平(0 低 / 1 高)CPHA:采样沿(0 第一沿 / 1 第二沿)四模式:Mode 0(空闲低,上升采)最常用,Mode 3(空闲高,上升采)次之位序:MSB first 多数,LSB 少数,主从必须一致全双工:读写同时,读要发 dummy 产生 SCK器件手册翻译:看空闲电平 → CPOL,看采样沿 → CPHA模式错配 → 数据全错/全 0xFF多从模式不一:切换前重新配控制器四模式速查模式CPOLCPHA空闲采样沿典型器件Mode 000低上升(第一)W25Q/SD/MCP3008Mode 101低下降(第二)MAX6675Mode 210高下降(第一)罕见Mode 311高上升(第二)ILI9341排查速查现象可能原因全 0xFFCS 没拉低 / 模式错 / MISO 高阻全 0x00模式错 / 器件未上电位反LSB/MSB 配错偶发错速度过高 / SI / 模式边界首字节错模式残留(多从切换)延伸阅读[[01-SPI电气特性与物理层]] —— 推挽驱动[[05-SPI片选与多从机制]] —— CS 与多从[[06-SPI数据帧与位序]] —— 数据帧详解[[08-SPI控制器寄存器与IP架构]] —— 模式寄存器配置[[13-SPI调试与排查]] —— 模式错配排查[[04-I2C协议与时序详解]] —— 对比 I2C 协议参考资料NXP AN10658(SPI modes)Motorola SPI Block Guide(V3.06)W25Q / ILI9341 / MCP3008 DatasheetSTM32 Reference Manual(SPI CR1.CPOL/CPHA)SPI 技术系列 00· 总目录 · 上一篇:[[03-SPI速度与电气约束]] ·下一篇:[[05-SPI片选与多从机制]]✨ 感谢你的阅读 ✨技术之路漫漫分享是为了更好地交流。如果本文的内容对你有启发希望能得到你的支持 点赞|⭐ 收藏| 关注如果你在调试过程中遇到了其他问题欢迎在评论区 留言我们一起探讨。关注我一起交流底层开发的那些事儿
阅读完成 · 觉得有帮助?
咨询建站