1.W25Qxx.h文件
/* W25Q32 */
#define W25QXXXX_FLASH_SIZE 0x0400000 /* 32 MBits => 4MBytes */
#define W25QXXXX_SECTOR_COUNT 0x40 /* 64 sectors of 64KBytes */
#define W25QXXXX_SECTOR_SIZE 0x10000 /* 64 sectors of 64KBytes */
#define W25QXXXX_SUBSECTOR_COUNT 0x0400 /* 1024 subsectors of 4kBytes */
#define W25QXXXX_SUBSECTOR_SIZE 0x1000 /* 1024 subsectors of 4kBytes */
#define W25QXXXX_PAGE_SIZE 0x100 /* 16384 pages of 256 bytes */
#define W25Q80 0XEF13 /* 8Mbit */
#define W25Q16 0XEF14 /* 16Mbit */
#define W25Q32 0XEF15 /* 32Mbit */
#define W25Q64 0XEF16 /* 64Mbit */
#define W25Q128 0XEF17 /* 128Mbit */
#define W25QXXXX_DUMMY_CYCLES_READ 4
#define W25QXXXX_DUMMY_CYCLES_READ_QUAD 10
#define W25QXXXX_BULK_ERASE_MAX_TIME 250000 /* 块擦除最大时间 */
#define W25QXXXX_SECTOR_ERASE_MAX_TIME 3000 /* 扇区擦除最大时间 */
#define W25QXXXX_SUBSECTOR_ERASE_MAX_TIME 800 /* 页擦除最大时间 */
#define W25QXXXX_TIMEOUT_VALUE 1000 /* 写数据超时时间 */
/**
* @brief W25QXX Commands
*/
/* Reset Operations */
#define RESET_ENABLE_CMD 0x66 /* 复位使能 */
#define RESET_MEMORY_CMD 0x99 /* 复位内存 */
#define ENTER_QPI_MODE_CMD 0x38 /* 进入QSPI模式 */
#define EXIT_QPI_MODE_CMD 0xFF /* 推出QSPI模式 */
/* Identification Operations */
#define READ_ID_CMD 0x90 /* 读ID */
#define DUAL_READ_ID_CMD 0x92 /* 读双ID */
#define QUAD_READ_ID_CMD 0x94 /* 读四ID */
#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 W25QXXXX_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25QXXXX_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25QXXXX_FSR_QE ((uint8_t)0x02) /*!< quad enable */
//移植只需要修改这里就行
#define Driver_W25Qxx_CS_Enable() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET)
#define Driver_W25Qxx_CS_Disable() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET)
extern SPI_HandleTypeDef hspi1;
#define Driver_W25Qxx_Transmit(cmd, size) HAL_SPI_Transmit(&hspi1, cmd, size, W25QXXXX_TIMEOUT_VALUE)
#define Deiver_W25Qxx_Receive(cmd, size) HAL_SPI_Receive(&hspi1, cmd, size, W25QXXXX_TIMEOUT_VALUE)
#define Driver_W25Qxx_Get_Tick() HAL_GetTick()
#define Driver_W25Qxx_Delay(ms) HAL_Delay(ms)
typedef struct
{
uint32_t FLASH_JEDECID;
uint32_t FLASH_Id;
uint32_t FLASH_Size;
uint32_t SECTOR_COUNT;
uint32_t SECTOR_SIZE;
uint32_t SUBSECTOR_COUNT;
uint32_t SUBSECTOR_SIZE;
uint32_t PAGE_SIZE;
}W25Qx_Parameter;
W25Qxx_TypeDef Driver_W25Qxx_Read_Data(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
W25Qxx_TypeDef Driver_W25Qxx_Write_Data(const uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
W25Qxx_TypeDef Driver_W25Qxx_Erase_Block(uint32_t Address);
W25Qxx_TypeDef Driver_W25Qxx_Erase_Chip(void);
2.W25Qxx.c文件
/*
WQ25xx:
256byte -- 一页,4k byte -- 一扇区,16扇区 -- 一块
读取器件号,90H
写使能,06H
擦除为一个扇区擦除,20H; 块擦除,DBH
读数据可以一个字节或以上的读取,03H
页编程,02H
*/
W25Qx_Parameter W25Qxx_Para;
static W25Qxx_TypeDef Driver_W25Qxx_Get_Parameter(W25Qx_Parameter *Para);
static W25Qxx_TypeDef Driver_W25Qxx_Get_Status(void);
static W25Qxx_TypeDef Driver_W25Qxx_Write_Enable(void);
/*********************************************************************
* @fn Driver_W25Qxx_Init
*
* @brief W25Qxx初始化.
*
* @param none
*
* @return none
*/
static void Driver_W25Qxx_Init(void)
{
uint8_t cmd[2] = {RESET_ENABLE_CMD, RESET_MEMORY_CMD};
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Driver_W25Qxx_CS_Disable();
Driver_W25Qxx_Delay(5);
if(Driver_W25Qxx_Get_Parameter(&W25Qxx_Para) != W25Qx_OK)
{
}
}
__Function_AUTOInit_W25Qxx(Driver_W25Qxx_Init);
/*********************************************************************
* @fn Driver_W25Qxx_Read_Data
*
* @brief 读取数据.
*
* @param pData:数据地址
*
* @param ReadAddr:起始地址
*
* @param Size:数据大小
*
* @return W25Qxx_TypeDef
*/
W25Qxx_TypeDef Driver_W25Qxx_Read_Data(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
uint8_t cmd[4];
/* 配置读命令和地址 */
cmd[0] = READ_CMD;
cmd[1] = (uint8_t)(ReadAddr >> 16);
cmd[2] = (uint8_t)(ReadAddr >> 8);
cmd[3] = (uint8_t)(ReadAddr);
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
if(Deiver_W25Qxx_Receive(pData, Size) != HAL_OK)
{
return W25Qx_ERROR;
}
Driver_W25Qxx_CS_Disable();
return W25Qx_OK;
}
/*********************************************************************
* @fn Driver_W25Qxx_Write_Data
*
* @brief 写数据.
*
* @param pData:数据地址
*
* @param WriteAddr:写地址
*
* @param Size:数据大小
*
* @return W25Qxx_TypeDef
*/
W25Qxx_TypeDef Driver_W25Qxx_Write_Data(const uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
uint8_t cmd[4];
uint32_t end_addr, current_size, current_addr = 0;
uint32_t tickstart = Driver_W25Qxx_Get_Tick();
/* 计算当前读写起始地址和剩余可擦写大小 */
while (current_addr <= WriteAddr)
{
current_addr += W25QXXXX_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
/* 计算当前剩余可擦写数据大小是否大于需要擦写数据大小 */
if (current_size > Size)
{
current_size = Size;
}
/* 计算起始地址和结束 */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
do
{
/* 配置写命令和地址 */
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);
/* 写使能和控制使能 */
Driver_W25Qxx_Write_Enable();
Driver_W25Qxx_CS_Enable();
/* 发送写使能和地址 */
if(Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd)) != HAL_OK)
{
return W25Qx_ERROR;
}
/* 发送数据 */
if(Driver_W25Qxx_Transmit(pData, current_size) != HAL_OK)
{
return W25Qx_ERROR;
}
Driver_W25Qxx_CS_Disable();
/* 等待写完成信号 */
while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
{
if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_TIMEOUT_VALUE)
{
return W25Qx_TIMEOUT;
}
}
/* 计算是否是需要下一页擦写 */
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + W25QXXXX_PAGE_SIZE) > end_addr) ? \
(end_addr - current_addr) : W25QXXXX_PAGE_SIZE;
} while(current_addr < end_addr);
return W25Qx_OK;
}
/*********************************************************************
* @fn Driver_W25Qxx_Erase_Block
*
* @brief 擦除一个块的数据.
*
* @param Address:擦除地址
*
* @return W25Qxx_TypeDef
*/
W25Qxx_TypeDef Driver_W25Qxx_Erase_Block(uint32_t Address)
{
uint8_t cmd[4];
uint32_t tickstart = Driver_W25Qxx_Get_Tick();
cmd[0] = SECTOR_ERASE_CMD;
cmd[1] = (uint8_t)(Address >> 16);
cmd[2] = (uint8_t)(Address >> 8);
cmd[3] = (uint8_t)(Address);
Driver_W25Qxx_Write_Enable();
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Driver_W25Qxx_CS_Disable();
while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
{
if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_SECTOR_ERASE_MAX_TIME)
{
return W25Qx_TIMEOUT;
}
Driver_W25Qxx_Delay(1);
}
return W25Qx_OK;
}
/*********************************************************************
* @fn Driver_W25Qxx_Erase_Chip
*
* @brief 擦除整个芯片数据.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
W25Qxx_TypeDef Driver_W25Qxx_Erase_Chip(void)
{
uint8_t cmd = CHIP_ERASE_CMD;
uint32_t tickstart = Driver_W25Qxx_Get_Tick();
Driver_W25Qxx_Write_Enable();
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Driver_W25Qxx_CS_Disable();
while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
{
if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_BULK_ERASE_MAX_TIME)
{
return W25Qx_TIMEOUT;
}
}
return W25Qx_OK;
}
/*********************************************************************
* @fn Driver_W25Qxx_Get_Status
*
* @brief W25Qxx获取当前状态.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
static W25Qxx_TypeDef Driver_W25Qxx_Get_Status(void)
{
uint8_t cmd = READ_STATUS_REG1_CMD;
uint8_t status;
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Deiver_W25Qxx_Receive(&status, sizeof(status));
Driver_W25Qxx_CS_Disable();
/* Check the value of the register */
if((status & W25QXXXX_FSR_BUSY) != 0)
{
return W25Qx_BUSY;
}
else
{
return W25Qx_OK;
}
}
/*********************************************************************
* @fn Driver_W25Qxx_Write_Enable
*
* @brief W25Qxx写使能.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
static W25Qxx_TypeDef Driver_W25Qxx_Write_Enable(void)
{
uint8_t cmd = WRITE_ENABLE_CMD;
uint32_t tickstart = Driver_W25Qxx_Get_Tick();
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Driver_W25Qxx_CS_Disable();
while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
{
if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_TIMEOUT_VALUE)
{
return W25Qx_TIMEOUT;
}
Driver_W25Qxx_Delay(1);
}
return W25Qx_OK;
}
/*********************************************************************
* @fn Driver_W25Qxx_Read_ID
*
* @brief W25Qxx读取ID.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
static void Driver_W25Qxx_Read_ID(uint16_t *ID)
{
uint8_t idt[2];
uint8_t cmd[4] = {READ_ID_CMD, 0x00, 0x00, 0x00};
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Deiver_W25Qxx_Receive(&idt[0], sizeof(idt));
Driver_W25Qxx_CS_Disable();
*ID = (idt[0] << 8) + idt[1];
}
/*********************************************************************
* @fn Driver_W25Qxx_Read_JEDECID
*
* @brief W25Qxx读取设备信息.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
static void Driver_W25Qxx_Read_JEDECID(uint32_t *JEDECID)
{
uint8_t idt[3];
uint8_t cmd = READ_JEDEC_ID_CMD;
Driver_W25Qxx_CS_Enable();
Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
Deiver_W25Qxx_Receive(&idt[0], sizeof(idt));
Driver_W25Qxx_CS_Disable();
*JEDECID = (idt[0] << 16) + (idt[1] << 8) + idt[2];
}
/*********************************************************************
* @fn Driver_W25Qxx_Get_Parameter
*
* @brief W25Qxx获取当前芯片信息.
*
* @param none
*
* @return W25Qxx_TypeDef
*/
static W25Qxx_TypeDef Driver_W25Qxx_Get_Parameter(W25Qx_Parameter *Para)
{
uint16_t id;
uint32_t size;
Para->PAGE_SIZE = 256;
Para->SUBSECTOR_SIZE = 4096;
Para->SECTOR_SIZE = 0x10000;
Driver_W25Qxx_Read_ID(&id);
if(id < W25Q80 || id > W25Q128)
{
return W25Qx_ERROR;
}
Driver_W25Qxx_Read_JEDECID(&Para->FLASH_JEDECID);
size = (uint32_t)powf(2, (id - 0xEF13))*1024*1024;
Para->FLASH_Id = id;
Para->FLASH_Size = size;
Para->SUBSECTOR_COUNT = Para->FLASH_Size / Para->SUBSECTOR_SIZE;
Para->SECTOR_COUNT = Para->FLASH_Size / Para->SECTOR_SIZE;
return W25Qx_OK;
}