|
#include <stdio.h>
|
#include "w25q32.h"
|
#include "spi.h"
|
|
/*+------------------------------+
|
*| Debug print macro |
|
*+------------------------------+*/
|
|
#define CONFIG_W25Q_DEBUG
|
|
#ifdef CONFIG_W25Q_DEBUG
|
#define w25q_print(format,args...) printf(format, ##args)
|
#else
|
#define w25q_print(format,args...) do{} while(0)
|
#endif
|
|
/*+------------------------------+
|
*| SPI Hardware definition |
|
*+------------------------------+*/
|
|
#define W25Q_SPI &hspi1
|
#define W25Q_CS_GPIO SPI1_CS_GPIO_Port
|
#define W25Q_CS_PIN SPI1_CS_Pin
|
#define DUMMY_BYTE 0xFF
|
|
#define w25q_delay(delay) HAL_Delay(delay)
|
#define w25q_cs_enable() HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET)
|
#define w25q_cs_disable() HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET)
|
|
/*+------------------------------+
|
*| W25Q Serial SPI Flash |
|
*+------------------------------+*/
|
|
/* Winbond -- w25x "page" are 256, "sectors" are 4KiB, "blocks" are 64K */
|
|
#define MB 0x100000
|
#define W25Q_PGESIZE 256
|
#define W25Q_SECSIZE 4096
|
#define W25Q_BLKSIZE 65536
|
#define W25Q_NPGES(size) ( ((size)*MB) / W25Q_PGESIZE )
|
#define W25Q_NSECS(size) ( ((size)*MB) / W25Q_SECSIZE )
|
#define W25Q_NBLKS(size) ( ((size)*MB) / W25Q_BLKSIZE )
|
|
#define INFO(_name, _jedecid, _npages, _nsectors, _nblocks) \
|
.name = _name, \
|
.id = _jedecid, \
|
.pagesize = W25Q_PGESIZE, \
|
.npages = _npages, \
|
.sectorsize = W25Q_SECSIZE, \
|
.nsectors = _nsectors, \
|
.blocksize = W25Q_BLKSIZE, \
|
.nblocks = _nblocks,
|
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
flash_info_t w25q_ids[] =
|
{
|
/* 1MB */
|
{ INFO("w25q80bl", 0xef4014, W25Q_NPGES(1), W25Q_NSECS(1), W25Q_NBLKS(1)) },
|
{ INFO("w25q80", 0xef5014, W25Q_NPGES(1), W25Q_NSECS(1), W25Q_NBLKS(1)) },
|
|
/* 2MB */
|
{ INFO("w25q16cl", 0xef4015, W25Q_NPGES(2), W25Q_NSECS(2), W25Q_NBLKS(2)) },
|
{ INFO("w25q16dw", 0xef6015, W25Q_NPGES(2), W25Q_NSECS(2), W25Q_NBLKS(2)) },
|
|
/* 4MB */
|
{ INFO("w25q32", 0xef4016, W25Q_NPGES(4), W25Q_NSECS(4), W25Q_NBLKS(4)) },
|
{ INFO("w25q32dw", 0xef6016, W25Q_NPGES(4), W25Q_NSECS(4), W25Q_NBLKS(4)) },
|
{ INFO("w25q32jv", 0xef7016, W25Q_NPGES(4), W25Q_NSECS(4), W25Q_NBLKS(4)) },
|
{ INFO("w25q32jwm", 0xef8016, W25Q_NPGES(4), W25Q_NSECS(4), W25Q_NBLKS(4)) },
|
|
/* 8MB */
|
{ INFO("w25q64cv", 0xef4017, W25Q_NPGES(8), W25Q_NSECS(8), W25Q_NBLKS(8)) },
|
{ INFO("w25q64dw", 0xef6017, W25Q_NPGES(8), W25Q_NSECS(8), W25Q_NBLKS(8)) },
|
{ INFO("w25q64jv", 0xef7017, W25Q_NPGES(8), W25Q_NSECS(8), W25Q_NBLKS(8)) },
|
|
/* 16MB */
|
{ INFO("w25q128", 0xef4018, W25Q_NPGES(16), W25Q_NSECS(16), W25Q_NBLKS(16)) },
|
{ INFO("w25q128fw", 0xef6018, W25Q_NPGES(16), W25Q_NSECS(16), W25Q_NBLKS(16)) },
|
{ INFO("w25q128jv", 0xef7018, W25Q_NPGES(16), W25Q_NSECS(16), W25Q_NBLKS(16)) },
|
|
/* 32MB */
|
{ INFO("w25q256", 0xef4019, W25Q_NPGES(32), W25Q_NSECS(32), W25Q_NBLKS(32)) },
|
{ INFO("w25q256fw", 0xef6019, W25Q_NPGES(32), W25Q_NSECS(32), W25Q_NBLKS(32)) },
|
{ INFO("w25q256jw", 0xef7019, W25Q_NPGES(32), W25Q_NSECS(32), W25Q_NBLKS(32)) },
|
};
|
|
/*+------------------------------+
|
*| W25Q Serial Flash Driver |
|
*+------------------------------+*/
|
|
flash_info_t *w25q;
|
|
static inline uint8_t w25q_spi_xfer(uint8_t txbyte)
|
{
|
uint8_t rxbyte = 0x00;
|
|
HAL_SPI_TransmitReceive(W25Q_SPI, &txbyte, &rxbyte, 1, 0xFFFF);
|
|
return rxbyte;
|
}
|
|
void w25q_Reset(void)
|
{
|
w25q_cs_enable();
|
|
w25q_spi_xfer(0x66); // enable reset
|
w25q_spi_xfer(0x99); // reset
|
|
w25q_cs_disable();
|
}
|
|
uint16_t w25q_ReadID(void)
|
{
|
uint16_t ID = 0x0;
|
|
w25q_cs_enable();
|
|
w25q_spi_xfer(0x90);
|
w25q_spi_xfer(DUMMY_BYTE);
|
w25q_spi_xfer(DUMMY_BYTE);
|
w25q_spi_xfer(0x00);
|
|
ID |= w25q_spi_xfer(DUMMY_BYTE)<<8; /* Manufacturer ID */
|
ID |= w25q_spi_xfer(DUMMY_BYTE); /* Device ID */
|
|
w25q_cs_disable();
|
|
return ID;
|
}
|
|
uint32_t w25q_ReadJedecID(void)
|
{
|
uint32_t ID = 0x0;
|
|
w25q_cs_enable();
|
|
w25q_spi_xfer(0x9F);
|
|
ID |= w25q_spi_xfer(DUMMY_BYTE)<<16; /* Manufacturer ID */
|
ID |= w25q_spi_xfer(DUMMY_BYTE)<<8; /* Device ID15~ID8 */
|
ID |= w25q_spi_xfer(DUMMY_BYTE)<<0; /* Device ID7~ID0 */
|
|
w25q_cs_disable();
|
|
return ID;
|
}
|
|
int w25q_Init(void)
|
{
|
uint16_t chipID;
|
uint32_t jedecID;
|
int i, found = 0;
|
int rv = 0;
|
|
w25q_Reset();
|
|
chipID = w25q_ReadID();
|
if( 0x00 == chipID )
|
{
|
rv = -2;
|
goto cleanup;
|
}
|
w25q_print("W25Q device ID: %04x\r\n", chipID);
|
|
jedecID = w25q_ReadJedecID();
|
if( 0x00 == jedecID )
|
{
|
rv = -3;
|
goto cleanup;
|
}
|
w25q_print("W25Q JEDEC ID: %lx\r\n", jedecID);
|
|
for(i=0; i<ARRAY_SIZE(w25q_ids); i++)
|
{
|
if( w25q_ids[i].id == jedecID )
|
{
|
found = 1;
|
w25q = &w25q_ids[i];
|
}
|
}
|
|
rv = -4;
|
|
cleanup:
|
if( found )
|
{
|
w25q_print("Dectec Norflash %s, Capacity %lu KB\r\n", w25q->name, w25q->blocksize*w25q->nblocks/1024);
|
return 0;
|
}
|
|
w25q_print("ERROR: Can not found W25Q chipset by JDEDEC\r\n");
|
return rv;
|
}
|
|
static inline void w25q_WriteEnable(void)
|
{
|
w25q_cs_enable();
|
w25q_spi_xfer(0x06);
|
w25q_cs_disable();
|
}
|
|
static inline void w25q_WriteDisable(void)
|
{
|
w25q_cs_enable();
|
w25q_spi_xfer(0x04);
|
w25q_cs_disable();
|
|
w25q_delay(1);
|
}
|
|
static inline uint8_t w25q_ReadSR(int reg)
|
{
|
uint8_t status = 0;
|
|
w25q_cs_enable();
|
|
if (REG_SR1 == reg)
|
{
|
w25q_spi_xfer(0x05);
|
status = w25q_spi_xfer(DUMMY_BYTE);
|
}
|
else if (REG_SR2 == reg)
|
{
|
w25q_spi_xfer(0x35);
|
status = w25q_spi_xfer(DUMMY_BYTE);
|
}
|
else if (REG_SR3 == reg)
|
{
|
w25q_spi_xfer(0x15);
|
status = w25q_spi_xfer(DUMMY_BYTE);
|
}
|
|
w25q_cs_disable();
|
return status;
|
}
|
|
static inline void w25q_WriteSR(int reg, uint8_t data)
|
{
|
w25q_cs_enable();
|
|
if (REG_SR1 == reg)
|
{
|
w25q_spi_xfer(0x01);
|
}
|
else if (REG_SR2 == reg)
|
{
|
w25q_spi_xfer(0x31);
|
}
|
else if (REG_SR2 == reg)
|
{
|
w25q_spi_xfer(0x11);
|
}
|
|
w25q_spi_xfer(data);
|
w25q_cs_disable();
|
|
return ;
|
}
|
|
/* Status Register[1] bit[0]: Erase/Write In Progress (BUSY) */
|
void w25q_Wait4Ready(void)
|
{
|
uint8_t regval;
|
|
do
|
{
|
w25q_delay(1);
|
regval = w25q_ReadSR(REG_SR1);
|
} while ( !(regval&0x01) );
|
|
return ;
|
}
|
|
|
void w25q_EraseChip(void)
|
{
|
w25q_WriteEnable();
|
|
w25q_cs_enable();
|
w25q_spi_xfer(0xC7);
|
w25q_cs_disable();
|
|
w25q_Wait4Ready();
|
w25q_print("chip erase %s done!\r\n", w25q->name);
|
|
return ;
|
}
|
|
#if 0
|
|
//###################################################################################################################
|
void w25q_EraseChip(void)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
uint32_t StartTime = HAL_GetTick();
|
printf("w25q EraseChip Begin...\r\n");
|
#endif
|
w25q_WriteEnable();
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
w25q_spi_xfer(0xC7);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
w25q_WaitForWriteEnd();
|
#if (_w25q_DEBUG == 1)
|
printf("w25q EraseBlock done after %d ms!\r\n", HAL_GetTick() - StartTime);
|
#endif
|
w25q_delay(10);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_EraseSector(uint32_t SectorAddr)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
uint32_t StartTime = HAL_GetTick();
|
printf("w25q EraseSector %d Begin...\r\n", SectorAddr);
|
#endif
|
w25q_WaitForWriteEnd();
|
SectorAddr = SectorAddr * w25q.SectorSize;
|
w25q_WriteEnable();
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x21);
|
w25q_spi_xfer((SectorAddr & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x20);
|
}
|
w25q_spi_xfer((SectorAddr & 0xFF0000) >> 16);
|
w25q_spi_xfer((SectorAddr & 0xFF00) >> 8);
|
w25q_spi_xfer(SectorAddr & 0xFF);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
w25q_WaitForWriteEnd();
|
#if (_w25q_DEBUG == 1)
|
printf("w25q EraseSector done after %d ms\r\n", HAL_GetTick() - StartTime);
|
#endif
|
w25q_delay(1);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_EraseBlock(uint32_t BlockAddr)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q EraseBlock %d Begin...\r\n", BlockAddr);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
w25q_WaitForWriteEnd();
|
BlockAddr = BlockAddr * w25q.SectorSize * 16;
|
w25q_WriteEnable();
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0xDC);
|
w25q_spi_xfer((BlockAddr & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0xD8);
|
}
|
w25q_spi_xfer((BlockAddr & 0xFF0000) >> 16);
|
w25q_spi_xfer((BlockAddr & 0xFF00) >> 8);
|
w25q_spi_xfer(BlockAddr & 0xFF);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
w25q_WaitForWriteEnd();
|
#if (_w25q_DEBUG == 1)
|
printf("w25q EraseBlock done after %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q_delay(1);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
uint32_t w25q_PageToSector(uint32_t PageAddress)
|
{
|
return ((PageAddress * w25q.PageSize) / w25q.SectorSize);
|
}
|
//###################################################################################################################
|
uint32_t w25q_PageToBlock(uint32_t PageAddress)
|
{
|
return ((PageAddress * w25q.PageSize) / w25q.BlockSize);
|
}
|
//###################################################################################################################
|
uint32_t w25q_SectorToBlock(uint32_t SectorAddress)
|
{
|
return ((SectorAddress * w25q.SectorSize) / w25q.BlockSize);
|
}
|
//###################################################################################################################
|
uint32_t w25q_SectorToPage(uint32_t SectorAddress)
|
{
|
return (SectorAddress * w25q.SectorSize) / w25q.PageSize;
|
}
|
//###################################################################################################################
|
uint32_t w25q_BlockToPage(uint32_t BlockAddress)
|
{
|
return (BlockAddress * w25q.BlockSize) / w25q.PageSize;
|
}
|
//###################################################################################################################
|
bool w25q_IsEmptyPage(uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_PageSize)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
if (((NumByteToCheck_up_to_PageSize + OffsetInByte) > w25q.PageSize) || (NumByteToCheck_up_to_PageSize == 0))
|
NumByteToCheck_up_to_PageSize = w25q.PageSize - OffsetInByte;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckPage:%d, Offset:%d, Bytes:%d begin...\r\n", Page_Address, OffsetInByte, NumByteToCheck_up_to_PageSize);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
uint8_t pBuffer[32];
|
uint32_t WorkAddress;
|
uint32_t i;
|
for (i = OffsetInByte; i < w25q.PageSize; i += sizeof(pBuffer))
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Page_Address * w25q.PageSize);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, sizeof(pBuffer), 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
for (uint8_t x = 0; x < sizeof(pBuffer); x++)
|
{
|
if (pBuffer[x] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
if ((w25q.PageSize + OffsetInByte) % sizeof(pBuffer) != 0)
|
{
|
i -= sizeof(pBuffer);
|
for (; i < w25q.PageSize; i++)
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Page_Address * w25q.PageSize);
|
w25q_spi_xfer(0x0B);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, 1, 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
if (pBuffer[0] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckPage is Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return true;
|
NOT_EMPTY:
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckPage is Not Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return false;
|
}
|
//###################################################################################################################
|
bool w25q_IsEmptySector(uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_SectorSize)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
if ((NumByteToCheck_up_to_SectorSize > w25q.SectorSize) || (NumByteToCheck_up_to_SectorSize == 0))
|
NumByteToCheck_up_to_SectorSize = w25q.SectorSize;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckSector:%d, Offset:%d, Bytes:%d begin...\r\n", Sector_Address, OffsetInByte, NumByteToCheck_up_to_SectorSize);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
uint8_t pBuffer[32];
|
uint32_t WorkAddress;
|
uint32_t i;
|
for (i = OffsetInByte; i < w25q.SectorSize; i += sizeof(pBuffer))
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Sector_Address * w25q.SectorSize);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, sizeof(pBuffer), 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
for (uint8_t x = 0; x < sizeof(pBuffer); x++)
|
{
|
if (pBuffer[x] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
if ((w25q.SectorSize + OffsetInByte) % sizeof(pBuffer) != 0)
|
{
|
i -= sizeof(pBuffer);
|
for (; i < w25q.SectorSize; i++)
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Sector_Address * w25q.SectorSize);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, 1, 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
if (pBuffer[0] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckSector is Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return true;
|
NOT_EMPTY:
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckSector is Not Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return false;
|
}
|
//###################################################################################################################
|
bool w25q_IsEmptyBlock(uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_BlockSize)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
if ((NumByteToCheck_up_to_BlockSize > w25q.BlockSize) || (NumByteToCheck_up_to_BlockSize == 0))
|
NumByteToCheck_up_to_BlockSize = w25q.BlockSize;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckBlock:%d, Offset:%d, Bytes:%d begin...\r\n", Block_Address, OffsetInByte, NumByteToCheck_up_to_BlockSize);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
uint8_t pBuffer[32];
|
uint32_t WorkAddress;
|
uint32_t i;
|
for (i = OffsetInByte; i < w25q.BlockSize; i += sizeof(pBuffer))
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Block_Address * w25q.BlockSize);
|
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, sizeof(pBuffer), 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
for (uint8_t x = 0; x < sizeof(pBuffer); x++)
|
{
|
if (pBuffer[x] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
if ((w25q.BlockSize + OffsetInByte) % sizeof(pBuffer) != 0)
|
{
|
i -= sizeof(pBuffer);
|
for (; i < w25q.BlockSize; i++)
|
{
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
WorkAddress = (i + Block_Address * w25q.BlockSize);
|
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((WorkAddress & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((WorkAddress & 0xFF0000) >> 16);
|
w25q_spi_xfer((WorkAddress & 0xFF00) >> 8);
|
w25q_spi_xfer(WorkAddress & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, 1, 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
if (pBuffer[0] != 0xFF)
|
goto NOT_EMPTY;
|
}
|
}
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckBlock is Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return true;
|
NOT_EMPTY:
|
#if (_w25q_DEBUG == 1)
|
printf("w25q CheckBlock is Not Empty in %d ms\r\n", HAL_GetTick() - StartTime);
|
w25q_delay(100);
|
#endif
|
w25q.Lock = 0;
|
return false;
|
}
|
//###################################################################################################################
|
void w25q_WriteByte(uint8_t pBuffer, uint32_t WriteAddr_inBytes)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
uint32_t StartTime = HAL_GetTick();
|
printf("w25q WriteByte 0x%02X at address %d begin...", pBuffer, WriteAddr_inBytes);
|
#endif
|
w25q_WaitForWriteEnd();
|
w25q_WriteEnable();
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x12);
|
w25q_spi_xfer((WriteAddr_inBytes & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x02);
|
}
|
w25q_spi_xfer((WriteAddr_inBytes & 0xFF0000) >> 16);
|
w25q_spi_xfer((WriteAddr_inBytes & 0xFF00) >> 8);
|
w25q_spi_xfer(WriteAddr_inBytes & 0xFF);
|
w25q_spi_xfer(pBuffer);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
w25q_WaitForWriteEnd();
|
#if (_w25q_DEBUG == 1)
|
printf("w25q WriteByte done after %d ms\r\n", HAL_GetTick() - StartTime);
|
#endif
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_WritePage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
if (((NumByteToWrite_up_to_PageSize + OffsetInByte) > w25q.PageSize) || (NumByteToWrite_up_to_PageSize == 0))
|
NumByteToWrite_up_to_PageSize = w25q.PageSize - OffsetInByte;
|
if ((OffsetInByte + NumByteToWrite_up_to_PageSize) > w25q.PageSize)
|
NumByteToWrite_up_to_PageSize = w25q.PageSize - OffsetInByte;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q WritePage:%d, Offset:%d ,Writes %d Bytes, begin...\r\n", Page_Address, OffsetInByte, NumByteToWrite_up_to_PageSize);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
w25q_WaitForWriteEnd();
|
w25q_WriteEnable();
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
Page_Address = (Page_Address * w25q.PageSize) + OffsetInByte;
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x12);
|
w25q_spi_xfer((Page_Address & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x02);
|
}
|
w25q_spi_xfer((Page_Address & 0xFF0000) >> 16);
|
w25q_spi_xfer((Page_Address & 0xFF00) >> 8);
|
w25q_spi_xfer(Page_Address & 0xFF);
|
HAL_SPI_Transmit(&_W25q_spi_xfer, pBuffer, NumByteToWrite_up_to_PageSize, 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
w25q_WaitForWriteEnd();
|
#if (_w25q_DEBUG == 1)
|
StartTime = HAL_GetTick() - StartTime;
|
for (uint32_t i = 0; i < NumByteToWrite_up_to_PageSize; i++)
|
{
|
if ((i % 8 == 0) && (i > 2))
|
{
|
printf("\r\n");
|
w25q_delay(10);
|
}
|
printf("0x%02X,", pBuffer[i]);
|
}
|
printf("\r\n");
|
printf("w25q WritePage done after %d ms\r\n", StartTime);
|
w25q_delay(100);
|
#endif
|
w25q_delay(1);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_WriteSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_SectorSize)
|
{
|
if ((NumByteToWrite_up_to_SectorSize > w25q.SectorSize) || (NumByteToWrite_up_to_SectorSize == 0))
|
NumByteToWrite_up_to_SectorSize = w25q.SectorSize;
|
#if (_w25q_DEBUG == 1)
|
printf("+++w25q WriteSector:%d, Offset:%d ,Write %d Bytes, begin...\r\n", Sector_Address, OffsetInByte, NumByteToWrite_up_to_SectorSize);
|
w25q_delay(100);
|
#endif
|
if (OffsetInByte >= w25q.SectorSize)
|
{
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q WriteSector Faild!\r\n");
|
w25q_delay(100);
|
#endif
|
return;
|
}
|
uint32_t StartPage;
|
int32_t BytesToWrite;
|
uint32_t LocalOffset;
|
if ((OffsetInByte + NumByteToWrite_up_to_SectorSize) > w25q.SectorSize)
|
BytesToWrite = w25q.SectorSize - OffsetInByte;
|
else
|
BytesToWrite = NumByteToWrite_up_to_SectorSize;
|
StartPage = w25q_SectorToPage(Sector_Address) + (OffsetInByte / w25q.PageSize);
|
LocalOffset = OffsetInByte % w25q.PageSize;
|
do
|
{
|
w25q_WritePage(pBuffer, StartPage, LocalOffset, BytesToWrite);
|
StartPage++;
|
BytesToWrite -= w25q.PageSize - LocalOffset;
|
pBuffer += w25q.PageSize - LocalOffset;
|
LocalOffset = 0;
|
} while (BytesToWrite > 0);
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q WriteSector Done\r\n");
|
w25q_delay(100);
|
#endif
|
}
|
//###################################################################################################################
|
void w25q_WriteBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_BlockSize)
|
{
|
if ((NumByteToWrite_up_to_BlockSize > w25q.BlockSize) || (NumByteToWrite_up_to_BlockSize == 0))
|
NumByteToWrite_up_to_BlockSize = w25q.BlockSize;
|
#if (_w25q_DEBUG == 1)
|
printf("+++w25q WriteBlock:%d, Offset:%d ,Write %d Bytes, begin...\r\n", Block_Address, OffsetInByte, NumByteToWrite_up_to_BlockSize);
|
w25q_delay(100);
|
#endif
|
if (OffsetInByte >= w25q.BlockSize)
|
{
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q WriteBlock Faild!\r\n");
|
w25q_delay(100);
|
#endif
|
return;
|
}
|
uint32_t StartPage;
|
int32_t BytesToWrite;
|
uint32_t LocalOffset;
|
if ((OffsetInByte + NumByteToWrite_up_to_BlockSize) > w25q.BlockSize)
|
BytesToWrite = w25q.BlockSize - OffsetInByte;
|
else
|
BytesToWrite = NumByteToWrite_up_to_BlockSize;
|
StartPage = w25q_BlockToPage(Block_Address) + (OffsetInByte / w25q.PageSize);
|
LocalOffset = OffsetInByte % w25q.PageSize;
|
do
|
{
|
w25q_WritePage(pBuffer, StartPage, LocalOffset, BytesToWrite);
|
StartPage++;
|
BytesToWrite -= w25q.PageSize - LocalOffset;
|
pBuffer += w25q.PageSize - LocalOffset;
|
LocalOffset = 0;
|
} while (BytesToWrite > 0);
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q WriteBlock Done\r\n");
|
w25q_delay(100);
|
#endif
|
}
|
//###################################################################################################################
|
void w25q_ReadByte(uint8_t *pBuffer, uint32_t Bytes_Address)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
uint32_t StartTime = HAL_GetTick();
|
printf("w25q ReadByte at address %d begin...\r\n", Bytes_Address);
|
#endif
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((Bytes_Address & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((Bytes_Address & 0xFF0000) >> 16);
|
w25q_spi_xfer((Bytes_Address & 0xFF00) >> 8);
|
w25q_spi_xfer(Bytes_Address & 0xFF);
|
w25q_spi_xfer(0);
|
*pBuffer = w25q_spi_xfer(DUMMY_BYTE);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
#if (_w25q_DEBUG == 1)
|
printf("w25q ReadByte 0x%02X done after %d ms\r\n", *pBuffer, HAL_GetTick() - StartTime);
|
#endif
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_ReadBytes(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
#if (_w25q_DEBUG == 1)
|
uint32_t StartTime = HAL_GetTick();
|
printf("w25q ReadBytes at Address:%d, %d Bytes begin...\r\n", ReadAddr, NumByteToRead);
|
#endif
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((ReadAddr & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((ReadAddr & 0xFF0000) >> 16);
|
w25q_spi_xfer((ReadAddr & 0xFF00) >> 8);
|
w25q_spi_xfer(ReadAddr & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, NumByteToRead, 2000);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
#if (_w25q_DEBUG == 1)
|
StartTime = HAL_GetTick() - StartTime;
|
for (uint32_t i = 0; i < NumByteToRead; i++)
|
{
|
if ((i % 8 == 0) && (i > 2))
|
{
|
printf("\r\n");
|
w25q_delay(10);
|
}
|
printf("0x%02X,", pBuffer[i]);
|
}
|
printf("\r\n");
|
printf("w25q ReadBytes done after %d ms\r\n", StartTime);
|
w25q_delay(100);
|
#endif
|
w25q_delay(1);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_ReadPage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_PageSize)
|
{
|
while (w25q.Lock == 1)
|
w25q_delay(1);
|
w25q.Lock = 1;
|
if ((NumByteToRead_up_to_PageSize > w25q.PageSize) || (NumByteToRead_up_to_PageSize == 0))
|
NumByteToRead_up_to_PageSize = w25q.PageSize;
|
if ((OffsetInByte + NumByteToRead_up_to_PageSize) > w25q.PageSize)
|
NumByteToRead_up_to_PageSize = w25q.PageSize - OffsetInByte;
|
#if (_w25q_DEBUG == 1)
|
printf("w25q ReadPage:%d, Offset:%d ,Read %d Bytes, begin...\r\n", Page_Address, OffsetInByte, NumByteToRead_up_to_PageSize);
|
w25q_delay(100);
|
uint32_t StartTime = HAL_GetTick();
|
#endif
|
Page_Address = Page_Address * w25q.PageSize + OffsetInByte;
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_RESET);
|
if (w25q.ID >= W25Q256)
|
{
|
w25q_spi_xfer(0x0C);
|
w25q_spi_xfer((Page_Address & 0xFF000000) >> 24);
|
}
|
else
|
{
|
w25q_spi_xfer(0x0B);
|
}
|
w25q_spi_xfer((Page_Address & 0xFF0000) >> 16);
|
w25q_spi_xfer((Page_Address & 0xFF00) >> 8);
|
w25q_spi_xfer(Page_Address & 0xFF);
|
w25q_spi_xfer(0);
|
HAL_SPI_Receive(&_W25q_spi_xfer, pBuffer, NumByteToRead_up_to_PageSize, 100);
|
HAL_GPIO_WritePin(W25Q_CS_GPIO, W25Q_CS_PIN, GPIO_PIN_SET);
|
#if (_w25q_DEBUG == 1)
|
StartTime = HAL_GetTick() - StartTime;
|
for (uint32_t i = 0; i < NumByteToRead_up_to_PageSize; i++)
|
{
|
if ((i % 8 == 0) && (i > 2))
|
{
|
printf("\r\n");
|
w25q_delay(10);
|
}
|
printf("0x%02X,", pBuffer[i]);
|
}
|
printf("\r\n");
|
printf("w25q ReadPage done after %d ms\r\n", StartTime);
|
w25q_delay(100);
|
#endif
|
w25q_delay(1);
|
w25q.Lock = 0;
|
}
|
//###################################################################################################################
|
void w25q_ReadSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_SectorSize)
|
{
|
if ((NumByteToRead_up_to_SectorSize > w25q.SectorSize) || (NumByteToRead_up_to_SectorSize == 0))
|
NumByteToRead_up_to_SectorSize = w25q.SectorSize;
|
#if (_w25q_DEBUG == 1)
|
printf("+++w25q ReadSector:%d, Offset:%d ,Read %d Bytes, begin...\r\n", Sector_Address, OffsetInByte, NumByteToRead_up_to_SectorSize);
|
w25q_delay(100);
|
#endif
|
if (OffsetInByte >= w25q.SectorSize)
|
{
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q ReadSector Faild!\r\n");
|
w25q_delay(100);
|
#endif
|
return;
|
}
|
uint32_t StartPage;
|
int32_t BytesToRead;
|
uint32_t LocalOffset;
|
if ((OffsetInByte + NumByteToRead_up_to_SectorSize) > w25q.SectorSize)
|
BytesToRead = w25q.SectorSize - OffsetInByte;
|
else
|
BytesToRead = NumByteToRead_up_to_SectorSize;
|
StartPage = w25q_SectorToPage(Sector_Address) + (OffsetInByte / w25q.PageSize);
|
LocalOffset = OffsetInByte % w25q.PageSize;
|
do
|
{
|
w25q_ReadPage(pBuffer, StartPage, LocalOffset, BytesToRead);
|
StartPage++;
|
BytesToRead -= w25q.PageSize - LocalOffset;
|
pBuffer += w25q.PageSize - LocalOffset;
|
LocalOffset = 0;
|
} while (BytesToRead > 0);
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q ReadSector Done\r\n");
|
w25q_delay(100);
|
#endif
|
}
|
//###################################################################################################################
|
void w25q_ReadBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_BlockSize)
|
{
|
if ((NumByteToRead_up_to_BlockSize > w25q.BlockSize) || (NumByteToRead_up_to_BlockSize == 0))
|
NumByteToRead_up_to_BlockSize = w25q.BlockSize;
|
#if (_w25q_DEBUG == 1)
|
printf("+++w25q ReadBlock:%d, Offset:%d ,Read %d Bytes, begin...\r\n", Block_Address, OffsetInByte, NumByteToRead_up_to_BlockSize);
|
w25q_delay(100);
|
#endif
|
if (OffsetInByte >= w25q.BlockSize)
|
{
|
#if (_w25q_DEBUG == 1)
|
printf("w25q ReadBlock Faild!\r\n");
|
w25q_delay(100);
|
#endif
|
return;
|
}
|
uint32_t StartPage;
|
int32_t BytesToRead;
|
uint32_t LocalOffset;
|
if ((OffsetInByte + NumByteToRead_up_to_BlockSize) > w25q.BlockSize)
|
BytesToRead = w25q.BlockSize - OffsetInByte;
|
else
|
BytesToRead = NumByteToRead_up_to_BlockSize;
|
StartPage = w25q_BlockToPage(Block_Address) + (OffsetInByte / w25q.PageSize);
|
LocalOffset = OffsetInByte % w25q.PageSize;
|
do
|
{
|
w25q_ReadPage(pBuffer, StartPage, LocalOffset, BytesToRead);
|
StartPage++;
|
BytesToRead -= w25q.PageSize - LocalOffset;
|
pBuffer += w25q.PageSize - LocalOffset;
|
LocalOffset = 0;
|
} while (BytesToRead > 0);
|
#if (_w25q_DEBUG == 1)
|
printf("---w25q ReadBlock Done\r\n");
|
w25q_delay(100);
|
#endif
|
}
|
|
#endif
|