
1.SPI介绍SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface)即串行外围设备接口是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间要求通讯速率较高的场合。1.1特点全双工通信主设备和从设备能够同时发送和接收数据提高数据传输效率。同步串行通信通过时钟信号同步数据传输确保数据的准确接收。主从架构一个主设备控制时钟和片选信号多个从设备通过片选线选择和通信。SPI总线设计为单主机多主机情况下需要额外硬件管理。通过多条片选线或外部解码器管理多个从设备。每个从设备通常需要独立片选线增加I/O资源消耗。高速传输能力通常支持几MHz甚至几十MHz的时钟频率适合高速数据交换。主机最大传输速率可达fPCLK/2。简单的硬件接口仅需4条主要信号线SCLK、MOSI、MISO、SS硬件设计简单。缺少标准错误检测机制SPI本身不提供CRC或校验功能错误检测需上层协议实现。无仲裁机制主设备完全控制总线不能自动处理总线冲突。不适合长距离通信由于没有差分信号和驱动能力适合板内或短距离通信。应用场景传感器数据采集闪存、EEPROM读写LCD显示屏驱动音频DAC/ADC通信其他高速外设接口1.2 物理连接SS( Slave Select)从设备选择信号线常称为片选信号线也称为 NSS、CS。当主机要选择从设备时把该从设备的 NSS 信号线设置为低电平该从设备即被选中即片选有效接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI 通讯以 NSS 线置低电平为开始信号以 NSS 线被拉高作为结束信号。SCK (Serial Clock)时钟信号线用于通讯数据同步。它由通讯主机产生决定了通讯的速率不同的设备支持的最高时钟频率不一样如 STM32 的 SPI 时钟频率最大为fpclk/2两个设备之间通讯时通讯速率受限于低速设备。主机SCK频率必须 ≤ 从设备最大支持频率。MOSI(Master Output Slave Input)主设备输出/从设备输入引脚。主机的数据从这条信号线输出从机由这条信号线读入主机发送的数据即这条线上数据的方向为主机到从机。传输数据时MSB和LSB先行都是可以设置的。MISO(Master Input,Slave Output)主设备输入/从设备输出引脚。主机从这条信号线读入数据从机的数据由这条信号线输出到主机即在这条线上数据的方向为从机到主机。传输数据时MSB和LSB先行都是可以设置的。1.3 协议时序四种模式下图中是模式1空闲时SCK低电平采样是偶边沿采样上升和下降各算一个边沿。NSS、SCK、MOSI 信号都由主机控制产生而 MISO 的信号由从机产生主机通过该信号线读取从机的数据。MOSI 与 MISO 的信号只在 NSS 为低电平的时候才有效在 SCK 的每个时钟周期 MOSI 和 MISO 传输一位数据。通讯的起始和停止信号标号①处NSS 信号线由高变低是 SPI 通讯的起始信号。NSS 是每个从机各自独占的信号线当从机在自己的 NSS 线检测到起始信号后就知道自己被主机选中了开始准备与主机通讯。在图中的标号⑥处NSS 信号由低变高是 SPI 通讯的停止信号表示本次通讯结束从机的选中状态被取消。数据有效性、如图②-⑤MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出在 SCK 的下降沿时被采样。即在 SCK 的下降沿时刻MOSI 及 MISO 的数据有效高电平时表示数据“1”为低电平时表示数据“0”。SPI 每次数据传输可以 8 位或 16 位为单位每次传输的单位数不受限制。不同的CPOL2.工程实践2.1 外设介绍在大容量产品和互联型产品上SPI接口可以配置为支持SPI协议或者支持2S音频协议。SPI接口默认工作在SPI方式可以通过软件把功能从SPI模式切换到I2S模式。注意在小容量和中容量产品上不支持I2S音频协议。通讯引脚SCK引脚SPI1/SPI2/SPI3芯片手册中告知最大速率18Mbps。NSS引脚有两种NSS模式软件和硬件。软件模式即可以用指定的GPIO来进行从设备片选。一般采用这种模式。MISO/MOSI引脚:数据收发引脚通过一个数据寄存器DR进行收发控制。主模式收发流程如下 (1) 控制 NSS 信号线产生起始信号 (2) 把要发送的数据写入到“数据寄存器 DR”中该数据会被存储到发送缓冲区 (3) 通讯开始SCK 时钟开始运行。MOSI把发送缓冲区中的数据一位一位地传输出去MISO 则把数据一位一位地存储进接收缓冲区中 (4) 当发送完一帧数据的时候“状态寄存器SR”中的“TXE 标志位”会被置 1表示传输完一帧发送缓冲区已空类似地当接收完一帧数据的时候“RXNE标志位”会被置1表示传输完一帧接收缓冲区非空 (5) 等待到“TXE 标志位”为 1时若还要继续发送数据则再次往“数据寄存器DR”写入数据即可等待到“RXNE 标志位”为 1时通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。2.2 MX配置说明Mode: Full-Duplex MasterFull-Duplex 表示SPI支持同时发送和接收数据。Master 表示该设备作为主机控制时钟和片选信号。Hardware NSS Signal: Disable是否启用硬件自动管理NSS片选信号Disable 表示由软件手动控制NSS引脚通常用户自行控制片选信号。Frame Format: MotorolaSPI数据帧格式STM32支持两种帧格式Motorola 标准SPI协议格式最常用。TI 表示Texas Instruments的特定帧格式较少用。、Data Size: 8 Bits每次传输的数据位宽这里表示每个数据单元是8位1字节。SPI也支持16位或其他位宽。First Bit: MSB First传输数据时先发送最高有效位MSB还是最低有效位LSB。Prescaler (for Baud Rate):4SPI时钟分频系数用于控制SPI时钟频率。因为SPI1挂接在APB2总线上需要除以4来保证不大于18Mbits/sCPOL 时钟极性SPI时钟空闲状态的电平。Low(0)空闲时SCK为低电平。High(1)空闲时SCK为高电平。CPHASPI时钟采样数据的时刻。1 Edge (First Edge)数据在第一个时钟边沿采样。2 Edge (Second Edge)数据在第二个时钟边沿采样。CPOL和CPHA组合决定SPI模式Mode0~Mode3。生成代码后spi.c中多出的关键代码hspi1.InstanceSPI1;hspi1.Init.ModeSPI_MODE_MASTER;hspi1.Init.DirectionSPI_DIRECTION_2LINES;hspi1.Init.DataSizeSPI_DATASIZE_8BIT;hspi1.Init.CLKPolaritySPI_POLARITY_LOW;hspi1.Init.CLKPhaseSPI_PHASE_1EDGE;hspi1.Init.NSSSPI_NSS_SOFT;hspi1.Init.BaudRatePrescalerSPI_BAUDRATEPRESCALER_4;hspi1.Init.FirstBitSPI_FIRSTBIT_MSB;hspi1.Init.TIModeSPI_TIMODE_DISABLE;hspi1.Init.CRCCalculationSPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial10;if(HAL_SPI_Init(hspi1)!HAL_OK){Error_Handler();}GPIO对应的代码略。2.3 和FLASH通信2.3.1 W25Q64 FLASH芯片芯片为NOR FLASH容量为64Mbit8MB其中WP 引脚可控制写保护功能当该引脚为低电平时禁止写入数据。我们直接接电源不使用写保护功能。HOLD 引脚可用于暂停通讯该引脚为低电平时通讯暂停数据输出引脚输出高阻抗状态时钟和数据输入引脚无效。我们直接接电源不使用通讯暂停功能。同时它支持 SPI 模式 0 及模式 3支持双线全双工使用MSB 先行模式支持最高通讯时钟为 104MHz数据帧长度为 8 位。2.3.2 片选GPIO配置这里配置默认输出高电平推挽输出同时打上标签。2.3.3 FLASH指令2.3.4 阻塞式读写//SPI片选voidSPI_FLASH_NSS(uint8_tnss){if(nss0){HAL_GPIO_WritePin(FLASH_NSS_GPIO_Port,FLASH_NSS_Pin,GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(FLASH_NSS_GPIO_Port,FLASH_NSS_Pin,GPIO_PIN_SET);}}//SPI收发1个字节 - 阻塞方式uint8_tSPI_FLASH_SendReadByte(uint8_tTxbyte){uint8_tRxByte0;//数据收发HAL_SPI_TransmitReceive(hspi1,Txbyte,RxByte,1,1000);returnRxByte;}因为是全双工通信要收也得发。2.3.5 读取FLASH 的ID信息来看看手册中给的读写时序图首先发送0x9F然后再读写三次获得ID信息。代码如下#defineDummy_Byte0xFF//SPI-FLASH 读取FLASHIDvoidSPI_FLASH_READ_FLASHID(){//进行片选SPI_FLASH_NSS(0);//发送 JEDEC 指令SPI_FLASH_SendReadByte(0x9F);//读生产厂商uint8_tMSPI_FLASH_SendReadByte(Dummy_Byte);//读存储器类型uint8_tTSPI_FLASH_SendReadByte(Dummy_Byte);//读容量uint8_tCSPI_FLASH_SendReadByte(Dummy_Byte);//片选结束SPI_FLASH_NSS(1);}最终读取的和下面W25Q64能匹配上。因为只是测试SPI读写FLASH这里不再罗列现学现卖即可。2.3 收发Dummy数据的作用我们看到FLASH W25Q64的读写其实在协议层是半双工的先发再收然后收的时候发送的是dummy数据发dummy的作用维持时钟同步主设备需继续发送 dummy 数据通常为 0x00 或固定值目的是持续生成 SCK 时钟让从设备有机会在 MISO 线上输出有效数据dummy 数据对主设备无意义仅用于 “驱动时钟”从设备也不会处理这些数据协议层已约定 “命令后的数据为有效输出”。2.4 SPI DMA读写SPI阻塞式读写需反复读取 SPI 状态寄存器SR注意是每bit都读经过实际测试11M频率下HAL库读写16bit耗时5us左右光轮询和检查参数的耗时就有3个us多。想要提速要么用DMA要么用LL库。DMA需要区分单次写还是轮询具体参考串口的DMA控制。DMA启动的性能大约在1-2us还是比阻塞快很多的。2.5 ADC采集电压待补充。高频率采集如果多个SPI对应多个ADC如何提升采集的性能呢如果用DMA因为频率太高那么如果想减少DMA中断次数可以只启用一个SPI的DMA比如先启动A再启动BB的半满中断时记录A的DMA当前位置因为先A后B有时间间隔然后B满中断时取出A和B的数据此时是对齐的以后也对齐了。当前必须是高速率比如64k如果1ms一次这种需考虑B的满中断时A可能那次的还没开始。