Skip to content
22 changes: 21 additions & 1 deletion docs/pages/SPIFlash/writeAdvanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

.. _noteOnErrorCheck:

Advanced use ``errorCheck`` ``HIGHSPEED``
Advanced use ``errorCheck`` ``HIGHSPEED`` ``ERASE_ASYNC``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-----------
Expand Down Expand Up @@ -78,3 +78,23 @@ Then, if ``#define HIGHSPEED`` is uncommented in `SPIFlash.h <https://github.com
Please note that using a combination of the methods listed in :ref:`High speed mode <noteOnHighSpeed>` and :ref:`Error checking <noteOnErrorCheck>` will result in the highest possible write speed from the library. However, this will result in the highest probability of write errors / data corruption as well.

``**WARNING**``

Asynchronous erase mode
^^^^^^^^^^^^^^^^^^^^^^^^

Normally, the library waits for erase transactions to signal that they are complete before proceeding with execution. However, these instructions can take excessive amounts of time (as much as 2 seconds for the 64K block erase) which may not be permissible for real-time applications.

If ``#define ERASE_ASYNC`` is uncommented in `SPIFlash.h`, the library will not wait for erases to be finished before continuing with execution. This means that if an erase fails, it is harder to trace the issue; however, ``suspendProg()`` can then be called to suspend the erase and allow a write to begin, then ``resumeProg()`` can be called after the write is complete to allow the erase to continue.

This functionality is subject to the following caveats:

* Currently, only suspending during erase is supported; writes are always synchronous. Asynchronous writes are supported by the specification, but are not yet implemented.

* There is at best no effect to the time required for the erase and subsequent write; the time required for the erase is simply split into smaller segments.

* It is not permitted to erase another sector while a previous erase is suspended.

* It is not permitted to write to a sector that is in the process of being erased.

* It is not permitted to suspend a full-chip erase.

62 changes: 62 additions & 0 deletions examples/FlashAsync/FlashAsync.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| FlashAsyc.ino |
| SPIMemory library |
| v 3.5.0 |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| LithosphereRocketry |
| 21.12.2023 |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| This program shows the method of reading a string from the console and saving it to flash memory |
| |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
*/
#include<SPIMemory.h>

#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif

#if defined (SIMBLEE)
#define BAUD_RATE 250000
#else
#define BAUD_RATE 115200
#endif

uint8_t someData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus
SPIFlash flash;

void setup() {
Serial.begin(BAUD_RATE);
#if defined (ARDUINO_SAMD_ZERO) || (__AVR_ATmega32U4__)
while (!Serial) ; // Wait for Serial monitor to open
#endif

flash.begin();

// Erase the block we will be writing to
flash.eraseBlock64K(0);

// Start erasing the next block
flash.eraseBlock64K(0x10000);
for(int i = 0; i < 10; i++) {
// Periodically while the erase is happening, pause it and write some data
// to the first block
flash.suspendProg();
// We can only read or write while suspended, no erasing
flash.writeByteArray(i*100, someData, 10);
flash.resumeProg();
delay(10);
}

// Clean up the block we wrote to
flash.eraseBlock64K(0);
}

void loop() {

}
39 changes: 24 additions & 15 deletions src/SPIFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,11 +1304,13 @@ bool SPIFlash::eraseSector(uint32_t _addr)
_beginSPI(kb4Erase.opcode); // The address is transferred as a part of this function
_endSPI();

if (!_notBusy(kb4Erase.time)) {
return false; // Datasheet says erasing a sector takes 400ms max
}
// _writeDisable();
#ifdef RUNDIAGNOSTIC
#ifndef ERASE_ASYNC
if(!_notBusy(kb4Erase.time)) {
return false; //Datasheet says erasing a sector takes 400ms max
}
#endif
//_writeDisable();
#ifdef RUNDIAGNOSTIC
_spifuncruntime = micros() - _spifuncruntime;
#endif

Expand All @@ -1331,13 +1333,14 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr)
}
_beginSPI(kb32Erase.opcode);
_endSPI();

if (!_notBusy(kb32Erase.time)) {
return false; // Datasheet says erasing a sector takes 400ms max
}
#ifndef ERASE_ASYNC
if (!_notBusy(kb32Erase.time)) {
return false; // Datasheet says erasing a sector takes 400ms max
}
#endif
_writeDisable();
#ifdef RUNDIAGNOSTIC
_spifuncruntime = micros() - _spifuncruntime;
_spifuncruntime = micros() - _spifuncruntime;
#endif

return true;
Expand All @@ -1361,9 +1364,12 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr)
_beginSPI(kb64Erase.opcode);
_endSPI();

if (!_notBusy(kb64Erase.time)) {
return false; // Datasheet says erasing a sector takes 400ms max
}

#ifndef ERASE_ASYNC
if(!_notBusy(kb64Erase.time)) {
return false; //Datasheet says erasing a sector takes 400ms max
}
#endif
#ifdef RUNDIAGNOSTIC
_spifuncruntime = micros() - _spifuncruntime;
#endif
Expand Down Expand Up @@ -1403,8 +1409,11 @@ bool SPIFlash::suspendProg(void)
#ifdef RUNDIAGNOSTIC
_spifuncruntime = micros();
#endif
if (_isChipPoweredDown() || _notBusy()) {
return false;
// Technically I think it's possible for suspend to fail while the chip is
// busy - e.g. during chip erase - but there's literally no point using suspend
// while the chip isn't busy so I don't think there's any reason for this check
if(_isChipPoweredDown()/* || _notBusy()*/) {
return false;
}

if (!_noSuspend()) {
Expand Down
9 changes: 9 additions & 0 deletions src/SPIMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@
// #define HIGHSPEED //
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Uncomment the code below to enable asynchronous erases using //
// suspendProg() / resumeProg() //
// //
// Must ensure that no erases occur while an erase is suspended //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// #define ERASE_ASYNC //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Uncomment the code below to disable overflow and force data //
// to only be written to the last address of the flash memory //
Expand Down