STM32F7实现SPI读写,读取W25Q16型号

发布者:EnchantedDream最新更新时间:2022-07-08 来源: csdn关键字:STM32F7  SPI读写 手机看文章 扫描二维码
随时随地手机看文章

SPI协议的原理,网上大把的资料可以找到,这里记录一下SPI的初始化过程,以即以读取W25Q16型号为例的一个简单的SPI读写过程。

CubeMX配置:

在这里插入图片描述

SPI模式

有只发送、只接收、半双工和全双工模式;

根据自己的需求,和SPI设备支持的类型,这里选择全双工的SPI;


片选信号

因为我们这个SPI总线上会挂载多个从设备,而且只有一个主机,所以,这里禁用硬件片选,程序里面读写之前使用软件进行片选;


帧格式

这里选择Motorola帧格式;

选择TI格式不能设置CPOL和CPHA,而且必须要开启硬件NSS这里才能选择TI模式。

博主在网上搜了一些关于TI的SSP协议相关的资料,只有简简单单的一句:SSP总线兼容SPI,SSI 和Microwire 总线的接口。

博主又搜了以下Microwire协议,和SPI一样,只不过片选信号是高电平有效。

这是手册里关于TI模式的说明部分和波形图:

在这里插入图片描述
在这里插入图片描述

也不清楚这个SCK的触发信号是干嘛的,所以这里老老实实选择Motorola就行了。


数据长度

4-16bit可选,根据实际,选择8bit;


数据传输模式

第一个传输的bit是高位还是低位,这里根据设备来选择,好像MSB(先发送高位)的比较多,注意这里的会同时设置发送和接收,如果设置错了,发送的指令对方就无法识别,可能收到的就是0xFF这种值。


SPI速率

SPI的波特率是由时钟分频得到的,CubeMX很方便的还帮我们计算出来了时钟速率,可以根据自己的需求设置。


时钟极性和时钟相位

根据极性和相位的不同,可以有4种不同的工作模式,这个根据芯片手册支持的模式选择,注意,一条总线上尽量挂载支持相通模式的设备,这样就不用每次在设备切换之前重新配置SPI外设。


CRC校验

暂时还没研究到这里……


NSS脉冲

参考SPI的NSS 脉冲模式的作用,这里用不到;


NSS信号类型

因为前面禁用了硬件片选,所以这里只能设置位软件模式。


除此意外,还需要把连接硬件片选信号的GPIO,设置为输出模式。

CubeMX生成的代码如下:


SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄


void SPI3_Init(void)

{

    SPI3_Handler.Instance = SPI3;

    SPI3_Handler.Init.Mode = SPI_MODE_MASTER;

    SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;

    SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;

    SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;

    SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;

    SPI3_Handler.Init.NSS = SPI_NSS_SOFT;

    SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;

    SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;

    SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;

    SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

    SPI3_Handler.Init.CRCPolynomial = 7;

    SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;

    SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

    HAL_SPI_Init(&SPI3_Handler);


    __HAL_SPI_ENABLE(&SPI3_Handler);               

}


void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  if(hspi->Instance==SPI3)

  {


    __HAL_RCC_SPI3_CLK_ENABLE();

  

    __HAL_RCC_GPIOB_CLK_ENABLE();


    GPIO_InitStruct.Pin = GPIO_PIN_2;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  }

}



static void MX_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};


  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOA_CLK_ENABLE();


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);


  /*Configure GPIO pin : PA4 */

  GPIO_InitStruct.Pin = GPIO_PIN_4;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


}


同一总线上不同设备,工作在不同模式的时候,速率可能不一样,需要一个重新设置速率的函数:


void SPI3_SetSpeed(u8 SPI_BaudRatePrescaler)

{

    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性

    __HAL_SPI_DISABLE(&SPI3_Handler);            //关闭SPI

    SPI3_Handler.Instance->CR1 &= 0XFFC7;        //位3-5清零,用来设置波特率

    SPI3_Handler.Instance->CR1 |= SPI_BaudRatePrescaler; //设置SPI速度

    __HAL_SPI_ENABLE(&SPI3_Handler);             //使能SPI


}


因为全双工的读写是同时的,封装一个读写函数:


//SPI2 读写一个字节

//TxData:要写入的字节

//返回值:读取到的字节

u8 SPI3_ReadWriteByte(u8 TxData)

{

    u8 Rxdata;

    HAL_SPI_TransmitReceive(&SPI3_Handler, &TxData, &Rxdata, 1, 1000);

    return Rxdata;                      //返回收到的数据

}


根据W25QXX的数据手册,写一个读ID的函数:


//读取芯片ID

//返回值如下:    

//0XEF13,表示芯片型号为W25Q80  

//0XEF14,表示芯片型号为W25Q16    

//0XEF15,表示芯片型号为W25Q32  

//0XEF16,表示芯片型号为W25Q64 

//0XEF17,表示芯片型号为W25Q128   

u16 W25QXX_ReadID(void)

{

u16 Temp = 0;   

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);     

SPI3_ReadWriteByte(0x90);//发送读取ID命令     

SPI3_ReadWriteByte(0x00);     

SPI3_ReadWriteByte(0x00);     

SPI3_ReadWriteByte(0x00);    

Temp|=SPI3_ReadWriteByte(0xFF)<<8;  

Temp|=SPI3_ReadWriteByte(0xFF);  

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  

return Temp;

}   


最后写一个在主函数中调用的接口函数。


void W25QXX_Init(void)

{

MX_GPIO_Init();

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);

SPI3_Init();

SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);

uint16_t W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.  

printf("W25QXX ID:0x%4xrn",W25QXX_TYPE);

}


下载运行,读取到了芯片ID。

在这里插入图片描述

关键字:STM32F7  SPI读写 引用地址:STM32F7实现SPI读写,读取W25Q16型号

上一篇:STM32F7使用SPI发送完成和接收中断
下一篇:SPI的NSS 脉冲模式的作用

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved