4. 调试接口与工具

SPI这个接口,做嵌入式的人都不陌生。但说实话,真正把它调稳、调快,还能在工业现场不出问题,这里面门道不少。CH32V203的SPI模块继承了RISC-V内核的灵活性和沁恒一贯的外设设计思路,既有通用性,又有一些值得注意的细节。

这一章,我会从最基础的配置讲起,结合我实际调试中踩过的坑,带你一步步把SPI吃透。

4.1 SPI主从模式配置

CH32V203有3个SPI模块。SPI1挂在APB2上,SPI2和SPI3挂在APB1上。主频不同,这点在高速传输时要留意。

配置主模式,核心就几步:

  1. 时钟使能:RCC_APB2PeriphClockCmd或RCC_APB1PeriphClockCmd
  2. GPIO配置:SCK、MOSI设为推挽复用输出,MISO设为浮空输入
  3. SPI初始化:SPI_InitStructure设置模式、极性、相位、波特率
  4. 使能SPI:SPI_Cmd

从模式配置更简单,但有个关键点——片选信号必须由主机控制。从机模式下,NSS引脚的电平变化直接决定SPI是否响应。

主从模式差异速查表

项目主模式从模式
时钟来源内部产生外部SCK输入
波特率控制SPI_CR1寄存器由主机决定
NSS管理软件或硬件输出硬件输入
数据流方向主动发起被动响应
典型应用Flash、传感器、LCD多机通信、从设备

我个人习惯,主模式用软件管理NSS,这样灵活。从模式则必须硬件NSS,否则容易丢数据。

4.2 CPOL/CPHA相位极性详解

这个知识点,面试常考,项目里也常坑人。CPOL决定时钟空闲电平,CPHA决定数据采样时刻。

  • CPOL=0:空闲时SCK为低电平
  • CPOL=1:空闲时SCK为高电平
  • CPHA=0:第一个时钟边沿采样数据
  • CPHA=1:第二个时钟边沿采样数据

组合起来就是4种模式。大多数Flash芯片用模式0或模式3。模式0:CPOL=0, CPHA=0;模式3:CPOL=1, CPHA=1。这两种模式下,数据在上升沿采样,下降沿切换,时序最对称。

我曾经在一个项目中,把从设备的CPOL/CPHA搞反了。现象很诡异——能读到数据,但偶尔错一个字节。用示波器一看,采样点正好落在数据跳变沿上。嗯,这就是典型的时序余量不足。后来改成正确的模式,问题消失。

怎么确认?看从设备数据手册的时序图。手册上会标出SCK的极性和数据采样边沿。实在不行,用示波器抓一下,对比主机发出的波形和从机期望的波形。

4.3 DMA方式传输

SPI用轮询方式,CPU一直在等。数据量小还行,大了就浪费。DMA传输,说白了就是让DMA控制器帮你搬数据,CPU可以干别的。

CH32V203的SPI支持DMA请求。配置流程:

  1. 使能DMA时钟
  2. 配置DMA通道:源地址、目的地址、数据长度、传输方向
  3. 使能SPI的DMA发送或接收请求
  4. 启动DMA传输

这里有个坑——SPI的DMA传输必须同时开启发送和接收。因为SPI是同步协议,发一个字节的同时必须收一个字节。如果你只开发送DMA,接收缓冲区会溢出;只开接收DMA,发送线没有时钟。

我建议:用DMA环形缓冲区配合SPI中断。比如,接收DMA用循环模式,每次传输完成触发中断,在中断里处理数据。这样既保证了实时性,又减少了CPU占用。

DMA传输的另一个好处是速度稳定。轮询方式下,中断响应时间不确定,会导致SPI时钟抖动。DMA是硬件控制,时序一致性更好。

4.4 SPI Flash读写实战

W25Q系列Flash是SPI外设的经典案例。以W25Q64为例,容量8MB,支持标准SPI和Dual/Quad SPI。

基本操作流程:

  • 写使能:发送0x06指令,等待WIP位清零
  • 擦除:扇区擦除(0x20)、块擦除(0xD8)、整片擦除(0xC7)
  • 页编程:发送0x02,地址+数据,每页256字节
  • 读数据:发送0x03,地址+连续读取

读操作最简单,不需要先擦除。写操作必须先擦除再编程。擦除的最小单位是扇区(4KB)。

Flash操作时序要点

操作指令码地址长度数据长度典型时间
读ID0x9F0字节3字节~10μs
读数据0x033字节N字节~50ns/字节
页编程0x023字节1-256字节~0.5ms/页
扇区擦除0x203字节0字节~45ms
整片擦除0xC70字节0字节~10s

实际项目中,我习惯把Flash驱动封装成三层:

  • 底层:SPI收发函数,直接操作寄存器
  • 中间层:Flash指令封装,如flash_read、flash_write、flash_erase
  • 应用层:文件系统或参数存储接口

这样做的好处是,换Flash芯片时只需要改中间层,上层代码不动。

注意:Flash写操作前一定要检查WIP位。我见过有人连续发写指令,结果数据全丢了。因为前一次写还没完成,后一次指令被忽略。加个超时等待,别死等。

4.5 知识体系总览

下面这张图,把本章的核心知识点串起来了。你可以把它当作调试时的检查清单。

SPI总线驱动与调试知识体系 CH32V203 SPI模块 主从模式配置 主模式:内部时钟 从模式:外部SCK NSS管理方式 CPOL/CPHA相位极性 4种模式组合 模式0/3最常用 时序余量检查 DMA方式传输 发送+接收同时开 环形缓冲区 时序一致性 SPI Flash读写实战 写使能→擦除→编程→读 WIP位检查 三层驱动封装 调试要点:示波器抓波形 → 对比时序图 核心原则:先确认从设备时序要求,再配置主机参数,最后用示波器验证

这张图把SPI调试的四个关键环节串起来了。从主从模式配置开始,到CPOL/CPHA的匹配,再到DMA提升效率,最后落到Flash读写这个具体场景。每个环节都有对应的调试要点。

实际调试时,我建议按这个顺序排查:先确认硬件连接(SCK、MOSI、MISO、NSS),再检查SPI寄存器配置,然后用示波器看波形,最后才怀疑芯片本身。大部分问题,出在配置和时序上。

一个小技巧:调试SPI时,先读从设备的ID寄存器。如果能读到正确的ID,说明基本通信没问题。读不到?先查时钟和片选,再查极性配置。这个方法帮我省了不少时间。