主控: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