☰
SPI技术系列 05 · SPI 片选与多从机制
2026/10/18 2:25:13 网站建设 项目流程

📚 SPI 技术系列 · 持续更新中

本系列从推挽电气层一路打到 Linux spi 子系统,把"四根线"背后的电气/协议/控制器/驱动/实战全拧成一根线。

👉 想系统追更,戳这里查看完整专栏:
【SPI 技术系列】
👉 其他技术系列专栏,欢迎关注、交流、共同成长:
【I2C 技术系列】 【串口技术系列】【RISC-V 架构系列】【Linux内核系列】


本篇定位:SPI 没有 I2C 那样的 7bit 地址,多从靠 CS 片选。本篇讲独立 CS(星型)、菊花链(Daisy Chain)、广播三种多从机制,以及 CS 时序、GPIO 软控 CS、Linux 框架 CS。读完你能设计任何 SPI 多从系统。

CS 是 SPI 的"寻址"机制
I2C 用地址寻址,SPI 用 CS 片选寻址。理解 CS 的工作方式,是理解 SPI 多从的关键。菊花链更是 SPI 独有的多从绝技(I2C 做不到),值得掌握。对照 【I2C 技术系列 07】I2C 寻址与协议扩展 看,理解两种寻址哲学的差异。


目录

  • 一、CS 片选的作用
    • 1.1 CS 的三大作用
    • 1.2 CS 让 MISO 多从共享成为可能
    • 1.3 CS vs I2C 地址
  • 二、独立 CS 多从(星型)
    • 2.1 接线
    • 2.2 传输流程
    • 2.3 优势
    • 2.4 缺点
    • 2.5 适用
  • 三、菊花链多从(Daisy Chain)
    • 3.1 原理
    • 3.2 工作流程
    • 3.3 菊花链 vs 独立 CS
    • 3.4 适用场景
    • 3.5 菊花链的代码
    • 3.6 菊花链的限制
  • 四、广播
    • 4.1 原理
    • 4.2 适用
    • 4.3 缺点
    • 4.4 菊花链 vs 广播
  • 五、CS 时序要求
    • 5.1 CS 建立保持
    • 5.2 CS 时序违规的后果
    • 5.3 CS 与 SCK 空闲电平
    • 5.4 CS 上升沿锁存
  • 六、GPIO 软控 CS
    • 6.1 为什么用 GPIO 软控
    • 6.2 软控 CS 代码
    • 6.3 硬件 CS vs GPIO CS
    • 6.4 Linux GPIO CS
  • 七、关键问题 Q&A
    • Q1:菊花链 3 个从机,主发 24 位,各从收到什么?
    • Q2:菊花链能读吗?
    • Q3:独立 CS 多从,MISO 共享会不会冲突?
    • Q4:CS 拉低后多久能发 SCK?
    • Q5:GPIO CS 在高速 SPI 有什么问题?
    • Q6:多个从机模式不同,怎么处理?
  • 八、实战案例
    • 案例 1:多从 MISO 冲突,数据错乱
    • 案例 2:菊花链 LED 驱动,顺序错
    • 案例 3:Flash 读首字节错
    • 案例 4:GPIO CS 高速抖动
    • 案例 5:多从模式不同,切换后首字节错
    • 案例 6:菊花链一个从机故障,全链断
  • 九、本篇小结与速查
    • 核心要点
    • 多从机制对照
    • CS 时序速查
  • 延伸阅读
  • 参考资料

一、CS 片选的作用

1.1 CS 的三大作用

  1. 选中从机:CS 拉低,从机 MISO 输出使能(推挽驱动)
  2. 未选中高阻:CS 高,从机 MISO 高阻,不影响总线
  3. 帧同步:CS 下降沿 = 传输开始,CS 上升沿 = 传输结束

1.2 CS 让 MISO 多从共享成为可能

Master MISO ──┬── 从0 MISO(CS0 高,高阻) ├── 从1 MISO(CS1 低,驱动)← 当前选中 └── 从2 MISO(CS2 高,高阻)
  • 同一时刻只有一个 CS 有效
  • 只有被选中的从机驱动 MISO,其他高阻
  • 这就是 SPI 多从共享 MISO 的物理基础(对比 I2C OD 开漏线与)

1.3 CS vs I2C 地址

维度SPI CSI2C 地址
寻址方式硬件(引脚选)软件(协议层发地址)
占用资源每从一根 CS(引脚多)共享两线(引脚少)
切换速度快(拉 GPIO)慢(发 START+地址)
冲突可能无(CS 独立)有(地址冲突)
适合异构多器件同类多器件

嵌入式视角:CS 的代价是引脚
SPI 挂 5 个从机,要 5 根 CS。MCU 引脚紧张时这很奢侈。I2C 两线挂 128 个器件。所以 SPI 适合"少而高速"的场景(Flash+显示+ADC),I2C 适合"多而低速"的场景(传感器阵列)。工程上常混合用:高速设备 SPI,低速设备 I2C。


二、独立 CS 多从(星型)

2.1 接线

Master ├─ SCK ────┬───────┬───────┐ (共享) │ │ │ │ ├─ MOSI ───┬───────┬───────┤ (共享) │ │ │ │ ├─ MISO ───┬───────┬───────┤ (共享) │ │ │ │ ├─ CS0 ────┘ │ │ → 从0 ├─ CS1 ────────────┘ │ → 从1 ├─ CS2 ────────────────────┘ → 从2
  • SCK/MOSI/MISO 三线共享
  • 每从独立 CS
  • 主机拉低某 CS 选中对应从机

2.2 传输流程

// 读从机 1gpio_low(CS1);// 选中从机 1spi_transfer(cmd);// 发命令spi_transfer(dummy);// 读数据gpio_high(CS1);// 释放

2.3 优势

  • 各从独立寻址,简单
  • 可任意时刻选某从
  • 各从速率/模式可不同(切换时重配控制器)

2.4 缺点

  • 走线多(每从一根 CS)
  • 多从共享 SCK/MOSI/MISO,负载电容大,高速 SI 受影响
  • MCU 引脚消耗多

2.5 适用

  • 异构多器件(Flash + 显示 + ADC)
  • 各从需要独立访问
  • 多数 SPI 系统用这种

三、菊花链多从(Daisy Chain)

3.1 原理

多个从机的移位寄存器串行级联,数据从主机 MOSI 进入第一个从机,其 DOUT 接下一个从机的 DIN,末从 DOUT 回主机 MISO:

Master ── MOSI ──→ 从0 DIN 从0 DOUT ──→ 从1 DIN 从1 DOUT ──→ 从2 DIN 从2 DOUT ──→ Master MISO Master ── SCK ────┬─────┬─────┬── (共享,所有从) Master ── CS ─────┬─────┬─────┬── (共享,所有从同时选中)
  • 所有从共享 SCK 和 CS
  • 数据串行穿过各从的移位寄存器
  • 一次传输 N×8 个 SCK(N 个从机,每个 8 位)

3.2 工作流程

3 个从机,每个 8 位移位寄存器,菊花链连接: - 主机发 24 个 SCK - 前 8 位:数据进入从0,从0 原数据移到从1,从1 原数据移到从2,从2 原数据移出(到 MISO) - 中 8 位:继续移位 - 后 8 位:继续移位 - 24 个 SCK 后:从0 收到原"中8位",从1 收到原"后8位",从2 收到原"前8位" (各从最终收到主发的不同 8 位段)

菊花链的数据分配
主发 24 位 [D0…D7][D8…D15][D16…D23],24 个 SCK 后:

  • 从0 收到 [D16…D23](最后 8 位,因为最先进入的移到最远)
  • 从1 收到 [D8…D15]
  • 从2 收到 [D0…D7](最先发的 8 位,移到从2)

顺序与直觉相反:先发的数据移到链尾的从机。软件要按"链尾从机的数据先发"组织。

