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

posted @ 2024-12-24 13:18  Osen  阅读(685)  评论(0)    收藏  举报