历史上的今天
今天是:2024年09月11日(星期三)
2019年09月11日 | 秉火429笔记之十七 SPI--操作FLASH
2019-09-11 来源:eefocus
1. SPI协议概述
关于SPI协议不做赘述,见详解。
https://blog.csdn.net/XieWinter/article/details/94738361
2. STM32 SPI特性及架构
STM32芯片也集成了专门用于SPI协议通讯的外设。
2.1 SPI外设简介
STM32的SPI外设可用作通讯的主机及从机,支持最高的SCK时钟频率为fpclk/2 (STM32F429型号的芯片默认fpclk1为90MHz,fpclk2为45MHz),完全支持SPI协议的4种模式,数据帧长度可设置为8位或16位,可设置数据MSB先行或LSB先行。
双线双工模式: 通常使用
双线单向模式:MOSI/MISO数据线向一个方向传输数据,可以加快一倍的速度
单线模式:半双工
● 基于三条线的全双工同步传输
● 基于双线的单工同步传输,其中一条可作为双向数据线
● 8 位或 16 位传输帧格式选择
● 主模式或从模式操作
● 多主模式功能
● 8 个主模式波特率预分频器(最大值为 fPCLK/2)
● 从模式频率(最大值为 fPCLK/2)
● 对于主模式和从模式都可实现更快的通信
● 对于主模式和从模式都可通过硬件或软件进行 NSS 管理:动态切换主/从操作
● 可编程的时钟极性和相位
● 可编程的数据顺序,最先移位 MSB 或 LSB
● 可触发中断的专用发送和接收标志
● SPI 总线忙状态标志
● SPI TI 模式
● 用于确保可靠通信的硬件 CRC 功能:
— 在发送模式下可将 CRC 值作为最后一个字节发送
— 根据收到的最后一个字节自动进行 CRC 错误校验
● 可触发中断的主模式故障、上溢和 CRC 错误标志
● 具有 DMA 功能的 1 字节发送和接收缓冲器:发送和接收请求
2.2 STM32的SPI架构剖析

2.2.1 通讯引脚
SPI的所有硬件架构都从图 中左侧MOSI、MISO、SCK及NSS线展开的。
处于不同外设总线上的SPI,最高通信速率有所差异。其中SPI1、SPI4、SPI5、SPI6是APB2上的设备,最高通信速率达45Mbtis/s,SPI2、SPI3是APB1上的设备,最高通信速率为22.5Mbits/s。
2.2.2 时钟控制逻辑
SCK线的时钟信号,由波特率发生器根据“控制寄存器CR1”中的BR[0:2]位控制,该位是对fpclk时钟的分频因子,对fpclk的分频结果就是SCK引脚的输出时钟频率。

2.2.3 数据控制逻辑
SPI的MOSI及MISO都连接到数据移位寄存器上,数据移位寄存器的数据来源及目标接收、发送缓冲区以及MISO、MOSI线。
通过写SPI的“数据寄存器DR”把数据填充到发送缓冲区中,通讯读“数据寄存器DR”,可以获取接收缓冲区中的内容。
其中数据帧长度,可以通过“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可选择MSB先行还是LSB先行。
3. 通信过程

主模式收发流程及事件说明如下:
(1) 控制NSS信号线,产生起始信号(图中没有画出);
(2) 把要发送的数据写入到“数据寄存器DR”中,该数据会被存储到发送缓冲区;
(3) 通讯开始,SCK时钟开始运行。MOSI把发送缓冲区中的数据一位一位地传输出去;MISO则把数据一位一位地存储进接收缓冲区中;
(4) 当发送完一帧数据的时候,“状态寄存器SR”中的“TXE标志位”会被置1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“RXNE标志位”会被置1,表示传输完一帧,接收缓冲区非空;
(5) 等待到“TXE标志位”为1时,若还要继续发送数据,则再次往“数据寄存器DR”写入数据即可;等待到“RXNE标志位”为1时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。
4. 硬件设计

FLASH芯片中还有WP和HOLD引脚。WP引脚可控制写保护功能,当该引脚为低电平时,禁止写入数据。我们直接接电源,不使用写保护功能。HOLD引脚可用于暂停通讯,该引脚为低电平时,通讯暂停,数据输出引脚输出高阻抗状态,时钟和数据输入引脚无效 。详情见芯片数据手册

“dummy”指该处可为任意数据,

