一、w25qxx驱动原理
w25qxx使用spi接口驱动,下面是它的时序图
从图上看,spi有两种配置模式:
1、低电平,第一个边缘;
2、高电平,第二个边缘;
二、stm32CubeMx配置:
三、w25qxx驱动代码:
1、w25qxx.h
#ifndef __W25QXX_H__
#define __W25QXX_H__
#include
#include 'spi.h'
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg1 0x05
#define W25X_WriteStatusReg1 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define WIP_Flag 0x01 /* Write In Progress (WIP) flag */
#define W25QXX_DUMMY_BYTE 0xFF
#pragma pack(1)
typedef enum
{
W25Q10=1,
W25Q20,
W25Q40,
W25Q80,
W25Q16,
W25Q32,
W25Q64,
W25Q128,
W25Q256,
W25Q512,
}W25QXX_ID_t;
typedef struct
{
W25QXX_ID_t ID;
uint8_t UniqID[8];
uint16_t PageSize;
uint32_t PageCount;
uint32_t SectorSize;
uint32_t SectorCount;
uint32_t BlockSize;
uint32_t BlockCount;
uint32_t CapacityInKiloByte;
uint8_t StatusRegister1;
uint8_t StatusRegister2;
uint8_t StatusRegister3;
uint8_t Lock;
}w25qxx_t;
#pragma pack()
extern w25qxx_t w25qxx;
/************************************************用户API*******************************************/
bool W25qxx_Init(void);
void W25qxx_EraseChip(void);
void W25qxx_EraseSector(uint32_t SectorAddr);
void W25qxx_EraseBlock(uint32_t BlockAddr);
uint32_t W25qxx_PageToSector(uint32_t PageAddress);
uint32_t W25qxx_PageToBlock(uint32_t PageAddress);
uint32_t W25qxx_SectorToBlock(uint32_t SectorAddress);
uint32_t W25qxx_SectorToPage(uint32_t SectorAddress);
uint32_t W25qxx_BlockToPage(uint32_t BlockAddress);
void W25qxx_WriteByte(uint8_t pBuffer, uint32_t WriteAddr);
void W25qxx_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void W25qxx_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void W25qxx_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
#endif
2、w25qxx.c
#include 'w25qxx.h'
#include 'w25qxx_config.h'
#if (_W25QXX_DEBUG == 1)
#include
#endif
#define W25QXX_CS_H HAL_GPIO_WritePin(_W25QXX_CS_GPIO, _W25QXX_CS_PIN, GPIO_PIN_SET);
#define W25QXX_CS_L HAL_GPIO_WritePin(_W25QXX_CS_GPIO, _W25QXX_CS_PIN, GPIO_PIN_RESET);
w25qxx_t w25qxx;
#if (_W25QXX_USE_FREERTOS == 1)
#define W25qxx_Delay(delay) osDelay(delay)
#include 'cmsis_os.h'
#else
#define W25qxx_Delay(delay) for(uint8_t i=0;i<255;i++);;
#endif
//###################################################################################################################
uint8_t W25qxx_Spi(uint8_t Data)
{
uint8_t ret;
HAL_SPI_TransmitReceive(&_W25QXX_SPI, &Data, &ret, 1, 100);
return ret;
}
//###################################################################################################################
uint32_t W25qxx_ReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
W25QXX_CS_L;
W25qxx_Spi(W25X_JedecDeviceID);
Temp0 = W25qxx_Spi(W25QXX_DUMMY_BYTE);
Temp1 = W25qxx_Spi(W25QXX_DUMMY_BYTE);
Temp2 = W25qxx_Spi(W25QXX_DUMMY_BYTE);
W25QXX_CS_H;
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
//###################################################################################################################
void W25qxx_ReadUniqID(void)
{
W25QXX_CS_L;
W25qxx_Spi(0x4B);
for(uint8_t i = 0; i < 4; i++)
{
W25qxx_Spi(W25QXX_DUMMY_BYTE);
}
for(uint8_t i = 0; i < 8; i++)
{
w25qxx.UniqID[i] = W25qxx_Spi(W25QXX_DUMMY_BYTE);
}
W25QXX_CS_H;
}
//###################################################################################################################
void W25qxx_WriteEnable(void)
{
W25QXX_CS_L;
W25qxx_Spi(W25X_WriteEnable);
W25QXX_CS_H;
W25qxx_Delay(1);
}
//###################################################################################################################
void W25qxx_WriteDisable(void)
{
W25QXX_CS_L;
W25qxx_Spi(W25X_WriteDisable);
W25QXX_CS_H;
W25qxx_Delay(1);
}
//###################################################################################################################
uint8_t W25qxx_ReadStatusRegister(uint8_t SelectStatusRegister_1_2_3)
{
uint8_t status=0;
W25QXX_CS_L;
if(SelectStatusRegister_1_2_3 == 1)
{
W25qxx_Spi(W25X_ReadStatusReg1);
status=W25qxx_Spi(W25QXX_DUMMY_BYTE);
w25qxx.StatusRegister1 = status;
}
else if(SelectStatusRegister_1_2_3 == 2)
{
W25qxx_Spi(0x35);
status=W25qxx_Spi(W25QXX_DUMMY_BYTE);
w25qxx.StatusRegister2 = status;
}
else
{
W25qxx_Spi(0x15);
status=W25qxx_Spi(W25QXX_DUMMY_BYTE);
w25qxx.StatusRegister3 = status;
}
W25QXX_CS_H;
return status;
}
//###################################################################################################################
void W25qxx_WriteStatusRegister(uint8_t SelectStatusRegister_1_2_3, uint8_t Data)
{
W25QXX_CS_L;
if(SelectStatusRegister_1_2_3 == 1)
{
W25qxx_Spi(W25X_WriteStatusReg1);
w25qxx.StatusRegister1 = Data;
}
else if(SelectStatusRegister_1_2_3 == 2)
{
W25qxx_Spi(0x31);
w25qxx.StatusRegister2 = Data;
}
else
{
W25qxx_Spi(0x11);
w25qxx.StatusRegister3 = Data;
}
W25qxx_Spi(Data);
W25QXX_CS_H;
}
//###################################################################################################################
void W25qxx_WaitForWriteEnd(void)
{
W25QXX_CS_L;
W25qxx_Spi(W25X_ReadStatusReg1);
do
{
w25qxx.StatusRegister1 = W25qxx_Spi(W25QXX_DUMMY_BYTE);
W25qxx_Delay(1);
}
while ((w25qxx.StatusRegister1 & WIP_Flag) == 0x01);
W25QXX_CS_H;
}
//###################################################################################################################
bool W25qxx_Init(void)
{
w25qxx.Lock=1;
// while(HAL_GetTick()<100)
// W25qxx_Delay(1);
W25QXX_CS_H;
// W25qxx_Delay(100);
uint32_t id;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Init Begin...rn');
#endif
id = W25qxx_ReadID();
#if (_W25QXX_DEBUG==1)
printf('w25qxx ID:0x%Xrn',id);
#endif
switch(id&0x0000FFFF)
{
case 0x401A: // w25q512
w25qxx.ID=W25Q512;
w25qxx.BlockCount=1024;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q512rn');
#endif
break;
case 0x4019: // w25q256
w25qxx.ID=W25Q256;
w25qxx.BlockCount=512;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q256rn');
#endif
break;
case 0x4018: // w25q128
w25qxx.ID=W25Q128;
w25qxx.BlockCount=256;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q128rn');
#endif
break;
case 0x4017: // w25q64
w25qxx.ID=W25Q64;
w25qxx.BlockCount=128;
#if (_W25QXX_DEBUG == 1)
printf('w25qxx Chip: w25q64rn');
#endif
break;
case 0x4016: // w25q32
w25qxx.ID=W25Q32;
w25qxx.BlockCount=64;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q32rn');
#endif
break;
case 0x4015: // w25q16
w25qxx.ID=W25Q16;
w25qxx.BlockCount=32;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q16rn');
#endif
break;
case 0x4014: // w25q80
w25qxx.ID=W25Q80;
w25qxx.BlockCount=16;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q80rn');
#endif
break;
case 0x4013: // w25q40
w25qxx.ID=W25Q40;
w25qxx.BlockCount=8;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q40rn');
#endif
break;
case 0x4012: // w25q20
w25qxx.ID=W25Q20;
w25qxx.BlockCount=4;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q20rn');
#endif
break;
case 0x4011: // w25q10
w25qxx.ID=W25Q10;
w25qxx.BlockCount=2;
#if (_W25QXX_DEBUG==1)
printf('w25qxx Chip: w25q10rn');
#endif
break;
default:
#if (_W25QXX_DEBUG==1)
printf('w25qxx Unknown IDrn');
#endif
w25qxx.Lock=0;
return false;
}
w25qxx.PageSize = 256;
w25qxx.SectorSize = 0x1000;
w25qxx.SectorCount = w25qxx.BlockCount * 16;
w25qxx.PageCount = (w25qxx.SectorCount * w25qxx.SectorSize) / w25qxx.PageSize;
w25qxx.BlockSize = w25qxx.SectorSize*16;
w25qxx.CapacityInKiloByte = (w25qxx.SectorCount * w25qxx.SectorSize) / 1024;
W25qxx_ReadUniqID();
W25qxx_ReadStatusRegister(1);
W25qxx_ReadStatusRegister(2);
W25qxx_ReadStatusRegister(3);
#if (_W25QXX_DEBUG == 1)
printf('w25qxx Page Size: %d Bytesrn',w25qxx.PageSize);
printf('w25qxx Page Count: %drn',w25qxx.PageCount);
printf('w25qxx Sector Size: %d Bytesrn',w25qxx.SectorSize);
printf('w25qxx Sector Count: %drn',w25qxx.SectorCount);
printf('w25qxx Block Size: %d Bytesrn',w25qxx.BlockSize);
printf('w25qxx Block Count: %drn',w25qxx.BlockCount);
printf('w25qxx Capacity: %d KiloBytesrn',w25qxx.CapacityInKiloByte);
printf('w25qxx Init Donern');
#endif
w25qxx.Lock = 0;
return true;
}
//###################################################################################################################
void W25qxx_EraseChip(void)
{
while(w25qxx.Lock==1)
{
W25qxx_Delay(1);
}
w25qxx.Lock=1;
#if (_W25QXX_DEBUG == 1)
uint32_t StartTime=HAL_GetTick();
printf('w25qxx EraseChip Begin...rn');
#endif
W25qxx_WriteEnable();
W25QXX_CS_L;
W25qxx_Spi(W25X_ChipErase);
W25QXX_CS_H;
W25qxx_WaitForWriteEnd();
#if (_W25QXX_DEBUG == 1)