Compare commits

...

10 Commits

Author SHA1 Message Date
Felix Rusu 4c49258506 add blockErase4K() & read example 2021-09-15 12:55:00 -04:00
Felix Rusu c733c385d4 fix travis-ci links 2021-08-31 15:24:56 -04:00
Felix Rusu deed665e02 add found() and regionIsEmpty() 2021-07-20 14:10:28 -04:00
Felix Rusu e80a582218
Merge pull request #28 from JasonC0x0D/update_comment
Updated Comments about sleep()
2021-06-08 08:14:34 -04:00
JasonC0x0D ac7bc9a993
Updated Comments about sleep()
Clarification that after using sleep(), wake() must be the first function used to communicate with the flash chip.
If this isn't the case, a noisy MISO line can cause the code to hang in the while(busy) loop in the command() function.
This is a "fix" for "gitHub bug #26".
2021-06-07 20:07:28 -07:00
Felix Rusu 9031099cdf Update SPIFlash.cpp
Closes #26, Closes #27
2021-06-07 16:44:39 -04:00
Felix Rusu 6423a585c4 Update .travis.yml 2021-04-29 19:36:15 -04:00
Felix Rusu 23227209f9 Update README.md 2021-04-29 19:33:51 -04:00
Felix Rusu 279282b51f Update examples 2021-01-19 12:48:53 -05:00
Felix Rusu f3f394b7f9 Update SPIFlash_Detect.ino 2021-01-14 15:10:42 -05:00
6 changed files with 110 additions and 33 deletions

View File

@ -1,6 +1,6 @@
language: python language: python
python: python:
- "2.7" - "3.6"
# Cache PlatformIO packages using Travis CI container-based infrastructure # Cache PlatformIO packages using Travis CI container-based infrastructure
sudo: false sudo: false

View File

