STM32 W25Q256驱动源码(使用SPI接口)

主控:STM32H7B0VBT6

平台:STM32CubeIDE

W25Q256一片,使用SPI驱动

 SPI配置(软件CS)

 W25Q256最高时钟速率能达到50MHz,但是由于使用的是软件CS,自己测试大概只能跑到15MHz

现在给出c文件h文件:

W25Q256.c:

// @file W25Q256.c
/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2023, Main, China, 被钢琴支配的悲惨大学生.
**                           All Rights Reserved
**
**                           By(被钢琴支配的悲惨大学生 personally owned)
**                           https://blog.csdn.net/m0_71226271?type=blog
**
**----------------------------------文件信息------------------------------------
** 文件名称: W25Q256.c
** 创建人员: 被钢琴支配的悲惨大学生
** 创建日期: 2023-07-30
** 文档描述:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V1.0
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/
 
#include "W25Q256.h"
#include "SPI.h"
/*************************************************************************************************
*	函 数 名: W25Q256_Read_JEDECID
*	入口参数: 无
*	返回值:无
*	函数功能: 读取W25Q256  JEDEC ID
*	说    明: W25Q256Q读取到的JEDEC ID是0XEF4019,如果不对请检查硬件接口
*************************************************************************************************/
void W25Q256_Read_JEDECID(uint8_t  *JEDECID)
{
   uint8_t SPI_Transmit_Data[1];
   SPI_Transmit_Data[0]=W25Q256_Command_Read_JEDECID;
   W25Q256_CS_L;
   HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,1,HAL_MAX_DELAY);
   HAL_SPI_Receive(&hspi1,JEDECID,3,HAL_MAX_DELAY);
   W25Q256_CS_H;
}
/*************************************************************************************************
*	函 数 名: W25Q256_Write_Enable
*	入口参数: 无
*	返回值:无
*	函数功能: 使能W25Q256写和擦除的权限
*	说    明: 无
*************************************************************************************************/
void W25Q256_Erase_Write_Enable()
{
   uint8_t SPI_Transmit_Data[1];
   SPI_Transmit_Data[0]=W25Q256_Command_Write_Enable;
   W25Q256_CS_L;
   HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,1,HAL_MAX_DELAY);
   W25Q256_CS_H;
}
/*************************************************************************************************
*	函 数 名: W25Q256_Waiting_For_Erase_Write_End
*	入口参数: 无
*	返回值:无
*	函数功能: 等待擦除和写完成
*	说    明: 这是一个阻塞函数,直到擦除和写完成停止等待
*************************************************************************************************/
void W25Q256_Waiting_For_Erase_Write_End()
{
	   uint8_t SPI_Transmit_Data[1];
	   SPI_Transmit_Data[0]=W25Q256_Command_Read_Status_Register_1;
	  uint8_t SPI_Receive_Data[1];
	  while(1)//一直阻塞轮询
	  {
		  W25Q256_CS_L;
		  HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,1,HAL_MAX_DELAY);
		  HAL_SPI_Receive(&hspi1,SPI_Receive_Data,1,HAL_MAX_DELAY);
		  W25Q256_CS_H;
		  if((SPI_Receive_Data[0]&0x01)==0)//最后一位等于0代表写、擦除完成,退出循环
		  {
			  break;
		  }
	  }
}
/*************************************************************************************************
*	函 数 名: W25Q256_Write_Data
*	入口参数: WriteData 写入数据的首地址、StartAddress 要写入的起始地址  WriteDataSize要写入的长度
*	返回值:无
*	函数功能: 向W25Q256特定地址写入特定长度数据
*	说    明: WriteDataSize最小是256,且是256的整数倍。并且StartAddress+WriteDataSize必须小于等于33554432(32MB)
*************************************************************************************************/
void W25Q256_Write_Data(uint8_t *WriteData,uint32_t StartAddress,uint32_t WriteDataSize)
{
	 uint8_t SPI_Transmit_Data[5];
	 uint32_t Number=WriteDataSize/256;//获取写入数据量是一页(256字节)的多少倍
	 uint32_t i;
	 for(i=0;i<Number;i++)//由于一次CS周期只能写入256字节,所以要分Number次写入,每写一次,数据地址+256
	 {
		 SPI_Transmit_Data[0] = W25Q256_Command_Page_Program;
		 SPI_Transmit_Data[1] = (uint8_t)((StartAddress+256*i) >> 24);
		 SPI_Transmit_Data[2] = (uint8_t)((StartAddress+256*i) >> 16);
		 SPI_Transmit_Data[3] = (uint8_t)((StartAddress+256*i )>> 8);
		 SPI_Transmit_Data[4] = (uint8_t)(StartAddress+256*i );//告知写入地址
		 W25Q256_Erase_Write_Enable();//写使能
		   W25Q256_CS_L;
		 HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,5,HAL_MAX_DELAY);
		 HAL_SPI_Transmit(&hspi1,WriteData+i*256,256,HAL_MAX_DELAY);//传入数据,传入数量固定256字节
		   W25Q256_CS_H;
		 W25Q256_Waiting_For_Erase_Write_End();//阻塞等待写入完成
	 }
 
}
/*************************************************************************************************
*	函 数 名: W25Q256_Read_Data
*	入口参数: ReceiveData 读取数据存放的首地址、StartAddress 要读取的起始地址  ReceiveDataSize要读取数据的长度
*	返回值:无
*	函数功能: 向W25Q256特定地址读出特定长度数据
*	说    明: StartAddress+ReceiveDataSize必须小于等于33554432(32MB)
*************************************************************************************************/
void W25Q256_Read_Data(uint8_t *ReceiveData,uint32_t StartAddress,uint32_t ReceiveDataSize)
{
	 uint8_t SPI_Transmit_Data[6];
	 SPI_Transmit_Data[0] = W25Q256_Command_Fast_Read_Data;
	 SPI_Transmit_Data[1] = (uint8_t)(StartAddress >> 24);
	 SPI_Transmit_Data[2] = (uint8_t)(StartAddress >> 16);
	 SPI_Transmit_Data[3] = (uint8_t)(StartAddress >> 8);
	 SPI_Transmit_Data[4] = (uint8_t)(StartAddress);
	 SPI_Transmit_Data[5] =0x00;//Dummy字节
	 W25Q256_CS_L;
	 HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,6,HAL_MAX_DELAY);
	 HAL_SPI_Receive(&hspi1,ReceiveData,ReceiveDataSize,HAL_MAX_DELAY);
	 W25Q256_CS_H;
}
/*************************************************************************************************
*	函 数 名: W25Q256_Sector_Erase
*	入口参数:StartAdress 要擦除的地址
*	返回值:无
*	函数功能: 向W25Q256特定地址擦除所在的Sector
*	说    明: StartAddress必须小于等于33554432(32MB),比如擦除第一Sector(0-4095),那么StartAddress写入0或者是4095都是擦第一个Sector
*************************************************************************************************/
void W25Q256_Sector_Erase(uint32_t StartAddress)
{
	 uint8_t SPI_Transmit_Data[5];
	 SPI_Transmit_Data[0] = W25Q256_Command_Sector_Erase;
	 SPI_Transmit_Data[1] = (uint8_t)(StartAddress >> 24);
	 SPI_Transmit_Data[2] = (uint8_t)(StartAddress >> 16);
	 SPI_Transmit_Data[3] = (uint8_t)(StartAddress >> 8);
	 SPI_Transmit_Data[4] = (uint8_t)(StartAddress);
	 W25Q256_Erase_Write_Enable();
	 W25Q256_CS_L;
	 HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,5,HAL_MAX_DELAY);
	 W25Q256_CS_H;
	 W25Q256_Waiting_For_Erase_Write_End();
}
/*************************************************************************************************
*	函 数 名: W25Q256_Chip_Erase
*	入口参数:无
*	返回值:无
*	函数功能: 全片擦除
*	说    明: 耗时大概一分钟
*************************************************************************************************/
void W25Q256_Chip_Erase()
{
	 uint8_t SPI_Transmit_Data[1];
	 SPI_Transmit_Data[0] = W25Q256_Command_Chip_Erase;
	 W25Q256_Erase_Write_Enable();
	 W25Q256_CS_L;
	 HAL_SPI_Transmit(&hspi1,SPI_Transmit_Data,1,HAL_MAX_DELAY);
	 W25Q256_CS_H;
	 W25Q256_Waiting_For_Erase_Write_End();
}