3.3 菊花链 vs 独立 CS

维度菊花链独立 CS
CS 线数1(共享)N(每从一根)
寻址靠位置(链中顺序)靠 CS 选
独立访问不能(必须全链传)能
延迟大(N×8 SCK)小(8 SCK)
数据流串行穿过并行选一
适合同类器件级联(ADC/LED驱动)异构器件

3.4 适用场景

  • LED 驱动级联:WS2812(虽然单线,但思想类似)、TLC5940 LED 驱动
  • 多通道 ADC:多个 ADC 移位寄存器级联,一次读所有通道
  • 移位寄存器扩展 IO:74HC595(输出)/74HC165(输入)级联
  • 同类器件批量配置:多个相同 DAC/ADC 同时更新

3.5 菊花链的代码

// 3 个从机菊花链,每个收 8 位// 想让 从0 收 0xAA, 从1 收 0xBB, 从2 收 0xCC// 发送顺序:从2 的数据先发(0xCC),再从1(0xBB),再从0(0xAA)voiddaisy_chain_write(uint8_td0,uint8_td1,uint8_td2){gpio_low(CS);spi_transfer(d2);// 先发链尾数据spi_transfer(d1);spi_transfer(d0);// 最后发链头数据gpio_high(CS);// CS 上升沿锁存各从数据}// 调用:daisy_chain_write(0xAA, 0xBB, 0xCC)

3.6 菊花链的限制

  • 各从必须移位寄存器兼容(同型号或同移位长度)
  • 不能独立访问某从(必须全链传)
  • 一次传输 N×8 SCK,延迟大
  • 链中一个从机故障,全链断

四、广播

4.1 原理

所有 CS 同时拉低,主机 MOSI 发的数据所有从机同时收:

Master ── MOSI ──┬── 从0 ├── 从1 └── 从2 Master ── CS ────┬── 从0 CS ├── 从1 CS └── 从2 CS (全部同时拉低)
  • 所有从 CS 接同一根线(或多个 CS 同时拉低)
  • 主机发数据,所有从同时收相同数据

4.2 适用

  • 同类器件同步更新(多个 DAC 同时输出)
  • 固件广播(少见)
  • 配置同步

4.3 缺点

  • 不能读(MISO 多从冲突,推挽不能线与)
  • 只能单向(主→从)
  • 各从必须同命令格式

4.4 菊花链 vs 广播

  • 菊花链:各从收不同数据(链中位置决定)
  • 广播:各从收相同数据

五、CS 时序要求

5.1 CS 建立保持

CS ‾‾‾‾‾\_____________________________/‾‾‾ ↑ ↑ CS ↓ ↓ CS SCK 空闲 \___/‾\_/‾\_/‾\___/ 空闲 ←tCSS→ ←tCST→ 建立 保持
参数含义典型
tCSSCS 下降到首 SCK 边沿50~100ns
tCST末 SCK 边沿到 CS 上升50~100ns
tCSHCS 高电平最小脉宽(两次传输间)50~100ns

5.2 CS 时序违规的后果

  • tCSS 太短:CS 拉低后 SCK 立即来,从机还没准备好,首字节错
  • tCST 太短:末 SCK 后 CS 立即拉高,从机没完成最后一位,末字节错
  • CS 抖动:EMI 让 CS 误触发,误传输

5.3 CS 与 SCK 空闲电平

  • CS 拉低时,SCK 应已在空闲电平(CPOL 决定)
  • 不能 CS 拉低时 SCK 还在跳变(会被误识别为时钟)

5.4 CS 上升沿锁存

  • 部分器件(Flash / 移位寄存器)在 CS 上升沿锁存移入的数据
  • 即:SCK 移位期间数据进移位寄存器,CS 上升沿把数据锁到输出/执行
  • 这种器件 CS 时序尤其关键

六、GPIO 软控 CS

6.1 为什么用 GPIO 软控

  • 控制器硬件 CS 引脚不够(多从时)
  • 需要灵活控制(菊花链、广播)
  • 硬件 CS 时序固定,不满足特殊器件