5. 软件设计
注意:根据SPI协议可知,时钟是由主机提供的,因此,读字节的时候,发送数据使主机产生时钟,从而是主从的移位寄存器按位移动数据,从而使得从机的数据,转移到主机的数据寄存器,从而获取从机的相应数据。
#ifndef __SPI_FLASH_H__
#define __SPI_FLASH_H__
#include "stm32f4xx.h"
#include /* Private typedef -----------------------------------------------------------*/ //#define sFLASH_ID 0xEF3015 //W25X16 //#define sFLASH_ID 0xEF4015 //W25Q16 //#define sFLASH_ID 0XEF4017 //W25Q64 #define sFLASH_ID 0XEF4018 //W25Q128 //#define SPI_FLASH_PageSize 4096 #define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256 /* Private define ------------------------------------------------------------*/ /*命令定义-开头*******************************/ #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */ #define Dummy_Byte 0xFF /*命令定义-结尾*******************************/ /*SPI接口定义-开头****************************/ //SPI号 #define FLASH_SPI SPI3 #define FLASH_SPI_CLK RCC_APB1Periph_SPI3 #define FLASH_SPI_CLK_INIT RCC_APB1PeriphClockCmd //SCK引脚 #define FLASH_SPI_SCK_PIN GPIO_Pin_3 #define FLASH_SPI_SCK_GPIO_PORT GPIOB #define FLASH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_SCK_PINSOURCE GPIO_PinSource3 #define FLASH_SPI_SCK_AF GPIO_AF_SPI3 //MISO引脚 #define FLASH_SPI_MISO_PIN GPIO_Pin_4 #define FLASH_SPI_MISO_GPIO_PORT GPIOB #define FLASH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MISO_PINSOURCE GPIO_PinSource4 #define FLASH_SPI_MISO_AF GPIO_AF_SPI3 //MOSI引脚 #define FLASH_SPI_MOSI_PIN GPIO_Pin_5 #define FLASH_SPI_MOSI_GPIO_PORT GPIOB #define FLASH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MOSI_PINSOURCE GPIO_PinSource5 #define FLASH_SPI_MOSI_AF GPIO_AF_SPI3 //CS(NSS)引脚 #define FLASH_CS_PIN GPIO_Pin_8 #define FLASH_CS_GPIO_PORT GPIOI #define FLASH_CS_GPIO_CLK RCC_AHB1Periph_GPIOI //控制CS(NSS)引脚输出低电平 #define SPI_FLASH_CS_LOW() {FLASH_CS_GPIO_PORT->BSRRH=FLASH_CS_PIN;} //控制CS(NSS)引脚输出高电平 #define SPI_FLASH_CS_HIGH() {FLASH_CS_GPIO_PORT->BSRRL=FLASH_CS_PIN;} /*SPI接口定义-结尾****************************/ /*等待超时时间*/ #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000) #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)) /*信息输出*/ #define FLASH_DEBUG_ON 0 #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"n",##arg) #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"n",##arg) #define FLASH_DEBUG(fmt,arg...) do{ if(FLASH_DEBUG_ON) printf("<<-FLASH-DEBUG->> [%d]"fmt"n",__LINE__, ##arg); }while(0) void SPI_FLASH_Init(void); void SPI_FLASH_SectorErase(uint32_t SectorAddr); void SPI_FLASH_BulkErase(void); void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead); uint32_t SPI_FLASH_ReadID(void); uint32_t SPI_FLASH_ReadDeviceID(void); void SPI_FLASH_StartReadSequence(uint32_t ReadAddr); void SPI_Flash_PowerDown(void); void SPI_Flash_WAKEUP(void); uint8_t SPI_FLASH_ReadByte(void); uint8_t SPI_FLASH_SendByte(uint8_t byte); uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord); void SPI_FLASH_WriteEnable(void); void SPI_FLASH_WaitForWriteEnd(void); #endif /* __SPI_FLASH_H__ */ /** ****************************************************************************** * @file bsp_spi_flash.c * @version V1.0 * @date 2015-xx-xx * @brief spi flash 底层应用函数bsp ****************************************************************************** */ #include "bsp_spi_flash.h" static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT; static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode); /** * @brief SPI_FLASH初始化 * @param 无 * @retval 无 */ void SPI_FLASH_Init(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* 使能 FLASH_SPI 及GPIO 时钟 */ /*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
史海拾趣
|
我在EASYARM2200上集成TCPIP,在实时轮询时可以稳定的运行,可是我改成中断触发模式后,我的板向PC机发送连接请求,发现前句分钟PC应答的报文总是ACK,过了好几分钟才变成SYN+ACK,有没有哪位大侠了解的?… 查看全部问答> |
|
不使用三极管和MOS管是否也可以搭建一个单键开关电路呢? 就是按一下电源可以接通,再按一下电源断开的那种。 哪位高人能给一个示意图呢? 恳请大家帮帮忙,感谢万分!… 查看全部问答> |
|
我现在在调一个光传感器,它是IIC通信的,直接与单片机IO相连,没有其他硬件结构,我之前在51开发板上调通了,效果很好。现在转到149的板子上就一直出不来,我把具体情况说下哈,还请大牛把把脉啊。 一:51调通了,再加上除了传感器没有其他硬件结 ...… 查看全部问答> |
|
新能源今年可算是很热的话题,自己也是从事这个行业,对这个行业也充满了无限的热受与喜欢,今天看了TI的微型逆变器解决方案,还是很不错,特点是系统的完全隔离的问题。我在这里补充一下逆变器的结构:对于大功率的一边是单级式的结构,整个逆变器 ...… 查看全部问答> |
|
用5438采集模拟量,A4管脚处有电压值,但ADC12产生的中断中采集的模拟量始终为0,已经检查过A4通道和ADC12MEM0对应,不知道是嘛情况,请高手指点~… 查看全部问答> |




