一,w25qxx简介。
二,stm32CubeIDE配置。
三,代码
1,w25qxx.c
#include "W25Qxx.h"/*********************************************************************************** 函数功能: 模块初始化*/
uint8_t BSP_W25Qx_Init(void)
{BSP_W25Qx_Reset();return BSP_W25Qx_GetStatus();
}void BSP_W25Qx_Reset(void)
{uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};W25Qx_Enable();/* Send the reset command */HAL_SPI_Transmit(&hspi1, cmd, 2, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();}/*********************************************************************************** 函数功能: 获取设备状态*/
uint8_t BSP_W25Qx_GetStatus(void)
{uint8_t cmd[] = {READ_STATUS_REG1_CMD};uint8_t status;W25Qx_Enable();/* Send the read status command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);/* Reception of the data */HAL_SPI_Receive(&hspi1,&status, 1, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();/* Check the value of the register */if((status & W25QxxFV_FSR_BUSY) != 0){return W25Qx_BUSY;}else{return W25Qx_OK;}
}/*********************************************************************************** 函数功能: 写使能*/
uint8_t BSP_W25Qx_WriteEnable(void)
{uint8_t cmd[] = {WRITE_ENABLE_CMD};uint32_t tickstart = HAL_GetTick();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);/*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 获取设备ID*/
void BSP_W25Qx_Read_ID(uint8_t *ID)
{uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);/* Reception of the data */HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();}/*********************************************************************************** 函数功能: 读数据* 输入参数: 缓存数组指针、读地址、字节数*/
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{uint8_t cmd[4];/* Configure the command */cmd[0] = READ_CMD;cmd[1] = (uint8_t)(ReadAddr >> 16);cmd[2] = (uint8_t)(ReadAddr >> 8);cmd[3] = (uint8_t)(ReadAddr);W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);/* Reception of the data */if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();return W25Qx_OK;
}/*********************************************************************************** 函数功能: 写数据* 输入参数: 缓存数组指针、写地址、字节数*/
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{uint8_t cmd[4];uint32_t end_addr, current_size, current_addr;uint32_t tickstart = HAL_GetTick();/* Calculation of the size between the write address and the end of the page */current_addr = 0;while (current_addr <= WriteAddr){current_addr += W25QxxFV_PAGE_SIZE;}current_size = current_addr - WriteAddr;/* Check if the size of the data is less than the remaining place in the page */if (current_size > Size){current_size = Size;}/* Initialize the adress variables */current_addr = WriteAddr;end_addr = WriteAddr + Size;/* Perform the write page by page */do{/* Configure the command */cmd[0] = PAGE_PROG_CMD;cmd[1] = (uint8_t)(current_addr >> 16);cmd[2] = (uint8_t)(current_addr >> 8);cmd[3] = (uint8_t)(current_addr);/* Enable write operations */BSP_W25Qx_WriteEnable();W25Qx_Enable();/* Send the command */if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}/* Transmission of the data */if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){return W25Qx_TIMEOUT;}}/* Update the address and size variables for next page programming */current_addr += current_size;pData += current_size;current_size = ((current_addr + W25QxxFV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25QxxFV_PAGE_SIZE;} while (current_addr < end_addr);return W25Qx_OK;
}/*********************************************************************************** 函数功能: 扇区擦除* 输入参数: 地址*/
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = SECTOR_ERASE_CMD;cmd[1] = (uint8_t)(Address >> 16);cmd[2] = (uint8_t)(Address >> 8);cmd[3] = (uint8_t)(Address);/* Enable write operations */BSP_W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);/*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25QxxFV_SECTOR_ERASE_MAX_TIME){return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 芯片擦除*/
uint8_t BSP_W25Qx_Erase_Chip(void)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = CHIP_ERASE_CMD;/* Enable write operations */BSP_W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);/*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() != W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25QxxFV_BULK_ERASE_MAX_TIME){return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*************************************************//*************************************************/ 2,w25qxx.h
/** w25qxx.h** Created on: Nov 26, 2022* Author: admin*/#ifndef INC_W25QXX_H_
#define INC_W25QXX_H_#endif /* INC_W25QXX_H_ */#ifndef __W25Qxx_H
#define __W25Qxx_H/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
//W25Q128
#define W25QxxFV_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */
#define W25QxxFV_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */
#define W25QxxFV_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */
#define W25QxxFV_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */
//zyd
//#define W25QxxFV_FLASH_SIZE 0x800000 /* 64 MBits => 8MBytes */
//#define W25QxxFV_SECTOR_SIZE 65536 /* 256 sectors of 64KBytes */
//#define W25QxxFV_SUBSECTOR_SIZE 4096 /* 4096 subsectors of 4kBytes */
//#define W25QxxFV_PAGE_SIZE 256 /* 65536 pages of 256 bytes */#define W25QxxFV_DUMMY_CYCLES_READ 4
#define W25QxxFV_DUMMY_CYCLES_READ_QUAD 10#define W25QxxFV_BULK_ERASE_MAX_TIME 250000
#define W25QxxFV_SECTOR_ERASE_MAX_TIME 3000
#define W25QxxFV_SUBSECTOR_ERASE_MAX_TIME 800
#define W25Qx_TIMEOUT_VALUE 1000/* Reset Operations */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF/* Identification Operations */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F/* Read Operations */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04/* Register Operations */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11/* Program Operations */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32/* Erase Operations */
#define SECTOR_ERASE_CMD 0x20
#define CHIP_ERASE_CMD 0xC7#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75/* Flag Status Register */
#define W25QxxFV_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25QxxFV_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25QxxFV_FSR_QE ((uint8_t)0x02) /*!< quad enable */#define W25Qx_Enable() HAL_GPIO_WritePin(W25_CS_GPIO_Port, W25_CS_Pin, GPIO_PIN_RESET)
#define W25Qx_Disable() HAL_GPIO_WritePin(W25_CS_GPIO_Port, W25_CS_Pin, GPIO_PIN_SET)#define W25Qx_OK ((uint8_t)0x00)
#define W25Qx_ERROR ((uint8_t)0x01)
#define W25Qx_BUSY ((uint8_t)0x02)
#define W25Qx_TIMEOUT ((uint8_t)0x03)uint8_t BSP_W25Qx_Init(void);
void BSP_W25Qx_Reset(void);
uint8_t BSP_W25Qx_GetStatus(void);
uint8_t BSP_W25Qx_WriteEnable(void);
void BSP_W25Qx_Read_ID(uint8_t *ID);
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address);
uint8_t BSP_W25Qx_Erase_Chip(void);#endif 3,测试
BSP_W25Qx_Read_ID(ID);BSP_W25Qx_Write(wr_buf,0,10);delay_ms(100);
BSP_W25Qx_Read(rd_buf,0, 10);delay_ms(100);for(i=0;i<10;i++){printf("\r\n rd_buf = %d ",rd_buf[i]);} 四,总结。
8MB=128块(64KB) 1块=16扇区(4KB) 1扇区=16页(256B)
1页(page) = 256B
1扇区(sector)=16页(256B)=16*256 = 4096B = 4KB
1块((block)=16扇区 = 16*4096B =65536B = 64KB
w25q64 大小 64Mbit 即8MByte
驱动程序只要是配置SPI,配置好以后,读写一般没有问题


