6.2 软控 CS 代码

voidspi_read_flash(uint8_tcmd,uint32_taddr,uint8_t*buf,intlen){gpio_low(CS_FLASH);// 软控 CS 拉低spi_transfer(cmd);// 发命令spi_transfer(addr>>16);spi_transfer(addr>>8);spi_transfer(addr);for(inti=0;i<len;i++){buf[i]=spi_transfer(0xFF);// dummy 换数据}gpio_high(CS_FLASH);// 软控 CS 拉高}

6.3 硬件 CS vs GPIO CS

维度硬件 CSGPIO CS
时序精确(自动)靠软件(有抖动)
灵活性差好
多从受限(引脚少)任意(GPIO 够就行)
高速优软件开销大
Linux 支持自动cs-gpios 属性

6.4 Linux GPIO CS

&spi0 { cs-gpios = <&gpio0 4 0>, <&gpio0 5 0>, <&gpio0 6 0>; /* 3 个 GPIO CS */ flash@0 { reg = <0>; compatible = "w25q128"; }; /* 用 cs-gpios[0] */ oled@1 { reg = <1>; compatible = "ili9341"; }; /* 用 cs-gpios[1] */ };
  • Linux spi 框架支持 GPIO CS(cs-gpios)
  • 框架自动管理 CS 拉低/拉高
  • 详见 [[11-SPI Linux驱动框架]]

七、关键问题 Q&A

Q1:菊花链 3 个从机,主发 24 位,各从收到什么?

A:主发 [D0…D7][D8…D15][D16…D23],24 个 SCK 后:

  • 从0(链头,最靠近 MOSI)收到 D16…D23
  • 从1 收到 [D8…D15]
  • 从2(链尾,最靠近 MISO)收到 D0…D7

先发的数据移到链尾。软件要"链尾从机数据先发"。

Q2:菊花链能读吗?

A:能。主发 24 个 dummy SCK,各从的移位寄存器内容串行移出到 MISO。主收 24 位 = [从2 原][从1 原][从0 原]。菊花链读写都行,但都是"全链批量",不能独立读某从。

Q3:独立 CS 多从,MISO 共享会不会冲突?

A:不会。每个从 MISO 是三态:CS 未选中高阻,选中推挽驱动。同一时刻只有一个 CS 有效 → 只有一个从驱动 MISO。前提:CS 时序正确,切换前一个 CS 拉高(tDIS),再拉低下一个 CS。

Q4:CS 拉低后多久能发 SCK?

A:看器件 datasheet 的 tCSS(典型 50~100ns)。CS 拉低后等 tCSS 再发 SCK,给从机响应时间。高速时这个间隔占周期比例要注意。GPIO 软控 CS 时,GPIO 操作本身有 μs 级开销,远大于 tCSS,一般够。

Q5:GPIO CS 在高速 SPI 有什么问题?

A:GPIO 拉低/拉高是单独操作,和 SCK 之间有软件延迟(几 ns 到 μs)。高速时 SCK 周期 20ns,GPIO 延迟可能让 CS 时序违规。50MHz+ 建议硬件 CS。Linux 框架的 GPIO CS 在高速时也可能有抖动。

Q6:多个从机模式不同,怎么处理?

A:每次切换从机前,重新配控制器 CPOL/CPHA/速度/位序。Linux spi 框架支持每 transfer 配模式(spi_transfer.cs_change+ 模式字段),框架自动重配。裸机要手动重配控制器寄存器。


八、实战案例

案例 1:多从 MISO 冲突,数据错乱

现象:3 从独立 CS,读从机 1 偶发读到从机 0 的数据。

分析:切换从机时,从机 0 的 CS 没拉高就拉低从机 1 的 CS,两个 CS 同时有效,MISO 冲突。

解决:严格"先拉高旧 CS,等 tDIS,再拉低新 CS"。

案例 2:菊花链 LED 驱动,顺序错

现象:3 个 TLC5940 LED 驱动菊花链,写入数据后 LED 亮度和预期反。

分析:菊花链数据顺序错——先发的数据移到链尾,软件按"链头先发"组织,反了。

解决:发送顺序反过来(链尾从机数据先发)。

案例 3:Flash 读首字节错

现象:W25Q 读 Flash,首字节恒错,后续字节对。

分析:CS 拉低后立即发 SCK,tCSS 不够,从机没准备好,首字节采错。

解决:CS 拉低后 delay 几 ns(或加几个 dummy SCK)再发命令。

案例 4:GPIO CS 高速抖动

现象:50MHz SPI 用 GPIO CS,偶发首字节错。

分析:GPIO 操作有 μs 级软件延迟和抖动,CS 与 SCK 时序不严格。

解决:改用硬件 CS,或降到 30MHz。

案例 5:多从模式不同,切换后首字节错

现象:Flash(Mode 0)+ OLED(Mode 3)共总线,切到 OLED 后首字节错。

分析:切换时没重配 CPOL/CPHA,OLED 用了 Flash 的 Mode 0。

解决:每次切换从机前重配控制器模式。

案例 6:菊花链一个从机故障,全链断

现象:3 从菊花链,中间从机故障,链尾从机收不到数据。

分析:菊花链数据串行穿过,中间从机移位寄存器坏,数据断流。

解决:菊花链可靠性差,关键场景用独立 CS。或加链路检测(末从 MISO 反馈)。


九、本篇小结与速查

核心要点

  • CS 是 SPI 的寻址机制:拉低选中,MISO 推挽驱动;拉高未选,MISO 高阻
  • 独立 CS(星型):每从一 CS,独立访问,异构多器件首选
  • 菊花链:数据串行穿过各从,共享 CS,适合同类级联(ADC/LED)
  • 广播:所有 CS 同拉低,单向主→从,各从收相同数据
  • 菊花链数据顺序:先发的移到链尾,软件反向组织
  • CS 时序:tCSS(建立)/ tCST(保持),违规首末字节错
  • GPIO 软控 CS 灵活但高速有抖动,50MHz+ 用硬件 CS
  • 多从模式不同:切换前重配控制器
  • Linux GPIO CS:cs-gpios设备树属性

多从机制对照

机制CS 线独立访问适合
独立 CS 星型N 根能异构多器件
菊花链1 根不能同类级联
广播1 根不能同步更新

CS 时序速查

参数含义典型
tCSSCS↓ 到首 SCK50~100ns
tCST末 SCK 到 CS↑50~100ns
tDISCS↑ 到 MISO 高阻50~100ns
tCSHCS 高最小脉宽50~100ns

延伸阅读

  • [[01-SPI电气特性与物理层]] —— 推挽与三态
  • [[02-SPI信号完整性与时钟分布]] —— 多从走线 SI
  • [[04-SPI协议与时序详解-CPOL-CPHA]] —— CS 与模式
  • [[06-SPI数据帧与位序]] —— 多字节 burst
  • [[11-SPI Linux驱动框架]] —— Linux CS 管理
  • [[07-I2C寻址与协议扩展]] —— 对比 I2C 寻址

参考资料

  • Motorola SPI Block Guide
  • W25Q Datasheet(CS 时序)
  • TLC5940 Datasheet(菊花链)
  • Linux Documentation/spi/spi-summary

SPI 技术系列 00· 总目录 · 上一篇:[[04-SPI协议与时序详解-CPOL-CPHA]] ·下一篇:[[06-SPI数据帧与位序]]


✨ 感谢你的阅读 ✨

技术之路漫漫,分享是为了更好地交流。
如果本文的内容对你有启发,希望能得到你的支持:

👍 点赞|⭐ 收藏|👀 关注

如果你在调试过程中遇到了其他问题,
欢迎在评论区 💬留言,我们一起探讨。

关注我,一起交流底层开发的那些事儿!🚀


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询