/********************************************************************** * Copyright: (C)2023 LingYun IoT System Studio * Author: GuoWenxue QQ: 281143292 * Description: ISKBoard W25Qxx SPI norflash Hardware Abstract Layer driver * * ChangeLog: * Version Date Author Description * V1.0.0 2023.04.3 GuoWenxue Release initial version ***********************************************************************/ #include #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; iname, 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