W25Q256.h:

// @file W25Q256.h
/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2023, Main, China, 被钢琴支配的悲惨大学生.
**                           All Rights Reserved
**
**                           By(被钢琴支配的悲惨大学生 personally owned)
**                           https://blog.csdn.net/m0_71226271?type=blog
**
**----------------------------------文件信息------------------------------------
** 文件名称: W25Q256.h
** 创建人员: 被钢琴支配的悲惨大学生
** 创建日期: 2023-07-30
** 文档描述:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V1.0
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------

\********************************End of Head************************************/
#include<main.h>
#define W25Q256_CS_L    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,GPIO_PIN_RESET)
#define W25Q256_CS_H   HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,GPIO_PIN_SET)//使用PA15作为软件片选,记得使用SWD调试,不然PA15被占用

#define W25Q256_Command_Read_JEDECID                                0X9F    //读取JEDECID指令
#define W25Q256_Command_Write_Enable                                  0X06   //写使能指令
#define W25Q256_Command_Read_Status_Register_1                 0X05//读取Status Register 1指令
#define W25Q256_Command_Fast_Read_Data                              0X0C//快速读取指令
#define W25Q256_Command_Page_Program                                0X12//页编程指令
#define W25Q256_Command_Sector_Erase                                    0x21//扇区擦除指令
#define W25Q256_Command_Chip_Erase                                       0XC7//全片擦除指令