@ -1,6 +1,6 @@
SPIFlash SPIFlash
======== ========
[![Build Status](https://travis-ci.org/LowPowerLab/SPIFlash.svg?branch=master)](https://travis-ci.org/LowPowerLab/SPIFlash) [![Build Status](https://app.travis-ci.com/LowPowerLab/SPIFlash.svg?branch=master)](https://app.travis-ci.com/LowPowerLab/SPIFlash)
[![GitHub release](https://img.shields.io/github/release/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash) [![GitHub release](https://img.shields.io/github/release/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash)
[![GitHub issues](https://img.shields.io/github/issues/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash/issues) [![GitHub issues](https://img.shields.io/github/issues/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash/pulls) [![GitHub pull requests](https://img.shields.io/github/issues-pr/LowPowerLab/SPIFlash.svg)](https://github.com/LowPowerLab/SPIFlash/pulls)

View File

@ -38,8 +38,13 @@ uint8_t SPIFlash::UNIQUEID[8];
/// IMPORTANT: NAND FLASH memory requires erase before write, because /// IMPORTANT: NAND FLASH memory requires erase before write, because
/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
/// See http://en.wikipedia.org/wiki/Flash_memory /// See http://en.wikipedia.org/wiki/Flash_memory
/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command /// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command
/// IMPORTANT: When flash chip is powered down, aka sleeping, the only command it will respond to is
/// Release Power-down / Device ID (ABh), per section 8.2.19 of the W25X40CL datasheet.
/// This means after using the sleep() function of this library, wake() must be the first
/// function called. If other commands are used, the flash chip will ignore the commands.
/// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response /// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response
/// get this from the datasheet of your flash chip /// get this from the datasheet of your flash chip
@ -180,11 +185,14 @@ void SPIFlash::command(uint8_t cmd, boolean isWrite){
command(SPIFLASH_WRITEENABLE); // Write Enable command(SPIFLASH_WRITEENABLE); // Write Enable
unselect(); unselect();
} }
//wait for any write/erase to complete // wait for any write/erase to complete
// a time limit cannot really be added here without it being a very large safe limit // a time limit cannot really be added here without it being a very large safe limit
// that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations
// a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the //
// open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present // Note: If the MISO line is high, busy() will return true.
// This can be a problem and cause the code to hang when there is noise/static on MISO data line when:
// 1) There is no flash chip connected
// 2) The flash chip connected is powered down, aka sleeping.
if (cmd != SPIFLASH_WAKE) while(busy()); if (cmd != SPIFLASH_WAKE) while(busy());
select(); select();
SPI.transfer(cmd); SPI.transfer(cmd);
@ -292,11 +300,46 @@ void SPIFlash::blockErase64K(uint32_t addr) {
unselect(); unselect();
} }
/// found() - checks there is a FLASH chip by checking the deviceID repeatedly - should be a consistent value
uint8_t SPIFlash::found() {
uint16_t deviceID=0;
wakeup(); //if sleep() was previously called, wakeup() is required or it's non responsive
for (uint8_t i=0;i<10;i++) {
uint16_t idNow = readDeviceId();
if (idNow==0 || idNow==0xffff || (i>0 && idNow != deviceID)) {
deviceID=0;
break;
}
deviceID=idNow;
}
if (deviceID==0) { //NO FLASH CHIP FOUND, ABORTING
return false;
}
return true;
}
///regionIsEmpty() - check a random flashmem byte array is all clear and can be written to (ie. it's all 0xff)
uint8_t SPIFlash::regionIsEmpty(uint32_t startAddress, uint8_t length) {
uint8_t flashBuf[length];
readBytes(startAddress, flashBuf, length);
for (uint8_t i=0;i<length;i++) if (flashBuf[i]!=0xff) return false;
return true;
}
/// Put flash memory chip into power down mode
/// WARNING: after this command, only the WAKEUP and DEVICE_ID commands are recognized
/// hence a wakeup() command should be invoked first before further operations
/// If a MCU soft restart is possible with flash chip left in sleep(), then a wakeup() command
/// should always be invoked before any other commands to ensure the flash chip was not left in sleep
void SPIFlash::sleep() { void SPIFlash::sleep() {
command(SPIFLASH_SLEEP); command(SPIFLASH_SLEEP);
unselect(); unselect();
} }
/// Wake flash memory from power down mode
/// NOTE: this command is required after a sleep() command is used, or no other commands will be recognized
/// If a MCU soft restart is possible with flash chip left in sleep(), then a wakeup() command
/// should always be invoked before any other commands to ensure the flash chip was not left in sleep
void SPIFlash::wakeup() { void SPIFlash::wakeup() {
command(SPIFLASH_WAKE); command(SPIFLASH_WAKE);
unselect(); unselect();

View File

@ -105,7 +105,9 @@ public:
void blockErase64K(uint32_t addr); void blockErase64K(uint32_t addr);
uint16_t readDeviceId(); uint16_t readDeviceId();
uint8_t* readUniqueId(); uint8_t* readUniqueId();
uint8_t found();
uint8_t regionIsEmpty(uint32_t startAddress, uint8_t length);
void sleep(); void sleep();
void wakeup(); void wakeup();
void end(); void end();

View File

@ -3,27 +3,30 @@
#include <SPIFlash.h> //https://github.com/lowpowerlab/spiflash #include <SPIFlash.h> //https://github.com/lowpowerlab/spiflash
#include <SPI.h> #include <SPI.h>
#define SERIAL_ENABLE #define SERIAL_BAUD 115200
#define BLINK_FAST_DELAY 100 #define BLINK_FAST_DELAY 50
#define BLINK_SLOW_DELAY 500 #define BLINK_SLOW_DELAY 1000
SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF40 for 16mbit windbond chip SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF40 for 16mbit windbond chip
int LEDTIME = 500; int LEDTIME = 500;
// the setup routine runs once when you press reset: // the setup routine runs once when you press reset:
void setup() { void setup() {
#ifdef SERIAL_ENABLE #ifdef SERIAL_BAUD
Serial.begin(115200); Serial.begin(SERIAL_BAUD);
delay(4000); //wait a bit until SerialMonitor can be opened while (!Serial) delay(100); //wait until Serial/monitor is opened
#endif #endif
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
//ensure the radio module CS pin is pulled HIGH or it might interfere!
pinMode(SS, OUTPUT); digitalWrite(SS, HIGH);
//ensure FLASH chip is not sleep mode (unresponsive)
flash.wakeup();
if (flash.initialize()) { if (flash.initialize()) {
Serial.println("SPI Flash Init OK!"); Serial.println("SPI Flash Init OK!");
LEDTIME = BLINK_SLOW_DELAY; LEDTIME = BLINK_SLOW_DELAY;
} } else {
else
{
Serial.println("SPI Flash Init FAIL! (is chip soldered?)"); Serial.println("SPI Flash Init FAIL! (is chip soldered?)");
LEDTIME = BLINK_FAST_DELAY; LEDTIME = BLINK_FAST_DELAY;
} }

View File

@ -2,14 +2,17 @@
// This sketch is an example of using the SPIFlash library with a Moteino // This sketch is an example of using the SPIFlash library with a Moteino
// that has an onboard SPI Flash chip. This sketch listens to a few serial commands // that has an onboard SPI Flash chip. This sketch listens to a few serial commands
// Hence type the following commands to interact with the SPI flash memory array: // Hence type the following commands to interact with the SPI flash memory array:
// - 'd' dumps the first 256bytes of the flash chip to screen //'c' - read flash chip's deviceID 10 times to ensure chip is present
// - 'e' erases the entire memory chip //'d' - dump first 256 bytes on the chip
// - 'i' print manufacturer/device ID //'e' - erase entire flash chip
// - [0-9] writes a random byte to addresses [0-9] (either 0xAA or 0xBB) //'E' - erase last 4K block in flash chip
//'D' - dump first 256 bytes in the last 4K block
//'i' - read deviceID
//'0'-'9' - write 0xaa/0xbb bytes at addresses 0..9, 520192..520447
// Get the SPIFlash library from here: https://github.com/LowPowerLab/SPIFlash // Get the SPIFlash library from here: https://github.com/LowPowerLab/SPIFlash
// Note: if other SPI devices are present, ensure their CS pins are pulled up or set HIGH // Note: if other SPI devices are present, ensure their CS pins are pulled up or set HIGH
// ********************************************************************************** // **********************************************************************************
// (C) 2020 Felix Rusu, LowPowerLab.com // (C) 2021 Felix Rusu, LowPowerLab.com
// Library and code by Felix Rusu - felix@lowpowerlab.com // Library and code by Felix Rusu - felix@lowpowerlab.com
// ********************************************************************************** // **********************************************************************************
// License // License
@ -53,9 +56,17 @@ uint16_t expectedDeviceID=0xEF30;
SPIFlash flash(SS_FLASHMEM, expectedDeviceID); SPIFlash flash(SS_FLASHMEM, expectedDeviceID);
void setup(){ void setup(){
#ifdef SERIAL_BAUD
Serial.begin(SERIAL_BAUD); Serial.begin(SERIAL_BAUD);
while (!Serial) delay(100); //wait until Serial/monitor is opened
#endif
pinMode(LED_BUILTIN, OUTPUT);
Serial.print("Start..."); Serial.print("Start...");
//ensure the radio module CS pin is pulled HIGH or it might interfere!
pinMode(SS, OUTPUT); digitalWrite(SS, HIGH);
if (flash.initialize()) if (flash.initialize())
{ {
Serial.println("Init OK!"); Serial.println("Init OK!");
@ -73,7 +84,10 @@ void setup(){
Serial.println("'c' - read flash chip's deviceID 10 times to ensure chip is present"); Serial.println("'c' - read flash chip's deviceID 10 times to ensure chip is present");
Serial.println("'d' - dump first 256 bytes on the chip"); Serial.println("'d' - dump first 256 bytes on the chip");
Serial.println("'e' - erase entire flash chip"); Serial.println("'e' - erase entire flash chip");
Serial.println("'E' - erase last 4K block in flash chip");
Serial.println("'D' - dump first 256 bytes in the last 4K block");
Serial.println("'i' - read deviceID"); Serial.println("'i' - read deviceID");
Serial.println("'0'-'9' - write 0xaa/0xbb bytes at addresses 0..9, 520192..520447");
Serial.println("************************\n"); Serial.println("************************\n");
delay(1000); delay(1000);
} }
@ -83,16 +97,26 @@ void loop(){
// ie: display first 256 bytes in FLASH, erase chip, write bytes at first 10 positions, etc // ie: display first 256 bytes in FLASH, erase chip, write bytes at first 10 positions, etc
if (Serial.available() > 0) { if (Serial.available() > 0) {
input = Serial.read(); input = Serial.read();
if (input == 'd') //d=dump flash area if (input == 'd') { //d=dump flash area
{ Serial.println("Flash content (256 bytes, starting address 0):");
Serial.println("Flash content:");
int counter = 0; int counter = 0;
while(counter<=256){ while(counter<256){
Serial.print(flash.readByte(counter++), HEX); Serial.print(flash.readByte(counter), HEX);
Serial.print('.'); counter++;
if (counter%16 == 0) Serial.println(); else Serial.print('.');
}
Serial.println();
}
else if (input == 'D') { //d=dump flash area @ last 4K block
Serial.println("Flash content (256bytes, starting address 520192):");
uint32_t counter = 520192;
while(counter<520192+256){
Serial.print(flash.readByte(counter), HEX);
counter++;
if (counter%16 == 0) Serial.println(); else Serial.print('.');
} }
Serial.println(); Serial.println();
} }
else if (input == 'c') { else if (input == 'c') {
@ -118,6 +142,13 @@ void loop(){
while(flash.busy()); while(flash.busy());
Serial.println("DONE"); Serial.println("DONE");
} }
else if (input == 'E')
{
Serial.print("Erasing last 4K block @520192 ... ");
flash.blockErase4K(520192);
while(flash.busy());
Serial.println("DONE");
}
else if (input == 'i') else if (input == 'i')
{ {
Serial.print("DeviceID: "); Serial.print("DeviceID: ");
@ -127,21 +158,19 @@ void loop(){
{ {
Serial.print("\nWriteByte("); Serial.print(input); Serial.print(")"); Serial.print("\nWriteByte("); Serial.print(input); Serial.print(")");
flash.writeByte(input-48, millis()%2 ? 0xaa : 0xbb); flash.writeByte(input-48, millis()%2 ? 0xaa : 0xbb);
flash.writeByte(input-48+520192, millis()%2 ? 0xaa : 0xbb);
} }
} }
// Periodically blink the onboard LED while listening for serial commands // Periodically blink the onboard LED while listening for serial commands
if ((int)(millis()/500) > lastPeriod) if ((int)(millis()/500) > lastPeriod) {
{
lastPeriod++; lastPeriod++;
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, lastPeriod%2); digitalWrite(LED_BUILTIN, lastPeriod%2);
} }
} }
void Blink(int DELAY_MS, byte loops) void Blink(int DELAY_MS, byte loops)
{ {
pinMode(LED_BUILTIN, OUTPUT);
while (loops--) while (loops--)
{ {
digitalWrite(LED_BUILTIN,HIGH); digitalWrite(LED_BUILTIN,HIGH);