adafruit / Adafruit_SPIFlash

Arduino library for external (Q)SPI flash device
MIT License
151 stars 83 forks source link

erasePage() does not work #175

Closed jeffreykneumann closed 1 week ago

jeffreykneumann commented 4 weeks ago

Operating System

Others

IDE version

Arduino IDE 2.3.2

Board

Adafruit ItsyBitsy M4

BSP version

1.7.13

SPIFlash Library version

4.3.4

Sketch as attached file if not stock example

test_flash.txt

What happened ?

From what I can tell, erasePage() does not work as expected. When readBuffer() or writeBuffer() is called after erasePage() the program will hang. I've traced the cause of this to waitUntilReady(). I've attached a demonstration function that shows readStatus() is different depending on whether eraseSector() or erasePage() is called beforehand.

Does anyone have any suggestions on how to prevent this hang? I could always use eraseSector() as a backup plan but it has an advertised erase time of 45ms compared to the advertised 0.6ms of erasePage().

How to reproduce ?

Here is a demonstration sketch I made to outline the issue:

#include <Adafruit_SPIFlash.h>
// #include <Adafruit_TinyUSB.h>

// Create the flash instance (using the default pins for the ItsyBitsy M4)
Adafruit_FlashTransport_QSPI flashTransport;
Adafruit_SPIFlash flash(&flashTransport);

const uint32_t startPage = 0; // Start address in flash memory
const uint32_t dataLength = 16;       // Length of the data buffer

void setup() {
  // Initialize Serial for output
  Serial.begin(115200);
  while (!Serial) delay(10); // Wait for the serial connection
  Serial.println("\nStarting");
  // Initialize the flash library
  if (!flash.begin()) {
    Serial.println("Error, failed to initialize flash memory!");
    while (1);
  }

  // Read the data back from flash memory
  uint8_t readBuffer[dataLength];
  memset(readBuffer, 0, dataLength);  // Clear the buffer before reading
  if (!flash.readBuffer(startPage, readBuffer, dataLength)) {
    Serial.println("Error, failed to read from flash memory!");
    while (1);
  }

  Serial.println("Flash beforehand");
  for(uint8_t i = 0; i < dataLength; i++){
    Serial.print(" 0x");
    Serial.print(readBuffer[i],HEX);
  }
  Serial.println();

  // Erase the first sector (4KB) of flash memory to prepare it for writing
  if (!flash.eraseSector(startPage)) {
    Serial.println("Error, failed to erase flash memory!");
    while (1);
  }
  Serial.println((String)"Status after eraseSection(): "+flash.readStatus());

  // Read the data back from flash memory after eraseSector()
  memset(readBuffer, 0, dataLength);  // Clear the buffer before reading
  if (!flash.readBuffer(startPage, readBuffer, dataLength)) {
    Serial.println("Error, failed to read from flash memory!");
    while (1);
  }
  Serial.println("Page after eraseSector()");
  for(uint8_t i = 0; i < dataLength; i++){
    Serial.print(" 0x");
    Serial.print(readBuffer[i],HEX);
  }
  Serial.println();

  // Write date to page
  uint8_t writeBuffer[dataLength];
  memset(writeBuffer, 0x11, dataLength);
  if (!flash.writeBuffer(startPage*256, writeBuffer, dataLength)) {
    Serial.println("Error, failed to write to flash memory!");
    while (1);
  }

  // Read the data back from flash memory after eraseSector() and write
  memset(readBuffer, 0, dataLength);  // Clear the buffer before reading
  if (!flash.readBuffer(startPage, readBuffer, dataLength)) {
    Serial.println("Error, failed to read from flash memory!");
    while (1);
  }
  Serial.println("Page after write after eraseSector()");
  for(uint8_t i = 0; i < dataLength; i++){
    Serial.print(" 0x");
    Serial.print(readBuffer[i],HEX);
  }
  Serial.println();

  // Erase the first page (256B) of flash memory to prepare it for writing
  if (!flash.erasePage(startPage)) {
    Serial.println("Error, failed to erase flash memory!");
    while (1);
  }
  Serial.println((String)"Status after erasePage(): "+flash.readStatus());

  // Read the data back from flash memory after erasePage()
  memset(readBuffer, 0, dataLength);  // Clear the buffer before reading
  if (!flash.readBuffer(startPage, readBuffer, dataLength)) {
    Serial.println("Error, failed to read from flash memory!");
    while (1);
  }
  Serial.println("Page after write after erasePage()");
  for(uint8_t i = 0; i < dataLength; i++){
    Serial.print(" 0x");
    Serial.print(readBuffer[i],HEX);
  }
  Serial.println();
  Serial.println("End of script.");
}

void loop() {
  // Do nothing in loop
}

Its output is:

Starting
Flash beforehand
 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11
Status after eraseSection(): 3
Page after eraseSector()
 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
Page after write after eraseSector()
 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11
Status after erasePage(): 2

Its output should be:

Starting
Flash beforehand
 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11
Status after eraseSection(): 3
Page after eraseSector()
 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
Page after write after eraseSector()
 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11
Status after erasePage(): 3
Page after erasePage()
 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
Page after write after erasePage()
 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11
End of script.

Debug Log as attached txt file

No response

Screenshots

No response

jeffreykneumann commented 3 weeks ago

After a closer look into the datasheet for my QSPI flash chip (GD25Q16C), it appears this chip does not support page erase. Does that mean that the erasePage() function does not work with all hardware?

hathach commented 1 week ago

After a closer look into the datasheet for my QSPI flash chip (GD25Q16C), it appears this chip does not support page erase. Does that mean that the erasePage() function does not work with all hardware?

I think you anwser yourself, the chip does not support page erase, you should use sector erase instead.