📚 SPI 技术系列 · 持续更新中
本系列从推挽电气层一路打到 Linux spi 子系统,把"四根线"背后的电气/协议/控制器/驱动/实战全拧成一根线。
👉 想系统追更,戳这里查看完整专栏:
👉 其他技术系列专栏,欢迎关注、交流、共同成长:
本篇定位:协议是软件视角,控制器是硬件实现。本篇讲 SPI 控制器 IP 内部------状态机、移位寄存器、分频器、FIFO/DMA,以及 STM32 / DesignWare / RISC-V SoC 的寄存器差异,重点讲 QSPI 控制器的特殊寄存器。读完你能看懂任何 SPI 控制器手册,配出 QSPI + XIP。
懂控制器才能配 QSPI + XIP标准 SPI 寄存器简单(配模式/速度/数据)。QSPI 控制器复杂得多------命令/地址/数据位宽、dummy 周期、XIP 模式都要配寄存器 。你 RISC-V SoC 启动用 QSPI XIP,寄存器配错就启动不了。本篇是 BSP 转型的硬件基础。对照 【I2C 技术系列 08】I2C 控制器寄存器与 IP 架构 看,理解控制器抽象的共通。
目录
- [一、控制器 IP 总框图](#一、控制器 IP 总框图)
- 二、核心组成模块
-
- [2.1 分频器](#2.1 分频器)
- [2.2 移位寄存器](#2.2 移位寄存器)
- [2.3 CS 控制](#2.3 CS 控制)
- [2.4 FIFO](#2.4 FIFO)
- [2.5 DMA 接口](#2.5 DMA 接口)
- 三、主模式状态机
-
- [3.1 简化状态机](#3.1 简化状态机)
- [3.2 关键状态](#3.2 关键状态)
- [3.3 QSPI 状态机扩展](#3.3 QSPI 状态机扩展)
- 四、通用寄存器组
-
- [4.1 通用寄存器(概念)](#4.1 通用寄存器(概念))
- [4.2 关键状态位](#4.2 关键状态位)
- [五、STM32 SPI 寄存器](#五、STM32 SPI 寄存器)
-
- [5.1 STM32F1/F4 SPI 寄存器](#5.1 STM32F1/F4 SPI 寄存器)
- [5.2 CR1 关键位](#5.2 CR1 关键位)
- [5.3 配 SPI 主模式(Mode 0, 8bit, 1MHz)](#5.3 配 SPI 主模式(Mode 0, 8bit, 1MHz))
- [5.4 收发](#5.4 收发)
- [5.5 STM32 QSPI(QUADSPI)](#5.5 STM32 QSPI(QUADSPI))
- [六、DesignWare SSI 寄存器](#六、DesignWare SSI 寄存器)
-
- [6.1 DesignWare SSI(Synopsys)](#6.1 DesignWare SSI(Synopsys))
-
- [6.2 寄存器](#6.2 寄存器)
- [6.3 CTRLR0 关键位](#6.3 CTRLR0 关键位)
- [6.4 配 Quad-SPI 读](#6.4 配 Quad-SPI 读)
- [七、QSPI 控制器特殊寄存器](#七、QSPI 控制器特殊寄存器)
-
- [7.1 命令配置寄存器(QSPI 专属)](#7.1 命令配置寄存器(QSPI 专属))
- [7.2 配置 Quad Fast Read(0x6B)](#7.2 配置 Quad Fast Read(0x6B))
- [7.3 XIP 模式](#7.3 XIP 模式)
- [7.4 采样延迟(RX_SAMPLE_DLY)](#7.4 采样延迟(RX_SAMPLE_DLY))
- [八、典型 IP 对照](#八、典型 IP 对照)
-
- [8.1 STM32 SPI](#8.1 STM32 SPI)
- [8.2 DesignWare SSI](#8.2 DesignWare SSI)
- [8.3 NXP LPC SPI](#8.3 NXP LPC SPI)
- [8.4 RISC-V SoC](#8.4 RISC-V SoC)
- [九、关键问题 Q&A](#九、关键问题 Q&A)
-
-
- [Q1:STM32 SPI 配 Mode 0,CPOL/CPHA 怎么写?](#Q1:STM32 SPI 配 Mode 0,CPOL/CPHA 怎么写?)
- [Q2:DesignWare 配 Quad 模式,哪些位关键?](#Q2:DesignWare 配 Quad 模式,哪些位关键?)
- [Q3:QSPI 读 Flash,寄存器怎么配?](#Q3:QSPI 读 Flash,寄存器怎么配?)
- Q4:OVR(溢出)什么时候发生?
- [Q5:XIP 模式寄存器怎么配?](#Q5:XIP 模式寄存器怎么配?)
- [Q6:RX_SAMPLE_DLY 配多少?](#Q6:RX_SAMPLE_DLY 配多少?)
-
- 十、实战案例
-
- [案例 1:STM32 SPI Mode 0 配成 Mode 3](#案例 1:STM32 SPI Mode 0 配成 Mode 3)
- [案例 2:DesignWare Quad 模式不工作](#案例 2:DesignWare Quad 模式不工作)
- [案例 3:QSPI 读首字节错](#案例 3:QSPI 读首字节错)
- [案例 4:OVR 频繁](#案例 4:OVR 频繁)
- [案例 5:XIP 启动慢](#案例 5:XIP 启动慢)
- [案例 6:RISC-V SoC QSPI 启动失败](#案例 6:RISC-V SoC QSPI 启动失败)
- 十一、本篇小结与速查
一、控制器 IP 总框图
┌─────────────────────────────────────────┐
│ SPI 控制器 IP │
│ │
APB/ │ ┌──────────┐ ┌──────────┐ │
AHB ←──┼─→│ 寄存器组 │ ←→ │ 控制逻辑 │ │
总线 │ │ CON/STAT │ │ (状态机) │ │
│ │ DR/BAUD │ └────┬─────┘ │
│ └──────────┘ │ │
│ ↓ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 分频器 │ ←→ │移位寄存器│ │
│ │(SCK生成) │ │ (收发) │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ┌────┴─────┐ ┌────┴─────┐ │
│ │ 中断逻辑 │ │ CS 控制 │ │
│ │ DMA 接口 │ │ FIFO │ │
│ └──────────┘ └────┬─────┘ │
└───────────────────────┼─────────────────┘
│
SCK / MOSI / MISO / CS(推挽)
(QSPI: DQ0~DQ3)
- 寄存器组:软件接口
- 控制逻辑:状态机,协议实现
- 分频器:从 PCLK 分频出 SCK
- 移位寄存器:串并转换
- CS 控制:片选生成(硬件 CS 或 GPIO)
- FIFO/DMA:批量传输
二、核心组成模块
2.1 分频器
PCLK → 分频器 → SCK
分频系数 = PCLK / fSCK(可配,2 的幂或步进)
- STM32:BR2:0 选 2/4/8/.../256 分频
- DesignWare:CLKDIV 寄存器,更灵活
2.2 移位寄存器
- 串行 ↔ 并行转换
- 发:写 DR → 移位到 MOSI
- 收:MISO 移位 → 读 DR
- 位序可配(MSB/LSB)
- 字长可配(4~32 位)
2.3 CS 控制
- 硬件 CS:控制器自动管 CS(配寄存器选 CS 引脚)
- GPIO CS:软件管(写 GPIO)
- QSPI 多 CS:可选 Flash(主)/RAM(副)
2.4 FIFO
- TX FIFO:软件一次写多字节,硬件逐字节发
- RX FIFO:硬件逐字节收,软件批量读
- 减少中断次数
- 8~32 字节典型
2.5 DMA 接口
- TX FIFO 半空 → DMA 搬数据进来
- RX FIFO 半满 → DMA 搬数据出去
- 大块传输省 CPU
三、主模式状态机
3.1 简化状态机
┌─────────┐
│ IDLE │←──────────────┐
└────┬────┘ │
│ 软件写 DR / 启动 │
↓ │
┌─────────┐ CS 拉低 │
│ START │──────────────┐│
└─────────┘ ↓│
┌────────────┐
│ 移位传输 │
│ (发/收) │
└─────┬──────┘
│ 传完(N 个 SCK)
↓
┌────────────┐
│ CS 拉高 │
└─────┬──────┘
│
└─→ IDLE
3.2 关键状态
| 状态 | 含义 | 卡住原因 |
|---|---|---|
| IDLE | 空闲 | --- |
| START | CS 拉低,准备 | CS 时序违规 |
| TX | 发送移位 | FIFO 空(UNDERRUN) |
| RX | 接收移位 | FIFO 满(OVERRUN) |
| DONE | CS 拉高,完成 | --- |
3.3 QSPI 状态机扩展
QSPI 多阶段(命令/地址/dummy/数据),状态机更复杂:
IDLE → CMD 阶段 → ADDR 阶段 → DUMMY 阶段 → DATA 阶段 → DONE
(1/2/4/8线) (1/2/4/8线) (空转) (1/2/4/8线)
- 各阶段位宽独立配
- 阶段间自动切换
四、通用寄存器组
4.1 通用寄存器(概念)
| 寄存器 | 含义 |
|---|---|
| CON/CTRL | 控制(使能/主从/模式/位序/字长) |
| STAT/SR | 状态(TXE/RXNE/BSY/OVR/MODF) |
| DR | 数据(写发/读收) |
| BAUD/BR | 分频(速度) |
| CS/NSS | 片选控制 |
| INTEN | 中断使能 |
| INTSTAT | 中断状态 |
| FIFO_CTRL | FIFO 配置 |
| DMA | DMA 配置 |
4.2 关键状态位
| 位 | 含义 |
|---|---|
| TXE | 发送寄存器空(可写下一字节) |
| RXNE | 接收寄存器非空(可读) |
| BSY | 忙(传输中) |
| OVR | 溢出(读不及时,数据覆盖) |
| MODF | 主模式错(CS 被外部拉低) |
| CRCERR | CRC 错(若用 CRC) |
| UDR | 欠载(从模式发不及时) |
五、STM32 SPI 寄存器
5.1 STM32F1/F4 SPI 寄存器
| 寄存器 | 含义 |
|---|---|
| CR1 | 控制1(SPE/BR/CPOL/CPHA/LSBFIRST/SSI/SSM/MSTR) |
| CR2 | 控制2(RXNEIE/TXEIE/ERRIE/SSOE/TXDMAEN/RXDMAEN) |
| SR | 状态(BSY/OVR/MODF/CRCERR/UDR/CHSIDE/TXE/RXNE) |
| DR | 数据(读写双缓冲) |
| CRCPR | CRC 多项式 |
| RXCRCR | RX CRC |
| TXCRCR | TX CRC |
5.2 CR1 关键位
bit15 DFF: 0=8bit, 1=16bit
bit14 BIDIMODE: 双线模式(单线双向)
bit11 RXONLY: 只收
bit9 CPOL: 时钟极性
bit8 CPHA: 时钟相位
bit7 LSBFIRST: 位序
bit6 SPE: SPI 使能
bit5 BIDIOE: 双线输出使能
bit4~2 BR[2:0]: 分频(2/4/8/.../256)
bit3 SSI: 内部 CS
bit2 SSM: 软件CS管理
bit1 MSTR: 主模式
bit0 CPHA... (重定义,看型号)
5.3 配 SPI 主模式(Mode 0, 8bit, 1MHz)
c
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // 开时钟
SPI1->CR1 = SPI_CR1_MSTR // 主模式
| SPI_CR1_SSM | SPI_CR1_SSI // 软件 CS
| (3 << 3) // BR=3,8 分频(PCLK/8)
| SPI_CR1_CPOL // ← CPOL,Mode 0 这里清
| SPI_CR1_CPHA; // ← CPHA,Mode 0 这里清
// Mode 0: CPOL=0, CPHA=0,上面两个位都不置
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | (3<<3);
SPI1->CR1 |= SPI_CR1_SPE; // 使能
5.4 收发
c
// 发一字节
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = data;
while (!(SPI1->SR & SPI_SR_RXNE));
uint8_t recv = SPI1->DR;
5.5 STM32 QSPI(QUADSPI)
H7 等有独立 QSPI 外设,寄存器:
| 寄存器 | 含义 |
|---|---|
| QUADSPI_CR | 控制(PRESCALER/EN/TCEN) |
| QUADSPI_DCR | 设备配置(CKMODE/CSHT/FSIZE) |
| QUADSPI_CCR | 命令配置(IMODE/ADMODE/ABMODE/DMODE/DCYC/FMODE) |
| QUADSPI_AR | 地址 |
| QUADSPI_DR | 数据 |
| QUADSPI_SR | 状态(FTL/FTF/SMF/TCF/BUSY) |
| QUADSPI_FCR | 标志清除 |
- CCR 配各阶段位宽(IMODE 指令/ADMODE 地址/DMODE 数据)
- DCYC:dummy 周期数
- FMODE:读/写/内存映射(XIP)
六、DesignWare SSI 寄存器
6.1 DesignWare SSI(Synopsys)
- ARM/RISC-V SoC 常用(RK/RISC-V 厂商)
- Linux spi-dw 驱动
- 寄存器清晰
6.2 寄存器
| 寄存器 | 含义 |
|---|---|
| CTRLR0 | 控制(SCPOL/SCPH/TMOD/DFS/SPI_FRF) |
| CTRLR1 | 帧数(收模式) |
| SSIENR | 使能 |
| MWCR | Microwire(忽略) |
| SER | 从机使能(CS 选) |
| BAUDR | 分频(0=禁用,2/4/...) |
| TXFTLR | TX FIFO 阈值 |
| RXFTLR | RX FIFO 阈值 |
| TXFLR | TX FIFO 当前 |
| RXFLR | RX FIFO 当前 |
| SR | 状态(BUSY/TFNF/TFE/RFNE/RFF) |
| IMR | 中断屏蔽 |
| ISR | 中断状态 |
| DR | 数据(0~36 号,各一个端口) |
| RCSAMPLE | 采样 |
| RX_SAMPLE_DLY | 采样延迟(抗 Skew) |
6.3 CTRLR0 关键位
SPI_FRF[1:0]: 帧格式(0=标准,1=Dual,2=Quad,3=Octal)
DFS: 数据帧大小(4~32bit)
CFR: ...
TMOD[1:0]: 传输模式(00=收发,01=发,10=收,11=EEPROM读)
SCPOL: CPOL
SCPH: CPHA
- SPI_FRF 选 Dual/Quad/Octal
- TMOD 选只发/只收/收发
6.4 配 Quad-SPI 读
c
SSI->SSIENR = 0; // 禁用,配寄存器
SSI->BAUDR = 4; // 分频(PCLK/4)
SSI->CTRLR0 = (2<<21) // SPI_FRF=Quad
| (7<<16) // DFS=8bit
| (0<<4) // SCPOL=0
| (0<<3); // SCPH=0(Mode 0)
SSI->CTRLR1 = len - 1; // 收 N 字节
SSI->RX_SAMPLE_DLY = 1; // 采样延迟(抗 Skew)
SSI->SER = 1; // 选 CS0
SSI->SSIENR = 1; // 使能
// 发命令 + 地址(QSPI 控制器自动处理位宽,见厂商手册)
七、QSPI 控制器特殊寄存器
7.1 命令配置寄存器(QSPI 专属)
| 字段 | 含义 |
|---|---|
| INSTRUCTION | 命令字节(0x6B 等) |
| IMODE | 指令阶段位宽(0/1/2/4/8 线) |
| ADMODE | 地址阶段位宽 |
| ADSIZE | 地址长度(8/16/24/32bit) |
| ABMODE | Alternate Byte 位宽(可选) |
| ABSIZE | Alternate Byte 长度 |
| DMODE | 数据阶段位宽 |
| DCYC | dummy 周期数 |
| FMODE | 功能模式(0=写,1=读,3=内存映射 XIP) |
7.2 配置 Quad Fast Read(0x6B)
c
QSPI->CCR = (0x6B << 24) // INSTRUCTION = 0x6B
| (1 << 20) // IMODE = 1 线
| (1 << 16) // ADMODE = 1 线(地址 1 线)
| (2 << 12) // ADSIZE = 24bit
| (0 << 10) // ABMODE = 无
| (3 << 8) // DMODE = 4 线(数据 4 线)
| (6 << 0); // DCYC = 6 dummy
// FMODE 在触发时配(0=写命令,1=读数据,3=XIP)
7.3 XIP 模式
- FMODE=3:内存映射,CPU 直接访问
- 控制器自动发命令(配 CCR 固化)
- 地址 = CPU 访问地址
7.4 采样延迟(RX_SAMPLE_DLY)
- 高速 QSPI,SCK 到数据采样有 Skew
- 配采样延迟(几个 ns)对齐采样窗口
- 抗 Skew,提速度
八、典型 IP 对照
8.1 STM32 SPI
- F1/F4:8/16 位,传统 SPI
- H7:32 位,FIFO 深,独立时钟,高速
- QSPI:独立外设,支持 XIP
8.2 DesignWare SSI
- ARM/RISC-V SoC 常用
- 灵活(4~32 位,Dual/Quad/Octal)
- Linux spi-dw 驱动成熟
8.3 NXP LPC SPI
- 简洁,寄存器少
- FIFO + DMA
8.4 RISC-V SoC
- 芯来 NA300 / Andes 平台:多用 DesignWare 或自研 IP
- 寄存器风格接近 DesignWare
- QSPI 控制器独立(启动用)
嵌入式视角:RISC-V 板子 SPI 多是 DesignWare 风格
重点掌握:CTRLR0 配模式/位宽/帧格式,BAUDR 配速度,SER 选 CS,DR 收发,SR 状态。QSPI 启动控制器是独立的,配 CCR 各阶段位宽 + DCYC + FMODE(XIP)。
九、关键问题 Q&A
Q1:STM32 SPI 配 Mode 0,CPOL/CPHA 怎么写?
A :Mode 0 = CPOL=0, CPHA=0。STM32 CR1 中 CPOL 和 CPHA 位都清零(不置)。代码:SPI1->CR1 = MSTR | SSM | SSI | BR;(不 | CPOL,不 | CPHA)。
Q2:DesignWare 配 Quad 模式,哪些位关键?
A:
- CTRLR0.SPI_FRF = 2(Quad 帧格式)
- CTRLR0.DFS = 7(8bit,值=8-1)
- 命令/地址位宽靠控制器具体型号的扩展寄存器(如 STM32 QSPI CCR,或 DesignWare QSPI 扩展)
- RX_SAMPLE_DLY 配采样延迟
Q3:QSPI 读 Flash,寄存器怎么配?
A:
- 禁用控制器(SSIENR=0)
- 配分频(BAUDR)
- 配命令寄存器(INSTRUCTION=0x6B, IMODE/ADMODE/DMODE 位宽, DCYC dummy)
- 配 FMODE=1(读)
- 写地址寄存器(AR)
- 使能(SSIENR=1)→ 自动发命令 + 地址 + dummy + 读数据
- 读 DR 取数据
Q4:OVR(溢出)什么时候发生?
A:RX FIFO 满,新数据覆盖旧数据。原因:CPU 读 DR 不及时(中断/DMA 没跟上)。检测:SR.OVR=1。处理:读 SR 清标志,读 DR 丢数据,重传。
Q5:XIP 模式寄存器怎么配?
A:
- 配 CCR(命令/位宽/dummy)------和普通读一样
- FMODE = 3(内存映射)
- 使能控制器
- 之后 CPU 访问 Flash 映射地址,控制器自动发命令返回数据
- 注意:I-Cache 必须开,否则性能极差
Q6:RX_SAMPLE_DLY 配多少?
A:看 SI 和速度。50MHz 以下可不配(0)。高速(> 50MHz)配 1~2(几个 ns 延迟),对齐 SCK 采样窗口。值太大反而采样错位。调试时从 0 开始加,找稳定的最小值。
十、实战案例
案例 1:STM32 SPI Mode 0 配成 Mode 3
现象:SPI 通信全错。
分析:CPOL 位错置(配成 Mode 3,器件要 Mode 0)。
解决:CR1 不置 CPOL/CPHA(Mode 0)。
案例 2:DesignWare Quad 模式不工作
现象:CTRLR0 配 SPI_FRF=2(Quad),但数据仍 1 线。
分析:只配了帧格式,没配命令阶段位宽(DMODE 仍 1 线)。
解决:配命令寄存器(如 STM32 QSPI CCR)的 DMODE=4 线,数据阶段才 4 线。
案例 3:QSPI 读首字节错
现象:QSPI 读 Flash,首字节错。
分析:DCYC(dummy)配 0,Flash 没切换到 4 线输出就开始读。
解决:DCYC 配 6~8(查 Flash datasheet)。
案例 4:OVR 频繁
现象:高速 SPI 读,RX FIFO 频繁溢出。
分析:CPU 中断响应慢,读 DR 不及时,FIFO 满溢出。
解决:改 DMA(自动搬,不靠 CPU),或增大 FIFO 阈值。
案例 5:XIP 启动慢
现象:QSPI XIP 启动后,CPU 执行极慢。
分析:没开 I-Cache,每条指令走 QSPI。
解决:开 I-Cache(硬件支持),性能提升几十倍。
案例 6:RISC-V SoC QSPI 启动失败
现象:N300 平台 QSPI 启动失败,挂死。
分析:QSPI 控制器配置错(命令位宽/dummy 不对),Flash 没正确响应。
解决:按 Flash datasheet(W25Q)配 DCYC=6,IMODE=1 线,DMODE=4 线,启动正常。
十一、本篇小结与速查
核心要点
- 控制器 IP = 寄存器组 + 控制逻辑(状态机)+ 分频器 + 移位寄存器 + CS 控制 + FIFO/DMA
- 状态机:IDLE → START → TX/RX → DONE
- 通用寄存器:CON/STAT/DR/BAUD/CS/INTEN/FIFO/DMA
- STM32:CR1(CPOL/CPHA/BR/LSBFIRST/MSTR)+ SR(TXE/RXNE/BSY/OVR/MODF)+ DR
- DesignWare:CTRLR0(SPI_FRF/DFS/TMOD/SCPOL/SCPH)+ BAUDR + SER + DR + SR
- QSPI 特殊:CCR(IMODE/ADMODE/DMODE/DCYC/FMODE)+ AR + DR
- XIP:FMODE=3,内存映射,CPU 直接访问 Flash
- RX_SAMPLE_DLY:抗 Skew,高速配
- 关键位:TXE(可写)/RXNE(可读)/BSY/OVR/MODF
DesignWare 关键寄存器速查
| 寄存器 | 作用 |
|---|---|
| CTRLR0 | 模式/位宽/帧格式/CPOL-CPHA |
| BAUDR | 分频(速度) |
| SER | CS 选 |
| DR | 数据收发 |
| SR | 状态(BUSY/TFE/RXNE) |
| IMR/ISR | 中断 |
| RX_SAMPLE_DLY | 采样延迟 |
QSPI 配置速查
| 阶段 | 配置 |
|---|---|
| 命令 | INSTRUCTION + IMODE(1/4 线) |
| 地址 | ADSIZE + ADMODE(1/4 线) |
| dummy | DCYC(6~8) |
| 数据 | DMODE(4 线) |
| 功能 | FMODE(0=写,1=读,3=XIP) |
延伸阅读
- \[04-SPI协议与时序详解-CPOL-CPHA] ------ 模式寄存器
- \[07-SPI双线四线八线-QSPI-Octal] ------ QSPI 协议
- \[09-SPI传输模式-轮询-中断-DMA] ------ 寄存器使用
- \[10-SPI错误处理与恢复] ------ OVR/MODF 处理
- \[11-SPI Linux驱动框架] ------ Linux 寄存器封装
- I2C 技术系列 08 I2C 控制器寄存器与 IP 架构 ------ 对比 I2C 控制器
参考资料
- Synopsys DesignWare SSI Databook
- STM32 RM0090/RM0433(SPI/QSPI 章节)
- Linux drivers/spi/spi-dw.c
- W25Q Datasheet(QSPI 命令时序)
SPI 技术系列 00· 总目录 · 上一篇:\[07-SPI双线四线八线-QSPI-Octal] · 下一篇:\[09-SPI传输模式-轮询-中断-DMA]
✨ 感谢你的阅读 ✨
技术之路漫漫,分享是为了更好地交流。
如果本文的内容对你有启发,希望能得到你的支持:
👍 点赞 | ⭐ 收藏 | 👀 关注
如果你在调试过程中遇到了其他问题,
欢迎在 评论区 💬 留言,我们一起探讨。
关注我,一起交流底层开发的那些事儿!🚀