目录
现在介绍一下W25Q64,SPI_FLASH芯片,NOR FLASH,64M-bit,即8M-Byte。
SPI,高速全双工。IIC,低速半双工(实际上一般不超400k)。
SPI使用线路 | 4 |
最大速度 | 最大10Mpps |
同步或异步 | 同步 |
串行或并行 | 串行 |
最大主机数 | 1 |
最大从机数 | 理论上无上限 |
SPI优点
没有启动和停止位,因此数据可以连续流式传输而不中断;
没有像I2C这么复杂的从机寻址系统;
数据传输率高于I2C(几乎是I2C的两倍);
分离MISO和MOSI线,以便可以同时发送和接收数据。
SPI缺点
使用四根线(I2C和UART使用两根线);
不确认数据已成功接收(I2C是可以确认的);
没有任何形式的错误检查,如在UART中的校验位;
只允许一个主机。
SPI物理层
总线:
SCK:时钟信号线,同步通讯数据。由通讯主机产生,决定了通讯的速率。
MOSI:主设备输出/从设备输入引脚。方向:主机-从机。
MISO:主设备输入/从设备输出引脚。方向:从机-主机。
片选线:
CS: 从设备选择信号线(片选信号线,NSS),低电平有效。主机置位,从机检测信号。
IIC协议通过设备地址寻址,选择从设备进行通讯。
SPI协议通过CS信号线寻址(没有设备地址),主机置某CS低电平选择某从设备进行通讯。
SPI协议层
SPI基本通讯时序
通讯开始:NSS高电平->低电平。
通讯结束:NSS低电平->高电平。
数据有效性:通过CPOL和CPHA确定通讯模式,再根据SCK信号线判断。
CPOL:时钟极性。0:空闲状态SCK线输出低电平;1:空闲状态SCK线输出高电平。
CPHA:时钟相位。0:MOSI或MISO数据线在SCK线输出的奇数边沿被采样;1:MOSI或MISO数据线在SCK线输出的偶数边沿被采样。
SPI模式(SPI_CR) | CPOA | CPHA | 空闲时SCK时钟 | 采样时刻 |
0 | 0 | 0 | 低电平 | 奇数边沿 |
1 | 0 | 1 | 低电平 | 偶数边沿 |
2 | 1 | 0 | 高电平 | 奇数边沿 |
3 | 1 | 1 | 高电平 | 偶数边沿 |
SPI外设框架
1.通讯引脚(基于stm32f10x)
引脚 | SPI1 | SPI2 | SPI3 |
NSS | PA4 | PB12 | PA15下载口的TDI |
CLK | PA5 | PB13 | PB3下载口的TDO |
MISO | PA6 | PB14 | PB4下载口的NTRST |
MOSI | PA7 | PB15 | PB5 |
其中 SPI1 是 APB2 上的设备,最高通信速率达 36Mbtis/s,SPI2、SPI3 是 APB1 上的设备,最高通信速率为 18Mbits/s。除了通讯速率,在其它功能上没有差异。
其中 SPI3 用到了下载接口的引脚,这几个引脚默认功能是下载,第二功能才是 IO 口,如果想使用 SPI3 接口,则程序上必须先禁用掉这几个 IO 口的下载功能。一般在资源不是十分紧张的情况下,这几个 IO 口是专门用于下载和调试程序,不会复用为 SPI3。如果用到了SPI3,则下载的时候按住复位键进行下载。
2.时钟控制逻辑
SCK线的时钟信号,由波特率发生器根据SPI_CR1:BR[0:2]位控制。
f_pclk代表SPI所在的APB总线频率。SPI1为f_pclk1,SPI2为f_pclk2。
3.数据控制逻辑
当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。通过写 SPI 的“数据寄存器 DR”把数据填充到发送缓冲区中,通讯读“数据寄存器 DR”,可以获取接收缓冲区中的内容。
其中数据帧长度可以通过SPI_CR1:DFF配置成 8 位及 16 位模式;配置SPI_CR1:LSB FIRST可选择 MSB 先行还是 LSB 先行。
4.整体控制逻辑
整体参数的配置。
我们一般不使用STM32 SPI外设的标准 NSS信号线。而是使用软件控制方式,直接对NSS引脚的GPIO进行电平输出,从而产生通讯信号和停止信号。
通讯过程
SPI初始化结构体
typedef struct
{
uint16_t SPI_Direction; //方向_单双向
uint16_t SPI_Mode; //模式,SPI_Mode_Master/SPI_Mode_Slave。
uint16_t SPI_DataSize; //数据大小,SPI_DataSize_8b/SPI_DataSize_16b
uint16_t SPI_CPOL; //时钟极性,SPI_CPOL_Low/SPI_CPOL_High
uint16_t SPI_CPHA; //时钟相位,SPI_CPHA_1Edge/SPI_CPHA_2Edge
uint16_t SPI_NSS; //片选信号,SPI_NSS_Soft/SPI_NSS_Hard
uint16_t SPI_BaudRatePrescaler; //波特率分频值
uint16_t SPI_FirstBit; //先行,SPI_FirstBit_MSB/SPI_FirstBit_LSB
uint16_t SPI_CRCPolynomial; //CRC校验表达式
}SPI_InitTypeDef;
HAL库_SPI
SPI配置
SPI_HandleTypeDef SpiHandle;
void SPI_FLASH_Init(void)
{
SpiHandle.Instance = SPI1;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
HAL_SPI_Init(&SpiHandle);
__HAL_SPI_ENABLE(&SpiHandle);
}
SPI结构体
typedef struct
{
uint32_t Mode;
uint32_t Direction;
uint32_t DataSize;
uint32_t CLKPolarity;
uint32_t CLKPhase;
uint32_t NSS;
uint32_t BaudRatePrescaler;
uint32_t FirstBit;
uint32_t TIMode;
uint32_t CRCCalculation;
uint32_t CRCPolynomial;
}SPI_InitTypeDef;
typedef struct __SPI_HandleTypeDef
{
SPI_TypeDef *Instance;
SPI_InitTypeDef Init;
uint8_t *pTxBuffPtr;
uint16_t TxXferSize;
__IO uint16_t TxXferCount;
uint8_t *pRxBuffPtr;
uint16_t RxXferSize;
__IO uint16_t RxXferCount;
void (*RxISR)(struct __SPI_HandleTypeDef * hspi);
void (*TxISR)(struct __SPI_HandleTypeDef * hspi);
DMA_HandleTypeDef *hdmatx;
DMA_HandleTypeDef *hdmarx;
HAL_LockTypeDef Lock;
__IO HAL_SPI_StateTypeDef State;
__IO uint32_t ErrorCode;
}SPI_HandleTypeDef;
SPI函数
__HAL_SPI_RESET_HANDLE_STATE(__HANDLE__);
//__HANDLE__,SPI_IT_TXE|SPI_IT_RXNE|SPI_IT_ERR
__HAL_SPI_ENABLE_IT(__HANDLE__, __INTERRUPT__);
__HAL_SPI_DISABLE_IT(__HANDLE__, __INTERRUPT__);
__HAL_SPI_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__);
//__HANDLE__,SPI_FLAG_RXNE|SPI_FLAG_TXE|SPI_FLAG_CRCERR|SPI_FLAG_MODF|SPI_FLAG_OVR|SPI_FLAG_BSY
__HAL_SPI_GET_FLAG(__HANDLE__, __FLAG__);
__HAL_SPI_CLEAR_CRCERRFLAG(__HANDLE__);
__HAL_SPI_CLEAR_MODFFLAG(__HANDLE__);
__HAL_SPI_CLEAR_OVRFLAG(__HANDLE__);
__HAL_SPI_ENABLE(__HANDLE__);
__HAL_SPI_DISABLE(__HANDLE__);
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DeInit (SPI_HandleTypeDef *hspi);
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Abort(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi);
void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi);
HAL_SPI_StateTypeDef HAL_SPI_GetState(SPI_HandleTypeDef *hspi);
uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi);
现在介绍一下W25Q64,SPI_FLASH芯片,NOR FLASH,64M-bit,即8M-Byte。
在W25Q64框图中,了解到将W25Q64分为128块,8MB/128=64KB,每块64KB。再将每块细分,每块分为16个扇区,64KB/16=4KB。每个扇区4KB。
FLASH的存储特性
在写入数据之前必须先擦除。
擦除时会把数据位全重置为1。
在写入数据时只能把为1的数据位改成0。
擦除时必须按最小单位来擦除(一般为扇区)。
norflash:可以一个字节写入。
nandflash :必须以扇区或块为单位进行读写。