W25Q64闪存部分指令
1. 写使能-06h

写使能将状态寄存器1的WEL位置一
执行Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register and Erase/Program Security Registers 指令前都必须写使能。
WEL位在上电以及Write Status Register, Erase/Program Security Registers, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase and Reset指令执行后自动重置
使用:
①CS拉低
②发送指令06h
③CS拉高
2. 写禁止-04h

①CS拉低
②发送04h指令
③CS拉高
3. 读数据-03h

注意:
在进行芯片擦除、编程、写期间执行该指令,该指令会被忽略,不产生任何影响
该指令仅支持Standard SPI Mode
使用步骤:
①CS拉低
②发送读数据指令03h
③发送24位数据地址
④连续读出数据,每次8位(MSB)
⑤CS拉高
4. 快速读取-0Bh

与读数据-03h类似,在发送完地址后多发送一个DUMMY(即多发一个字节数据,数据为多少无所谓)给设备内部电路额外的时间来设置初始地址,之后以最高速率进行读取
使用步骤:
①CS拉低
②发送读数据指令03h+24位数据地址+8位DUMMY
③连续读出数据,每次8位(MSB)
④CS拉高
5. 页编程-02h

在已擦除的位置对1-256字节数据进行编程,使用前需执行写使能。
当写入数据达到页尾后则下一个数据跳到页首覆盖页首数据,且因未执行擦除,页首数据为错误数据此需注意写入地址与写入字节个数
写入过程中该BUSY位置1,写入完成置0
如果寻址的页面受到块保护 (CMP、SEC、TB、BP2、BP1 和 BP0) 位或单个块/扇区锁的保护,则不会执行 Page Program 指令
使用:
①写使能
②CS拉低
③发送指令02h+24位地址
④连续写入数据,每次8位(MSB)
⑤写入完成,CS拉高
⑥等待Busy置0
6. 芯片擦除-60h/E7h

将整个芯片的储存空间写为1,使用前必须写使能
注意:如果任何储存空间受到块保护(CMP、SEC、TB、BP2、BP1 和 BP0)位或单个块/扇区锁的保护,则不会执行该指令
使用:
①写使能
②CS拉低
③发送60h/E7h指令
④CS拉高
⑤等待Busy,完成后WEL自动清零
7. 擦除扇区-20h

擦除4KB空间,使用前需要写使能
注意:如果任何储存空间受到块保护(CMP、SEC、TB、BP2、BP1 和 BP0)位或单个块/扇区锁的保护,则不会执行该指令
使用:
①写使能
②CS拉低
③发送20h指令+24位地址
④CS拉高
⑤等待Busy,完成后WEL自动清零
8. 擦除32KB块-52h

擦除32KB空间,使用前需写使能
注意:如果任何储存空间受到块保护(CMP、SEC、TB、BP2、BP1 和 BP0)位或单个块/扇区锁的保护,则不会执行该指令
使用:
①写使能
②CS拉低
③发送52h指令+24位地址
④CS拉高
⑤等待Busy,完成后WEL自动清零
9. 擦除64KB块-D8h

擦除64KB空间,使用前需写使能
注意:如果任何储存空间受到块保护(CMP、SEC、TB、BP2、BP1 和 BP0)位或单个块/扇区锁的保护,则不会执行该指令
使用:
①写使能
②CS拉低
③发送D8h指令+24位地址
④CS拉高
⑤等待Busy,完成后WEL自动清零
10. 读取制造/设备ID-90h

①CS拉低
②发送90h指令+24位地址(000000h)
③读取制造id、设备ID
④CS拉低
块图表

