diff --git a/SerialFlash.h b/SerialFlash.h index f51dc21..20d57d1 100644 --- a/SerialFlash.h +++ b/SerialFlash.h @@ -40,6 +40,7 @@ class SerialFlashChip static bool begin(uint8_t pin = 6); static uint32_t capacity(const uint8_t *id); static uint32_t blockSize(); + static uint32_t eraseSectorSize(); static void sleep(); static void wakeup(); static void readID(uint8_t *buf); @@ -50,12 +51,11 @@ class SerialFlashChip static void write(uint32_t addr, const void *buf, uint32_t len); static void eraseAll(); static void eraseBlock(uint32_t addr); + static void eraseSector(uint32_t addr); static SerialFlashFile open(const char *filename); static bool create(const char *filename, uint32_t length, uint32_t align = 0); - static bool createErasable(const char *filename, uint32_t length) { - return create(filename, length, blockSize()); - } + static bool createErasable(const char *filename, uint32_t length); static bool exists(const char *filename); static bool remove(const char *filename); static bool remove(SerialFlashFile &file); diff --git a/SerialFlashChip.cpp b/SerialFlashChip.cpp index a07618b..1bbd253 100644 --- a/SerialFlashChip.cpp +++ b/SerialFlashChip.cpp @@ -46,6 +46,7 @@ static SPIClass& SPIPORT = SPI; #define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands #define FLAG_MULTI_DIE 0x08 // multiple die, don't read cross 32M barrier #define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks +#define FLAG_SECTOR_ERASE 0x20 // has 4k erase sectors #define FLAG_DIE_MASK 0xC0 // top 2 bits count during multi-die erase void SerialFlashChip::wait(void) @@ -288,6 +289,30 @@ void SerialFlashChip::eraseBlock(uint32_t addr) } +void SerialFlashChip::eraseSector(uint32_t addr) +{ + uint8_t f = flags; + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0x06); // write enable command + CSRELEASE(); + delayMicroseconds(1); + CSASSERT(); + if (f & FLAG_32BIT_ADDR) { + SPIPORT.transfer(0x20); + SPIPORT.transfer16(addr >> 16); + SPIPORT.transfer16(addr); + } else { + SPIPORT.transfer16(0x2000 | ((addr >> 16) & 255)); + SPIPORT.transfer16(addr); + } + CSRELEASE(); + SPIPORT.endTransaction(); + busy = 2; +} + + bool SerialFlashChip::ready() { uint32_t status; @@ -391,6 +416,9 @@ bool SerialFlashChip::begin(uint8_t pin) // Micron requires busy checks with a different command f |= FLAG_STATUS_CMD70; // TODO: all or just multi-die chips? } + if (id[0] == ID0_WINBOND) { + f |= FLAG_SECTOR_ERASE; + } flags = f; readID(id); return true; @@ -478,6 +506,13 @@ uint32_t SerialFlashChip::blockSize() return 65536; } +uint32_t SerialFlashChip::eraseSectorSize() +{ + if (flags & FLAG_SECTOR_ERASE) return 4096; + // everything else seems to have 64K sectors + return blockSize(); +} + diff --git a/SerialFlashDirectory.cpp b/SerialFlashDirectory.cpp index d97d971..2d567b5 100644 --- a/SerialFlashDirectory.cpp +++ b/SerialFlashDirectory.cpp @@ -330,6 +330,14 @@ bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t ali return true; } +bool SerialFlashChip::createErasable(const char *filename, uint32_t length) { + uint32_t filesize = SerialFlash.eraseSectorSize(); + while (length > filesize) { + filesize = filesize * 2; + } + return create(filename, length, filesize); +} + bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize) { uint32_t maxfiles, index, straddr; @@ -381,13 +389,19 @@ bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesi void SerialFlashFile::erase() { - uint32_t i, blocksize; - - blocksize = SerialFlash.blockSize(); - if (address & (blocksize - 1)) return; // must begin on a block boundary - if (length & (blocksize - 1)) return; // must be exact number of blocks - for (i=0; i < length; i += blocksize) { - SerialFlash.eraseBlock(address + i); + uint32_t i, blockSize, sectorSize; + + blockSize = SerialFlash.blockSize(); + sectorSize = SerialFlash.eraseSectorSize(); + + if (address & (sectorSize - 1)) return; // must begin on a block boundary + if (length & (sectorSize - 1)) return; // must be exact number of blocks + for (i=0; i < length; i += sectorSize) { + if (sectorSize < blockSize) { + SerialFlash.eraseSector(address + i); + } else { + SerialFlash.eraseBlock(address + i); + } } }