STM32个人笔记-SPI

目录

SPI优点

SPI缺点

SPI物理层

总线:

片选线:

SPI协议层

SPI基本通讯时序

SPI外设框架

1.通讯引脚(基于stm32f10x)

2.时钟控制逻辑

3.数据控制逻辑

4.整体控制逻辑

通讯过程

SPI初始化结构体

HAL库_SPI

SPI配置

SPI结构体

SPI函数

现在介绍一下W25Q64,SPI_FLASH芯片,NOR FLASH,64M-bit,即8M-Byte。

FLASH的存储特性


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)CPOACPHA空闲时SCK时钟采样时刻
000低电平奇数边沿
101低电平偶数边沿
210高电平奇数边沿
311高电平偶数边沿

SPI外设框架

1.通讯引脚(基于stm32f10x)

引脚SPI1SPI2SPI3
NSSPA4PB12PA15下载口的TDI
CLKPA5PB13PB3下载口的TDO
MISOPA6PB14PB4下载口的NTRST
MOSIPA7PB15PB5

其中 SPI1 APB2 上的设备,最高通信速率达 36Mbtis/sSPI2SPI3 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 :必须以扇区或块为单位进行读写。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值