- 通信方式:高速全双工
- 作用: 主机与从机之间同步交换数据
- 时钟: 最大18Mhz,支持DMA,可以配置SPI协议
- 通信线
-
MISO 主输入从输出
MOSI 主输出从输入
SCLK 时钟信号,主设备产生
CS 片选信号,主设备控制
-
- 协议层
- 起始信号
- NSS 信号由高变低
- 终止信号
- NSS 信号由低变高
- 数据有效性
- 采样:
- MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时被采样。
- 即在 SCK 的下降沿时刻,MOSI 及 MISO 的数据有效,高电平时表示数据“1”,为低电平时表示数据“0”。在其它时刻,数据无效,
- 触发:
- MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时被采样.
- 通讯模式
- 共4种,区别于 SCK 的时钟状态以及数据采样时刻
- SPI外设
- 时钟:
- SPI1 是 APB2 上的设备,最高通信速率达 36Mbtis/s,SPI2、SPI3 是 APB1 上的设备,最高通信速率为 18Mbits/s
- 引脚

- 通讯过程
- (1) 控制 NSS 信号线,产生起始信号(NSS拉低,图中没有画出);
- (2) 把要发送的数据写入到“数据寄存器 DR”中,该数据会被存储到发送缓冲区;
- (3) 通讯开始,SCK 时钟开始运行。MOSI 把发送缓冲区中的数据一位一位地传输出去;MISO 则把数据一位一位地存储进接收缓冲区中;
- (4) 当发送完一帧数据的时候,“状态寄存器 SR”中的“TXE 标志位”会被置 1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“RXNE标志位”会被置 1,表示传输完一帧,接收缓冲区非空;
- (5) 等待到“TXE 标志位”为 1 时,若还要继续发送数据,则再次往“数据寄存器DR”写入数据即可;等待到“RXNE 标志位”为 1 时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。
- 处理收发数据
- 中断方式
- 使能TXE 或 RXNE 中断,TXE 或 RXNE 置 1 时会产生 SPI 中断信号,进入同一个中断服务函数,到 SPI 中断服务程序后,可通过检查寄存器位来了解是哪一个事件,再分别进行处理
- DMA方式
- 使用 DMA 方式来收发“数据寄存器 DR”中的数据。
-
配置流程
- 配置相关引脚的复用功能,使能 SPI2 时钟 ,设置 SPI2 的相关引脚为复用输出,这样才会连接到 SPI2
- 初始化 SPI2,设置 SPI2 工作模式
- 使能 SPI2
- SPI 传输数据
- 查看 SPI 传输状态
裸机--SPI--FLASH读写
- 硬件连接
- WP 引脚可控制写保护功能,当该引脚为低电平时,禁止写入数据。我们直接接电源,不使用写保护功能。

- 指令表
- 带括号的字节参数,方向为 FLASH 向主机传输,即命令响应,不带括号的则为主机向 FLASH 传输
- 表中“A0~A23”指 FLASH 芯片内部存储器组织的地址;
- “M0~M7”为厂商号(MANUFACTURER ID);
- “ID0-ID15”为 FLASH 芯片的ID;
- “dummy”指该处可为任意数据;
- “D0~D7”为 FLASH 内部存储矩阵的内容。

- FLASH操作
- 一般流程
- CS拉低
- 发送指令
- 操作数据
- CS拉高
- 等待
- 扇区擦除
- 只能把原来为“1”的数据位改写成“0”,而原来为“0”的数据位不能直接改写为“1”。在写入前,必须要对目标存储矩阵进行擦除操作,把矩阵中的数据位擦除为“1”,在数据写入的时候,如果要存储数据“1”,那就不修改存储矩阵 ,在要存储数据“0”时,才更改该位。
- FLASH 芯片的最小擦除单位为扇区(Sector),而一个块(Block)包含 16 个扇区,
- 流程:
- 发送写使能
- CS拉低
- 发送擦除指令
- 发送擦除地址
- CS拉高
- 等待擦除完毕
1 /** 2 * @brief 擦除 FLASH 扇区 3 * @param SectorAddr:要擦除的扇区地址 4 * @retval 无 5 */ 6 void SPI_FLASH_SectorErase(u32 SectorAddr) 7 { 8 /* 发送 FLASH 写使能命令 */ 9 SPI_FLASH_WriteEnable(); 10 SPI_FLASH_WaitForWriteEnd(); 11 /* 擦除扇区 */ 12 /* 选择 FLASH: CS 低电平 */ 13 SPI_FLASH_CS_LOW(); 14 /* 发送扇区擦除指令*/ 15 SPI_FLASH_SendByte(W25X_SectorErase); 16 /*发送擦除扇区地址的高位*/ 17 SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16); 18 /* 发送擦除扇区地址的中位 */ 19 SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8); 20 /* 发送擦除扇区地址的低位 */ 21 SPI_FLASH_SendByte(SectorAddr & 0xFF); 22 /* 停止信号 FLASH: CS 高电平 */ 23 SPI_FLASH_CS_HIGH(); 24 /* 等待擦除完毕*/ 25 SPI_FLASH_WaitForWriteEnd(); 26 }
- 页写入
- 最多写入256字节
- 一般以扇区单位进行读写
- 流程
- 发送写使能
- CS拉低
- 发送写指令
- 发送写地址
- 写入数据
- CS拉高
- 等待
1 /** 2 * @brief 对 FLASH 按页写入数据,调用本函数写入数据前需要先擦除扇区 3 * @param pBuffer,要写入数据的指针 4 * @param WriteAddr,写入地址 5 * @param NumByteToWrite,写入数据长度,必须小于等于页大小 6 * @retval 无 7 */ 8 void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) 9 { 10 /* 发送 FLASH 写使能命令 */ 11 SPI_FLASH_WriteEnable(); 12 13 /* 选择 FLASH: CS 低电平 */ 14 SPI_FLASH_CS_LOW(); 15 /* 写送写指令*/ 16 SPI_FLASH_SendByte(W25X_PageProgram); 17 /*发送写地址的高位*/ 18 SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16); 19 /*发送写地址的中位*/ 20 SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8); 21 /*发送写地址的低位*/ 22 SPI_FLASH_SendByte(WriteAddr & 0xFF); 23 24 if (NumByteToWrite > SPI_FLASH_PerWritePageSize) 25 { 26 NumByteToWrite = SPI_FLASH_PerWritePageSize; 27 FLASH_ERROR("SPI_FLASH_PageWrite too large!"); 28 } 29 30 /* 写入数据*/ 31 while (NumByteToWrite--) 32 { 33 /* 发送当前要写入的字节数据 */ 34 SPI_FLASH_SendByte(*pBuffer); 35 /* 指向下一字节数据 */ 36 pBuffer++; 37 } 38 39 /* 停止信号 FLASH: CS 高电平 */ 40 SPI_FLASH_CS_HIGH(); 41 42 /* 等待写入完毕*/ 43 SPI_FLASH_WaitForWriteEnd(); 44 }
- 读取数据
- 流程
- CS拉低
- 发送读指令
- 发送读地址
- 读取数据
- CS拉高