资讯动态

STM32 SPI通信协议详解:原理、配置与主从实验

发布时间:2026/10/14 20:15:03 来源:尧图企业网站定制
做嵌入式这几年我最大的体会就是很多同学学STM32卡住不是卡在GPIO和串口上而是卡在通信接口上。I2C动不动就死在应答信号上UART速度上去之后又容易丢帧这时候回头看SPI反而觉得它是三类常用接口里最容易上手、也最实用的一个。这篇文章是我《STM32学习心得》系列的第三十篇专门把SPI接口的原理、配置方法和实验过程完整梳理一遍希望帮正在学SPI的朋友少走弯路。SPI的全称是Serial Peripheral Interface串行外设接口最早由半导体行业提出并沿用至今。它只需要四根线就能完成全双工数据交换速度远高于UART和I2C而且协议本身非常自由没有复杂的地址帧、应答帧想怎么传就怎么传。从Flash存储、SD卡到各类传感器和显示屏甚至ADC芯片都能看到它的身影。不管你是刚把GPIO和UART玩明白的新手还是想系统复习SPI底层细节的熟手这篇文章应该都能帮到你。1. SPI协议原理与硬件架构拆解1.1 为什么嵌入式设备里离不开SPI先从一个最实际的角度说总线的速度。UART异步通信要收发双方约定波特率一旦时钟误差积累高速下就容易错位I2C虽然有时钟同步机制但每个字节后面都要跟一个应答位从机拉不住时钟线就会卡死整条总线。SPI则是同步通信主机自己产生时钟时钟沿一到收发同时完成一位不受波特率误差影响也没有应答机制拖后腿所以在需要高吞吐的场合SPI基本是第一选择。串行NOR Flash、串行NAND Flash这类存储芯片尤其依赖SPI。你想一下刷一个固件动辄几百KB如果用UART得传好久用I2C更是慢得让人着急而SPI在这种场景下能轻松跑到几十兆波特率速度差距是数量级的。另外SPI的接线非常简单主机的MOSI接从机的MOSI主机的MISO接从机的MISOSCK对SCKCS对CS四根线就能搞定。对于硬件工程师来说PCB布线也友好得多。还有一个容易被忽略的点是SPI的“协议自由”。I2C有严格的起始、停止、地址、应答格式而SPI除了时钟极性和相位必须匹配之外数据内容怎么编排完全由芯片手册决定。这意味着你可以针对不同从机设计非常灵活的通信帧这也是它能在那么多不同芯片上存活到今天的原因。1.2 四根信号线是如何协作的SPI的四根线分别是SCK、MOSI、MISO和CS。SCK是串行时钟由主机产生决定了一位一位数据在什么时刻被移入和移出MOSI全称Master Out Slave In数据从主机流向从机MISO全称Master In Slave Out数据从从机流向主机CS是片选信号低电平有效主机把它拉低就代表总线上的这个从机“被选中”可以开始通信了。要理解SPI的数据交换最好的类比是把主机和从机各想象成一个移位寄存器一根线把主机的输出端连到从机的输入端另一根线把从机的输出端连回主机的输入端。每次SCK来一个跳变沿两个移位寄存器就同时左移一位主机吐出一个bit给从机从机也吐出一个bit给主机。所以SPI是全双工的——发送和接收在同一时刻完成你要想从从机读一个字节就得先发一个字节出去哪怕发的是无效数据。这也解释了为什么SPI的读写经常是同一个操作主机调用一次收发函数发出一个字节同时收到一个字节。很多初学的人会纠结“这不是读操作吗为什么还要先写数据”其实就是这个原因。CS信号则保证了总线上多个从机不会互相干扰——同一时刻只有被拉低CS的那个从机响应时钟其他从机的输出处于高阻状态。1.3 CPOL/CPHA与四种工作模式SPI最容易把人绕晕的地方就在这里CPOL和CPHA。CPOL决定SCK空闲时的电平CPOL0表示空闲时SCK为低电平CPOL1表示空闲时SCK为高电平。CPHA决定数据在哪个边沿被采样CPHA0表示在第一个跳变沿采样CPHA1表示在第二个跳变沿采样。这两个参数组合起来就是SPI的四种Mode从Mode 0到Mode 3。SPI模式CPOLCPHASCK空闲电平数据采样沿Mode 000低第一个边沿上升沿Mode 101低第二个边沿下降沿Mode 210高第一个边沿下降沿Mode 311高第二个边沿上升沿市面上大多数从机芯片默认支持Mode 0也就是CPOL0、CPHA0所以很多人的SPI例程收到数据都能跑通。但千万别觉得Mode 0够用就行——有些传感器和存储器对时序有特别要求只支持Mode 2或者Mode 3。判断依据永远是芯片数据手册里的时序图它会明确告诉你数据是在上升沿还是下降沿建立、在哪个边沿采样。你和从机模式不一致最典型的现象就是数据能通但全是乱的没有规律。这里我再补一个理解技巧主机的CPOL和CPHA必须和从机完全一致因为SPI没有额外的握手协议时钟怎么跳、数据怎么采全靠双方约定。通信前先把两个设备的手册各自翻开确认模式再动手接线。1.4 数据帧格式与传输速率SPI的数据帧一般是8位或者16位但在STM32的标准外设库里最常用的是8位。存储芯片、传感器这类从机绝大多数都按字节组织寄存器所以8位帧足够用。数据的位序也有讲究STM32支持MSB先行和LSB先行通信双方必须一致否则会出现数据左右颠倒的情况——比如发出去的0x01变成了0x80。传输速率方面SPI的时钟频率由主机决定等效公式很简单SPI时钟 外设总线时钟 / 分频系数。在STM32F1系列里SPI1挂在APB2总线上APB2最高72MHzSPI2和SPI3挂在APB1总线上APB1最高36MHz。分频系数可以从2到256取2的整数次幂所以SPI1理论上最高能到36MHzSPI2最高18MHz。听起来很高但实际能不能跑满还要看从机支持的最高时钟频率和PCB走线质量。2. STM32的SPI外设配置要点解析2.1 STM32的SPI资源分布与时钟来源STM32F1系列常见的SPI外设有SPI1、SPI2、SPI3三个引脚复用关系固定不能随便换。我整理了一个最常用的映射表方便接线时查SPI外设时钟总线SCKMISOMOSI常用NSSSPI1APB2PA5PA6PA7PA4SPI2APB1PB13PB14PB15PB12SPI3APB1PB3PB4PB5PA15不同型号的引脚映射有差异比如某些大封装芯片上SPI1的引脚还能重映射到PB3/PB4/PB5查手册的“Alternate function mapping”表最靠谱。时钟总线这一点一定要记牢因为它直接决定分频后的最大频率。很多人把SPI2的分频写成2以为能到36MHz实际上APB1只有36MHz分频2之后最高18MHz所以在追求极限速度的场合优先用SPI1。2.2 GPIO复用配置SPI使能之前先得把引脚配置对。SCK和MOSI由主机输出时钟和数据所以要配成复用推挽输出GPIO_Mode_AF_PPMISO是从机的输出、主机的输入所以要配成浮空输入或者带上拉的输入模式CS如果走软件控制就配成普通推挽输出通信前手动拉低。这三个角色一旦搞混——比如把MISO配成了输出读数据就会出问题。为什么SCK和MOSI是“复用推挽”而不是“普通推挽”因为在STM32里外设信号和GPIO是分时复用同一组引脚的普通推挽模式下引脚由GPIO数据寄存器控制而改成复用推挽之后引脚的控制权才交给SPI外设这样SPI移位寄存器才能把数据送到引脚上。理解了“复用”这两个字后面看USART、定时器通道的配置也就一通百通了。另外GPIO速度这里建议直接配到最高50MHz尤其SCK频率高的场景。GPIO速度设置太低会让引脚边沿变缓数据采样点不稳定高速通信时就容易偶发错位。虽然50MHz对大多数场景都有余量但把这个配好能省去很多奇怪的时序问题。2.3 SPI结构体参数逐项拆解标准外设库里SPI初始化就靠一个SPI_InitStructure逐项设置之后调用SPI_Init()。我按实际配置顺序逐个说SPI_Direction选择双线全双工SPI_Direction_2Lines_FullDuplex这是最多见的用法单线发送、单线接收只在特殊从机时才用。SPI_Mode主机还是从机。一个总线里只能有一个主机其他都是从机。SPI_DataSize8位还是16位。绝大多数从机用8位按手册来。SPI_CPOL和SPI_CPHA前面说的四种模式全看从机手册。SPI_NSS硬件NSS还是软件NSS。我强烈建议新手用软件NSS。SPI_BaudRatePrescaler分频系数取值为2、4、8、16、32、64、128、256。SPI_FirstBitMSB还是LSB先行。这里插一句用HAL库的同学会发现这些参数在CubeMX里都能看到名称也差不多只是把CPOL/CPHA合并成SPI模式选项初始化流程更傻瓜化但底层逻辑和标准库完全一致。不管你用哪种库搞清楚这些参数的含义才是关键。2.4 硬件NSS与软件NSS的选择NSS这根线在STM32里支持两种玩法硬件NSS和软件NSS。硬件NSS模式下外部引脚的变化会直接影响SPI外设的工作状态主机的NSS引脚拉低SPI才认为总线可用软件NSS模式下NSS引脚不参与SPI外设仲裁只需要通过一个普通GPIO去控制从机的片选即可。我为什么建议新手用软件NSS因为硬件NSS牵扯到SPI外设内部状态自动切换比如多从机场景下切换不及时可能出现主机误以为总线忙导致第一个字节发送异常这类诡异问题。软件NSS就是普通GPIO控制拉低选中、拉高释放逻辑直接排查问题也简单。唯一要注意的是在软件NSS模式下SPI_InitStructure里的SPI_NSS仍要设置成SPI_NSS_Soft并且主机模式下还要把SSI位置1告诉外设“片选内部有效”——这个位漏配的话SPI会一直处于未选中状态数据根本发不出去。2.5 使能与收发流程初始化完成之后最后一步是SPI_Cmd使能外设这一步很基础但特别容易被漏掉。使能之后核心操作就是收发一体的读写函数先检查TXE标志发送缓冲区空空的就把要发的字节填入SPI数据寄存器接着芯片会自动产生时钟把数据移出去同时把从机移回来的数据放进接收缓冲区再检查RXNE标志接收缓冲区非空非空就把数据读回来。这个流程里TXE和RXNE的顺序不能反很多人收到乱码就是在一个字节还没移完时又强行发下一个导致数据覆盖。收发函数里还有一个很多人忽略的点读接收数据必须在RXNE置位之后进行否则会读到上一次的残留数据。从机模式下同样要走这套收发流程只是时钟由主机提供从机程序需要做的就是把数据提前准备好等待主机的时钟来把数据带走、把新的数据送进来。3. SPI通信实验主从收发与波形分析3.1 实验硬件准备与接线这个实验我选了两块开发板对接一块当主机一块当从机实现双向数据交换。实验的目的是让你亲眼看到SPI的时序主机发什么、从机回什么、波形长什么样。硬件准备如下两块STM32F1系列开发板杜邦线至少四根逻辑分析仪或者示波器一台没有逻辑分析仪的话用串口打印也能验证数据对不对。先把两块板的GND接一起否则电平参考不一致什么都白搭。接线表如下注意MOSI和MISO是对接的主机引脚功能从机引脚PA5SCKPA5PA7MOSIPA6PA6MISOPA7PA4CSPA4GND地GND这里有一个极其常见的坑很多人会把主机的MOSI接到从机的MISO结果两边都在输出总线打架。记住一点MOSI这个名字是站在主机角度命名的从机那边的对应引脚虽然手册上也叫MOSI但实际方向是输入。所以主机MOSI就是要连从机的MOSI引脚名一样方向相反用逻辑分析仪抓数据时别被两边的同名引脚绕晕。3.2 主机模式初始化代码主机代码我用标准外设库写这样寄存器逻辑比较直观。SCK用PA5、MISO用PA6、MOSI用PA7、CS用PA4全部挂在SPI1上。分频系数根据实验先选6472MHz除以64得到1.125MHz的SCK这个速度对杜邦线连接来说非常稳不容易出现信号质量问题。void SPI1_Init_Master(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); // PA5SCK, PA7MOSI - 复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // PA6MISO - 浮空输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); // PA4CS - 软件控制片选普通推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_Pin_4); // CS默认拉高不选中从机 SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode SPI_Mode_Master; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; // Mode 0 SPI_InitStructure.SPI_CPHA SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_64; SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; SPI_Init(SPI1, SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); }这段代码里我特意把CS初始状态设为高这样从机在上电到初始化完成的这段时间内不会被误触发。SCK和MOSI配成复用推挽MISO配成浮空输入这些前面已经解释过就不再重复了。3.3 从机模式初始化代码从机那边只需把SPI_Mode改成SPI_Mode_Slave其余参数必须和主机保持一致特别是CPOL和CPHA。从机的SCK和MOSI方向相对主机正好相反SCK是输入、MOSI是输入但MISO是输出。对应到GPIO配置上从机的MISO要配成复用推挽SCK和MOSI配成浮空输入。void SPI1_Init_Slave(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); // PA5SCK, PA7MOSI - 输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); // PA6MISO - 复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // PA4CS - 输入由主机控制这里不参与SPI仲裁 GPIO_InitStructure.GPIO_Pin GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode SPI_Mode_Slave; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; SPI_Init(SPI1, SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); }从机模式下不需要配置波特率分频因为时钟完全由主机提供这个参数在从机模式下意义不大。有些芯片手册会要求从机在片选拉低后的若干个时钟周期内准备好数据所以从机代码通常要在主循环里提前调用收发函数把要返回的数据预先放进发送缓冲区等主机的时钟一过来就能移出去。如果你的项目后面要做真正的多从机或严格帧同步建议把从机的CS接回SPI硬件NSS功能或者自己用外部中断感知CS下降沿这里为了让实验最简单先不处理这些。3.4 收发一体的核心读写函数无论主机还是从机单字节收发都可以用同一个函数区别只在于数据内容由谁决定。下面是SPI1的读写函数uint8_t SPI1_ReadWriteByte(uint8_t txData) { uint8_t rxData; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET); // 等待发送缓冲区空 SPI_I2S_SendData(SPI1, txData); // 填入要发送的数据 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET); // 等待接收缓冲区非空 rxData SPI_I2S_ReceiveData(SPI1); // 取回从机返回的数据 return rxData; }这个函数的核心思路就是“发一个、收一个”。第一次调用时从机还没返回数据你收到的可能是0x00或者0xFF这都正常因为从机还没来得及初始化。主机要做的往往是在正式读取从机数据之前先发送一个“读取命令”字节从机收到命令后在下一个字节的时钟里把数据返回。理解了这一点你就明白了那些复杂的Flash读写时序图是怎么来的。3.5 逻辑分析仪看波形代码跑起来之后把逻辑分析仪接到主机的PA5SCK、PA7MOSI、PA6MISO、PA4CS上逻辑分析仪的GND也一定要和板子的GND接在一起否则采样全是乱的。正常应该能看到这样的时序CS先是高电平通信开始瞬间被拉低SCK开始输出一串方波每个字节8个脉冲MOSI在SCK的上升沿附近输出数据位MISO也同步返回数据。在逻辑分析仪里选择SPI协议解码器把参数设为CPOL0、CPHA0对应的Mode 0就能直接看到MOSI和MISO线上解出来的十六进制数据。这里有个操作习惯很值得养成抓波形时别只抓一两个字节把连续几个字节的波形都抓下来。如果发现SCK波形中间有断续说明两个字节之间存在间隙这在某些高速从机上是不能接受的如果发现MISO数据在SCK边沿附近跳变说明时序裕量不够要么降速要么检查接线长度。3.6 实验结果与现象主机程序里写一个简单的测试逻辑CS拉低依次发送0xA5、0x5A、0x01、0x02四个字节每发一个字节把返回值存下来然后CS拉高把返回值和发送值通过串口打印。我的实测结果是从机把接收到的0xA5、0x5A、0x01、0x02原样返回主机读回这四个值收发一一对应。再把实验扩展一下把从机换成常见的SPI Flash芯片比如W25Q64这类用同样的主机代码发0x9F读ID命令然后连读三个字节返回的通常是厂家ID和芯片ID。这个实验的意义在于Flash芯片不需要你写从机程序它就是一个现成的SPI从机任何SPI时序问题都会被它无情地暴露出来。读ID能读到正确值说明你的SPI主机配置从GPIO到模式全部正确读不到回头按第四节的排查表逐步查。4. 常见问题与排查技巧实录4.1 读回来全是0xFF怎么回事这是SPI调试中出现频率最高的问题没有之一。现象是通信流程正常但MISO上读回来的数据永远是0xFF。看到这个现象第一反应不是怀疑代码而是按下面顺序排除先检查CS有没有被真正拉低很多人用万用表测CS在通信过程中确实是低电平但拉低的时机不对数据移出去了CS才变化再查MISO引脚是不是配成了输入模式、有没有虚焊或杜邦线松动最后确认从机是不是上电了、复位引脚有没有被拉死。如果从机是Flash这类芯片还有一个容易忽略的点某些芯片在读取命令之后需要等待一小段“转换时间”主机必须在命令字节和读数据字节之间插入几个空时钟周期或延时。这类参数在数据手册里会以tRD或状态寄存器的RDY位给出不看手册就闷头调试很容易在这里卡住。实际上很多接了Flash的裸机程序第一次读ID失败都是因为这里没留意。4.2 数据错位、第一位丢失字节错位比如主机发了4个字节从机读到的却是3个字节经常是片选建立时间不够。很多从机要求CS拉低之后再过一段时间才能收到第一个SCK边沿这段最小时间在手册里叫tCSS。如果主机在CS拉低的瞬间就立刻产生时钟从机还没准备好第一个字节就会丢。解决思路有两种一种是在CS拉低后加一小段延时再开始写数据另一种是每次通信前先检查SPI的BSY标志确认总线空闲。如果你在做多字节传输还要注意CS在整个传输过程中必须一直保持低电平不能在两个字节之间被拉高否则从机会认为一次事务已经结束。这类问题靠逻辑分析仪最容易确认看CS拉低和第一个SCK上升沿之间的时间差再对照手册里的tCSS参数。4.3 时钟极性和相位不匹配模式不匹配的典型症状是数据能收到而且“准乱”。所谓准乱就是错的规律性很强比如收到的字节永远是发送字节的左右镜像或者数据整体偏移了一位。出现这种规律性错误基本可以确定是CPOL或CPHA配错了而不是接线或硬件问题。排查方法很简单看从机数据手册的时序图确认数据是在上升沿采样还是下降沿采样空闲时钟是高还是低然后回头改SPI_CPOL和SPI_CPHA。如果手头有逻辑分析仪直接用解码功能选不同模式试哪种模式解出来的数据有意义就用哪种。这里提醒一句主机的CPOL/CPHA和从机的CPOL/CPHA必须一致但MOSI和MISO两条线上的数据建立时间可能不同个别高速芯片还会有数十纳秒的延迟参数遇到极高速率下的偶发错误要考虑数据信号延时而不是一味怪模式。4.4 连续发送时时钟之间有间隔很多从机对“一次传输中SCK必须连续”有要求但你会发现用上面的SPI1_ReadWriteByte连续调用时SCK波形在两个字节之间出现了停顿。原因在于每个字节传输完成后CPU需要检查TXE标志、再写入新的数据这个过程的时间是随机的取决于CPU时钟和代码执行路径。对于大多数从机来说这种字节间隙都能容忍但有些对时序敏感的芯片就会出错。解决办法最有效的是DMA。把要发送的数据放入DMA缓冲区配置好SPI的发送DMA通道让DMA连续补充发送数据寄存器CPU只需要在开始时触发一次后面的事情全部交给DMASCK就不会因为CPU执行速度而出现不可控的间隙。另一种办法是关闭SPI后再发送多个字节但那样会把CS时序搞得很复杂不如DMA干净。4.5 DMA传输的几个坑用DMA做SPI收发时常见问题有两个。第一个是DMA缓冲区的数据宽度配置错误SPI的8位数据对应DMA的字节模式如果你把DMA配成了半字模式数据会错位反过来SPI设置16位数据帧时DMA要配成半字模式。第二个问题出现在收发都开DMA的场景发送和接收用同一个DMA通道时要分时使用或者用两个不同的DMA通道否则数据会串。还有一个容易被忽略的坑是DMA结束后的外设关闭顺序。正确做法是先关闭DMA对应的通道再关闭SPI外设最后清标志位。如果顺序反了SPI控制器里可能残留未完成的传输状态下一次开启DMA时会收到一个脏数据。这些经验都是踩过坑之后才总结出来的写下来希望你能跳过。4.6 问题排查速查表把上面这些经验浓缩成一张表遇到问题对着查现象可能原因排查方向读回全是0xFFCS未有效拉低、MISO配置错误、从机未就绪测CS时序、查GPIO模式、查从机供电复位数据规律性错乱CPOL/CPHA不匹配、位序不一致核对从机手册时序图检查FirstBit第一个字节丢失CS建立时间不够CS拉低后延时检查tCSSSCK字节间有间隙CPU软件填充速度不稳定改用DMA传输DMA数据错位数据宽度和帧宽度不匹配8位对应字节模式16位对应半字模式偶发性乱码接线过长、无共地、速度过快降低分频、缩短杜邦线、确认共地这张表只覆盖了最高频的问题SPI世界里还有从机NSS硬件冲突、多从机总线争用这类进阶问题等你的主从通信跑顺之后再遇到新现象时用“逻辑分析仪手册对照”的方法基本都能定位。最后再分享一个我自己的习惯SPI调试永远从慢速开始。先把分频系数调到最大跑通了再逐步提速每一步提速后都观察波形和数据的稳定性。很多人一上来就追求几十兆的高频率结果在硬件问题上浪费大量时间其实只要时序逻辑正确速度只是参数问题。另一个实用技巧是写一个SPI回环测试把MOSI和MISO用一根线短接主机发什么就能读回什么这是检验SPI外设配置是否正确的最快方法不需要任何从机芯片。我在实际项目中排查SPI问题时第一步永远是回环测试第二步才是接真实从机。希望这篇心得能让你在SPI调试的路上少走几个弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