W25Q64的FLASH大小为64Mb=8MB
每个扇区为4KB(0x1000),共8MB/4KB=2048
每页为256Byte(0x100),共8MB/256Byte=32768
因此页编程地址最好从0x000100的整数倍开始,这时能够写入最大256个字节,超过字节后从页头重新覆盖数据,写入超过256字节的数据时要及时停下,更新地址后再次写入。
读取不受页限制,可随机读取。
测试:
wel在执行完写入操作后自动重置,查询该位可判断写入是否成功
代码注意:
1.写使能函数在被引用时片选信号不要与引用函数的片选信号重复
2.查看芯片的状态寄存器,可能会有写保护置位导致芯片无法被写入的问题
3.调试发现会有读取数据时第一个字节数据最高位置位1的情况,降低波特率后正常,带逻辑分析仪到位后查找原因。
示例代码:SPI2与w25q64通信
#include "stm32h7xx.h" // Device header
#include "stm32h7xx_hal.h"
#include "w25q64.h"
#include "spi.h"
void w25q64_init(void)
{
SPI2_Init();
}
/**
* @brief 写使能
* @param
* @retval
*/
void W25Q64_WriteEnable(void)
{
uint8_t command=W25_WriteEnable;
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
W25CS_H;
}
/**
* @brief 写失能
* @param
* @retval
*/
void W25Q64_WriteDisable(void)
{
uint8_t command=W25_WriteDisable;
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
W25CS_H;
}
/**
* @brief 读对应状态寄存器
* @param command 对应命令
* @retval data 寄存器值
*/
uint8_t W25Q64_ReadStatus(uint8_t command)
{
uint8_t data=0;
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
HAL_SPI_Receive(&hspi2,&data,1,0xffffffff);
W25CS_H;
return data;
}
/**
* @brief 写状态寄存器
* @param
* @retval
*/
void W25Q64_WriteStatus(uint8_t command,uint8_t data)
{
W25Q64_WriteEnable();
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
HAL_SPI_Transmit(&hspi2,&data,1,0xffffffff);
W25CS_H;
}
/**
* @brief 扇区擦除(4k)
* @param
* @retval
*/
void W25Q64_SectorErase(uint32_t Address)
{
uint8_t command=W25_SectorErase;
W25Q64_WriteEnable();
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
command=Address;
for(uint8_t i=0;i<3;i++)
{
command=Address>>(8*(2-i));
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
}
W25CS_H;
while((W25Q64_ReadStatus(W25_ReadStatusReg1)&0x01));
}
/**
* @brief 块擦除(64KB)
* @param Address µØÖ·
* @retval
*/
void W25Q64_BlockErase(uint32_t Address)
{
uint8_t command=W25_BlockErase;
W25Q64_WriteEnable();
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
command=Address;
for(uint8_t i=0;i<3;i++)
{
command=Address>>(8*(2-i));
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
}
W25CS_H;
while((W25Q64_ReadStatus(W25_ReadStatusReg1)&0x01));
}
/**
* @brief 芯片擦除
* @param
* @retval
*/
void W25Q64_ChipErase(void)
{
uint8_t command=W25_ChipErase;
W25Q64_WriteEnable();
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
W25CS_H;
while((W25Q64_ReadStatus(W25_ReadStatusReg1)&0x01));
}
/**
* @brief 页编程
* @param uint32_t Address,地址
uint8_t *p_txbuff, 发送缓存区
uint8_t DataSize 数据大小(<=256字节)
* @retval
*/
void W25Q64_PagePRG(uint32_t Address,uint8_t *p_txbuff,uint16_t DataSize)
{
uint8_t command=W25_PageProgram;
W25Q64_WriteEnable();
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
for(uint8_t i=0;i<3;i++)
{
command=Address>>(8*(2-i));
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
}
HAL_SPI_Transmit(&hspi2,p_txbuff,DataSize,0xffffffff);
W25CS_H;
// while((W25Q64_ReadStatus(W25_ReadStatusReg1)&0x01));
}
/**
* @brief 对应地址写数据(自动换页)
* @param
* @retval
*/
void W25Q64_WriteData(uint32_t Address,uint8_t *p_txbuff,uint16_t DataSize)
{
uint16_t pageremain;
pageremain = 256 - Address % 256;
if (DataSize <= pageremain)
{
pageremain = DataSize;
}
while (1)
{
W25Q64_PagePRG(Address,p_txbuff,pageremain);
if (DataSize == pageremain)
{
break;
}
else
{
p_txbuff += pageremain;
Address += pageremain;
DataSize -= pageremain;
if (DataSize > 256)
{
pageremain = 256;
}
else
{
pageremain = DataSize;
}
}
}
}
/**
* @brief 读器件ID
* @param
* @retval
*/
void W25Q64_ReadID(uint8_t *data)
{
uint8_t command=W25_ManufactDeviceID,ID=0;
uint8_t dummy[]={0x00,0x00,0x00};
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
HAL_SPI_Transmit(&hspi2,dummy,3,0xffffffff);
HAL_SPI_Receive(&hspi2,data,2,0xffffffff);
W25CS_H;
}
/**
* @brief 随机地址读数据
* @param uint32_t Address 地址
uint8_t *p_buff, 接收缓存区
uint16_t DataSize 数据大小
* @retval
*/
void W25Q64_ReadData(uint32_t Address,uint8_t *p_buff,uint16_t DataSize)
{
uint8_t command=W25_ReadData;
W25CS_L;
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
for(uint8_t i=0;i<3;i++)
{
command=Address>>(8*(2-i));
HAL_SPI_Transmit(&hspi2,&command,1,0xffffffff);
}
HAL_SPI_Receive(&hspi2,p_buff,DataSize,5000);
W25CS_H;
}
#ifndef __W25Q64_H
#define __W25Q64_H
#define W25_WriteEnable 0x06
#define W25_WriteDisable 0x04
#define W25_ReadStatusReg1 0x05
#define W25_ReadStatusReg2 0x35
#define W25_ReadStatusReg3 0x15
#define W25_WriteStatusReg1 0x01
#define W25_WriteStatusReg2 0x31
#define W25_WriteStatusReg3 0x11
#define W25_ReadData 0x03
#define W25_FastReadData 0x0B
#define W25_FastReadDual 0x3B
#define W25_FastReadQuad 0xEB
#define W25_PageProgram 0x02
#define W25_PageProgramQuad 0x32
#define W25_BlockErase 0xD8
#define W25_SectorErase 0x20
#define W25_ChipErase 0xC7
#define W25_PowerDown 0xB9
#define W25_ReleasePowerDown 0xAB
#define W25_DeviceID 0xAB
#define W25_ManufactDeviceID 0x90
#define W25_JedecDeviceID 0x9F
#define W25_Enable4ByteAddr 0xB7
#define W25_Exit4ByteAddr 0xE9
#define W25_SetReadParam 0xC0
#define W25_EnterQPIMode 0x38
#define W25_ExitQPIMode 0xFF
#define W25CS_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET)
#define W25CS_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET)
extern SPI_HandleTypeDef hspi2;
extern DMA_HandleTypeDef hdma_spi2_rx;
extern DMA_HandleTypeDef hdma_spi2_tx;
void w25q64_init(void);
void W25Q64_WriteEnable(void);
void W25Q64_WriteDisable(void);
uint8_t W25Q64_ReadStatus(uint8_t command);
void W25Q64_WriteStatus(uint8_t command,uint8_t data);
void W25Q64_SectorErase(uint32_t Address);
void W25Q64_BlockErase(uint32_t Address);
void W25Q64_ChipErase(void);
void W25Q64_PagePRG(uint32_t Address,uint8_t *p_txbuff,uint16_t DataSize);
void W25Q64_WriteData(uint32_t Address,uint8_t *p_txbuff,uint16_t DataSize);
void W25Q64_ReadID(uint8_t *data);
void W25Q64_ReadData(uint32_t Address,uint8_t *p_buff,uint16_t DataSize);
#endif

浙公网安备 33010602011771号