void W25Q256_Read_JEDECID(uint8_t  *JEDECID);
void W25Q256_Write_Data(uint8_t *WriteData,uint32_t StartAddress,uint32_t WriteDataSize);
void W25Q256_Read_Data(uint8_t *ReceiveData,uint32_t StartAdress,uint32_t ReceiveDataSize);
void W25Q256_Sector_Erase(uint32_t StartAdress);
void W25Q256_Chip_Erase();

 全片擦除后插上USB进行格式化

 

格式化完毕:

注意事项:本代码使用的是全阻塞模式,如果遇到卡死请检查:

1.硬件接口是否对应

2.降低SPI时钟频率

3.断电重启W25Q256

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是STM32驱动W25Q128的代码示例,使用SPI接口进行通信: ```c #include "stm32f10x.h" #define W25Q128_CS_GPIO GPIOA #define W25Q128_CS_PIN GPIO_Pin_4 #define W25Q128_WRITE_ENABLE 0x06 #define W25Q128_WRITE_DISABLE 0x04 #define W25Q128_READ_STATUS_REG 0x05 #define W25Q128_WRITE_STATUS_REG 0x01 #define W25Q128_READ_DATA 0x03 #define W25Q128_PAGE_PROGRAM 0x02 #define W25Q128_SECTOR_ERASE 0x20 #define W25Q128_BLOCK_ERASE_32K 0x52 #define W25Q128_BLOCK_ERASE_64K 0xD8 #define W25Q128_CHIP_ERASE 0xC7 #define W25Q128_POWER_DOWN 0xB9 #define W25Q128_READ_DEVICE_ID 0x90 #define W25Q128_READ_MANUFACTURER_ID 0x9F void W25Q128_Init(void); void W25Q128_CS_Enable(void); void W25Q128_CS_Disable(void); void W25Q128_WriteEnable(void); void W25Q128_WriteDisable(void); void W25Q128_ReadStatusReg(uint8_t *status); void W25Q128_WriteStatusReg(uint8_t status); void W25Q128_ReadData(uint8_t *data, uint32_t addr, uint16_t size); void W25Q128_PageProgram(uint8_t *data, uint32_t addr, uint16_t size); void W25Q128_SectorErase(uint32_t addr); void W25Q128_BlockErase32K(uint32_t addr); void W25Q128_BlockErase64K(uint32_t addr); void W25Q128_ChipErase(void); void W25Q128_PowerDown(void); void W25Q128_ReadDeviceID(uint8_t *id); void W25Q128_ReadManufacturerID(uint8_t *id); void W25Q128_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = W25Q128_CS_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(W25Q128_CS_GPIO, &GPIO_InitStruct); SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStruct.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); } void W25Q128_CS_Enable(void) { GPIO_ResetBits(W25Q128_CS_GPIO, W25Q128_CS_PIN); } void W25Q128_CS_Disable(void) { GPIO_SetBits(W25Q128_CS_GPIO, W25Q128_CS_PIN); } void W25Q128_WriteEnable(void) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_WRITE_ENABLE); W25Q128_CS_Disable(); } void W25Q128_WriteDisable(void) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_WRITE_DISABLE); W25Q128_CS_Disable(); } void W25Q128_ReadStatusReg(uint8_t *status) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_READ_STATUS_REG); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *status = SPI_I2S_ReceiveData(SPI1); W25Q128_CS_Disable(); } void W25Q128_WriteStatusReg(uint8_t status) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_WRITE_STATUS_REG); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, status); W25Q128_CS_Disable(); } void W25Q128_ReadData(uint8_t *data, uint32_t addr, uint16_t size) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_READ_DATA); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 16) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 8) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, addr & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); while (size--) { SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *data++ = SPI_I2S_ReceiveData(SPI1); } W25Q128_CS_Disable(); } void W25Q128_PageProgram(uint8_t *data, uint32_t addr, uint16_t size) { W25Q128_WriteEnable(); W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_PAGE_PROGRAM); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 16) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 8) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, addr & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); while (size--) { SPI_I2S_SendData(SPI1, *data++); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); } W25Q128_CS_Disable(); } void W25Q128_SectorErase(uint32_t addr) { W25Q128_WriteEnable(); W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_SECTOR_ERASE); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 16) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 8) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, addr & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); W25Q128_CS_Disable(); } void W25Q128_BlockErase32K(uint32_t addr) { W25Q128_WriteEnable(); W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_BLOCK_ERASE_32K); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 16) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 8) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, addr & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); W25Q128_CS_Disable(); } void W25Q128_BlockErase64K(uint32_t addr) { W25Q128_WriteEnable(); W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_BLOCK_ERASE_64K); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 16) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, (addr >> 8) & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, addr & 0xFF); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); W25Q128_CS_Disable(); } void W25Q128_ChipErase(void) { W25Q128_WriteEnable(); W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_CHIP_ERASE); W25Q128_CS_Disable(); } void W25Q128_PowerDown(void) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_POWER_DOWN); W25Q128_CS_Disable(); } void W25Q128_ReadDeviceID(uint8_t *id) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_READ_DEVICE_ID); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); W25Q128_CS_Disable(); } void W25Q128_ReadManufacturerID(uint8_t *id) { W25Q128_CS_Enable(); SPI_I2S_SendData(SPI1, W25Q128_READ_MANUFACTURER_ID); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); SPI_I2S_SendData(SPI1, 0); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); *id++ = SPI_I2S_ReceiveData(SPI1); W25Q128_CS_Disable(); } ``` 注意,在使用前需要先初始化SPI接口和CS引脚。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值