diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6065e76..14f8c13 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,10 @@ Hey there! Thanks for using the SPIFlash library for Arduino. +### Please note that starting 01.03.2018 any issue raised here MUST be submitted according to this template or it will be flagged with 'Not enough information'. No action will be taken till all the prerequisite information is provided. If no information is provided for over a month, the issue will be closed. **Note: For support questions, please use the [Arduino Forums](http://forum.arduino.cc/index.php?topic=324009.0). This repository's issues are reserved for feature requests and bug reports.** +# Issue details + **I'm submitting a ...** - [ ] bug report - [ ] feature request @@ -27,8 +30,21 @@ When opening an issue please include the following details: -------------------------- ###### Bug reports only - -- [ ] If this is a bug report - Provide a **minimal code snippet** example that reproduces the bug. Please make sure you wrap any code in the proper code blocks like below +- If this is a bug report - + +- [ ] Make sure you have run FlashDiagnostics.ino with ``` #define RUNDIAGNOSTICS ``` uncommented in SPIFlash.h. **List any error codes** that pop up in your Serial output when you run FlashDiagnostics.ino.here: + Error codes + ------------ + - + - + - + - + - +- [ ] If you have a problem with a particular function, call the flash.error() function (after you have made sure you have started up your Serial port with a ``` Serial.begin(BAUD) ``` ). Provide details of the function, the data given to/ expected from the function and the error code here: (**Please repeat this for every function you have an error with***) + Function - + Data - + Error code - +- [ ] Provide a **minimal code snippet** example that reproduces the bug. Please make sure you wrap any code in the proper code blocks like below ``` ```CODE HERE``` ``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index eb18044..7e59ed7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,8 @@ +Hey there! Thanks for using the SPIFlash library for Arduino. +### Please note that starting 01.03.2018 any Pull request raised here MUST be submitted according to this template or it will be flagged with 'Not enough information'. No action will be taken till all the prerequisite information is provided. If no information is provided for over a month, the pull request will be closed. + +# Pull request details + * **Please check if the PR fulfills these requirements** - [ ] The commit message/s explain/s all the changes clearly - [ ] Tests for the changes have been added (for bug fixes / features) @@ -5,7 +10,10 @@ * **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) - +- [ ] Bug fix +- [ ] Added feature +- [ ] Documentation update +- [ ] Other - Please explain here: * **What is the current behavior?** (You can also link to an open issue here) diff --git a/.travis.yml b/.travis.yml index 6790cc7..381a13e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,18 +4,18 @@ before_install: - source <(curl -SLs https://raw.githubusercontent.com/Marzogh/Travis-CI/master/install.sh) script: - build_main_platforms - #- build_platform trinket #- build_platform rtl8195a #- build_platform uno #- build_platform due #- build_platform zero #- build_platform esp8266 #- build_platform leonardo + #- build_platform mega #- build_platform rtl8195a #- build_platform simblee - #- build_platform mega - #- build_platform fio - #- build_platform micro + #- build_platform cplayClassic + #- build_platform cplayExpress + #- build_platform trinket notifications: email: on_success: change diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 index f058204..8083807 --- a/README.md +++ b/README.md @@ -1,28 +1,52 @@ # SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=stable)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash) [![GitHub release](https://img.shields.io/github/release/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) -[![GitHub commits](https://img.shields.io/github/commits-since/Marzogh/SPIFlash/v3.0.0.svg)](https://github.com/Marzogh/SPIFlash/compare/v3.0.0...development) +[![GitHub commits](https://img.shields.io/github/commits-since/Marzogh/SPIFlash/v3.0.0.svg)](https://github.com/Marzogh/SPIFlash/compare/v3.0.1...stable) [![GitHub issues](https://img.shields.io/github/issues/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash/issues) [![GitHub pull requests](https://img.shields.io/github/issues-pr/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash/pulls) [![license](https://img.shields.io/github/license/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash/blob/master/LICENSE) -### Arduino library for Flash Memory Chips (SPI based only) - Download the latest stable release (v3.0.0) from here. Please report any bugs in issues. +## Arduino library for Flash Memory Chips (SPI based only) + Download the latest stable release from [here](https://github.com/Marzogh/SPIFlash/releases/latest). Please report any bugs in [issues](https://github.com/Marzogh/SPIFlash/issues/new). This Arduino library is for use with flash memory chips that communicate using the SPI protocol. In its current form it supports identifying the flash chip and its various features; automatic address allocation and management; writing and reading a number of different types of data, ranging from 8-bit to 32-bit (signed and unsigned) values, floats, Strings, arrays of bytes/chars and structs to and from various locations; sector, block and chip erase; and powering down for low power operation. +
+ +>### Important note from developer +>The term 'SPI Flash' is a fairly common way to refer to Flash memory chips that communicate over the SPI protocol and there are a number of libraries that are named SPIFlash. When I first started work on this library in 2014, it was mostly as an exercise to improve my embedded systems programming skills. When I asked for it to be included in the list of Arduino libraries, I did not really expect it to go very far or get very popular. But, before I knew it, I was releasing new versions every other month and I found the number of users got way bigger than I imagined it would. The amount of traffic the GitHub repository gets still surprises me. +> +>A few months ago, @LowPowerLab raised an issue ([#83](https://github.com/Marzogh/SPIFlash/issues/83)) about the problems the name of this library was causing the users of his library - also called SPIFlash. The fact that this library is in the Arduino Library manager meant that his users were being asked to upgrade their version of SPIFlash when the libraries were actually different. I can understand how much of an annoyance this can be for a user. +> +>@LowPowerLab's version of SPIFlash has been around for longer than this one and his library is a major part of his commercial line of development boards. Since I am a hobbyist developer (I'm a full-time geneticist & a part-time dabbler in ecology - if you're curious) and this library is not a commercial product with branding and trademarks to worry about, the least I can do is change the name of this library so it stops being an annoyance to @LowPowerLab's customers. +>> On a side note, if you did not know already, @LowPowerLab makes and sells a fantastic line of Arduino compatible boards - the [Moteino](https://lowpowerlab.com/shop/) series - and has developed a fantastic IoT protocol to use with them to add smarts to your home. In January this year, I finally got around to getting my hands on some of his boards and have been playing around with them. They are fantastic! I'd strongly recommend you check them out - if you haven't already done so. +> +>I asked the Arduino developers if there was a way to migrate this library to a new name without breaking the upgrade path ([Issue #6904](https://github.com/arduino/Arduino/issues/6904)) and was told that it was not possible. The only way is to pull my version of SPIFlash from the library manager and ask for a renamed version to be included in the library manager after. +> +>So, this is what I have decided to do.: +>- This version - v3.1.0 - will be the last version to be released under the SPIFlash name. +>- Anyone downloading this version of the library will be able to read this notice in the ReadMe file. +>- Anyone using this version of the library will see a notice in their Serial output directing them to this notice in the ReadMe file. (this can be removed by commenting out the `#define PRINTNAMECHANGEALERT` in `SPIFlash.h`) +>- Version 3.2.0 will be released in a couple of months (in May most likely) under a new name - SPIMemory. +>- This version of SPIFlash will be removed from the library manager then and replaced with the new one. +> +>The only change will have to be made in end-user code will be to change the `#include SPIFlash.h` to `#include SPIMemory.h`. After the name change, rest assured that older versions will remain accessible and the development history of the library will be preserved. +> +>I apologise for any trouble this might cause you as the end user, but, given the facts, it is the only thing I can do to be fair to @LowPowerLab +> +>Thanks again for using `SPIFlash` and I hope you will continue to find it useful in whatever new name it will take on. -- For details of the Flash chips compatible with this library please refer to the list below. +
-#### Compatibility +### Compatibility -##### Arduino IDEs supported (actually tested with) +#### Arduino IDEs supported (actually tested with) - IDE v1.5.x - IDE v1.6.0-v1.6.5 - IDE v1.6.9-v1.6.12 - IDE v1.8.1-v1.8.5 -##### Boards +#### Boards -###### Completely supported +##### Completely supported - Arduino Uno - Arduino Leonardo - Arduino Due @@ -36,16 +60,16 @@ This Arduino library is for use with flash memory chips that communicate using t - Arduino Micro - Arduino Fio -###### In BETA +##### In BETA - ESP32 Boards (Tested on the Adafruit ESP32 Feather) The library is known to work with the ESP32 core as of the current commit 8ba91b9 on 07.11.2017. ```ESP32 support will remain in beta till the ESP32 core can be installed via the Arduino boards manager.``` NOTE: ESP32 boards usually have an SPIFlash already attached to their SS pin, so the user has to declare the ChipSelect pin being used when the constructor is declared - for example ``` SPIFlash flash(33); ``` -##### Flash memory compatibility +#### Flash memory compatibility -###### Completely supported (Actually tested with) +##### Completely supported (Actually tested with) - Winbond - W25Q16BV - W25Q64FV @@ -58,26 +82,26 @@ SPIFlash flash(33); - S25FL116K - S25FL127S -###### Should work with (Similar enough to the ones actually tested with) +##### Should work with (Similar enough to the ones actually tested with) - Winbond (All SPI Flash chips) - Microchip (SST25 & SST26 series) - Cypress/Spansion (S25FL series) -#### Installation +### Installation -##### Option 1 +#### Option 1 - Open the Arduino IDE. - Go to Sketch > Include Library > Manage libraries. - Search for SPIFlash. - Install the latest version. -##### Option 2 +#### Option 2 - Click on the 'Clone or download' button above the list of files on this page . - Select Download ZIP. A .zip file will download to your computer. - Unzip the archive and rename resulting folder to 'SPIFlash' - Move the folder to your libraries folder (~/sketches/libraries) -#### Usage +### Usage - The library is called by declaring the```SPIFlash flash(csPin*)``` constructor where 'flash' can be replaced by a user constructor of choice and 'csPin' is the Chip Select pin for the flash module. @@ -85,40 +109,39 @@ SPIFlash flash(33); - Every version of the library >= v3.0.0 supports the ability to use any of multiple SPI interfaces (if your micro-controller supports them). Switching to use another SPI interface is done by calling ```SPIFlash flash(csPin, &SPI1);``` (or &SPI2 and so on), instead of ```SPIFlash flash(csPin)```. * NOTE: This is currently only supported on the SAMD and STM32 architectures. -- Make sure to include ```#include``` when you include ```#include```. - Also make sure to include ```flash.begin(CHIPSIZE*)``` in ```void setup()```. This enables the library to detect the type of flash chip installed and load the right parameters. * Optional -###### Notes on Address overflow and Error checking +##### Notes on Address overflow and Error checking - The library has Address overflow enabled by default - i.e. if the last address read/written from/to, in any function, is 0xFFFFF then, the next address read/written from/to is 0x00000. This can be disabled by uncommenting ```#define DISABLEOVERFLOW``` in SPIFlash.h. (Address overflow only works for Read / Write functions. Erase functions erase only a set number of blocks/sectors irrespective of overflow.) - All write functions have Error checking turned on by default - i.e. every byte written to the flash memory will be checked against the data stored on the Arduino. Users who require greater write speeds can disable this function by setting an optional last 'errorCheck' argument in any write function to NOERRCHK - For eg. call the function ```writeByte(address, *data_buffer, NOERRCHK)``` instead of ```writeByte(address, *data_buffer)```. The library enables the following functions:
-##### Non-I/O commands +#### Non-Read/Write functions
-###### begin(_chipsize*) -Must be called at the start in setup(). This function detects the type of chip being used and sets parameters accordingly. An optional CHIPSIZE parameter can be declared as an argument with this function. For supported CHIPSIZE values, please refer to the appropriate [wiki section](https://github.com/Marzogh/SPIFlash/wiki/begin()) or look at defines.h . +###### `begin(_chipsize*)` +Must be called at the start in setup(). This function detects the type of chip being used and sets parameters accordingly. An optional CHIPSIZE parameter can be declared as an argument with this function. For supported CHIPSIZE values, please refer to the appropriate [wiki section](https://github.com/Marzogh/SPIFlash/wiki/Chipsize) or look at defines.h . -###### setClock(clockSpeed) +###### `setClock(clockSpeed)` Must be called straight after begin(). This function takes a 32-bit number as replacement for the default maximum clock speed (104MHz for Winbond NOR flash) thereby initiating future SPI transactions with the user-defined clock speed. Use with care. -###### error(_verbosity) +###### `error(_verbosity)` Returns the (8-bit) error code generated by the function called immediately before this is called. If the optional VERBOSE argument is used, a verbose troubleshooting report is printed to Serial. Refer to the [Error reporting](https://github.com/Marzogh/SPIFlash/wiki/Error-reporting) section the Wiki for further reference. -###### getMANID() +###### `getManID()` Returns the Manufacturer ID as a 16-bit value. -###### getJEDECID() +###### `getJEDECID()` Returns the JEDEC ID as a 32-bit value. -###### getUniqueID() +###### `getUniqueID()` Returns the Unique ID as a 64-bit value. -###### getAddress(sizeOfData) +###### `getAddress(sizeOfData)` Gets the next available address for use. Has two variants: * Takes the size of the data as an argument and returns a 32-bit address * Takes a three variables, the size of the data and two other variables to return a page number value & an offset into. @@ -133,7 +156,7 @@ size = sizeof(variable) can be used for all types of data but String objects. ###### getCapacity() Returns the capacity in bytes as a 32-bit value. -###### getmaxPage() +###### getMaxPage() Returns the maximum number of pages in the flash memory as a 32-bit value. ###### functionRunTime() @@ -258,6 +281,11 @@ Erases one 64KB block - 256 pages - containing the address to be erased. The blo ###### eraseChip() Erases entire chip. Use with care. + +###### eraseSection(address, sizeOfData) +Erases the specific number of blocks/sectors to fit data (size defined by the sizeOfData arguement) into. When a user requires a large and variable (between writes) amount of data to be written to the flash memory on the fly and to have the correct amount of space erased to fit the data, this function will automatically calculate and erase the right amount of space to fit the data. + +Please note that if the the amount of data being written is consistently the same size, the pre-existing 'flash.eraseSector()', 'flash.eraseBlock32K()' and 'flash.eraseBlock64K()' functions will operate a lot faster.
##### Suspend/Resume commands diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index 3a4be5d..4bae611 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -2,14 +2,14 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | FlashDiagnostic_functions.ino | | SPIFlash library | - | v 3.0.0 | + | v 3.1.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 17.11.2017 | + | 04.03.2018 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | + | uncomment #define RUNDIAGNOSTIC in SPIFlash.h in the library before compiling | | and loading this application onto your Arduino. | | | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| @@ -114,10 +114,6 @@ void getID() { b2 = (JEDEC >> 8); //b3 = (JEDEC >> 0); - - printLine(); - //---------------------------------------------------------------------------------------------// - clearprintBuffer(&printBuffer[1]); #if defined (ARDUINO_ARCH_ESP32) sprintf(printBuffer, "\t\t\tJEDEC ID: %04xh", JEDEC); @@ -377,6 +373,10 @@ void structTest() { int32_t s3; bool s4; uint8_t s5; + struct structOfStruct { + uint8_t b1; + float f2; + } structofstruct; }; Test _d; Test _data; @@ -386,6 +386,8 @@ void structTest() { _d.s3 = 880932; _d.s4 = true; _d.s5 = 5; + _d.structofstruct.b1 = 234; + _d.structofstruct.f2 = 6.28; uint32_t wTime = 0; uint32_t addr, rTime; @@ -402,7 +404,7 @@ void structTest() { Serial.print ("\t\t\tStruct: \t"); - if ((_d.s1 == _data.s1) && (_d.s2 == _data.s2) && (_d.s3 == _data.s3) && (_d.s4 == _data.s4) && (_d.s5 == _data.s5)) { + if ((_d.s1 == _data.s1) && (_d.s2 == _data.s2) && (_d.s3 == _data.s3) && (_d.s4 == _data.s4) && (_d.s5 == _data.s5) && (_d.structofstruct.b1 == _data.structofstruct.b1) && (_d.structofstruct.b1 == _data.structofstruct.b1)) { pass(TRUE); } else { @@ -488,6 +490,21 @@ void eraseSectorTest() { Serial.println(); } +void eraseSectionTest() { + Serial.println(); + uint32_t _time, _addr; + _addr = random(0, 0xFFFFF); + Serial.print(F("\t\t\tErase 72KB Section: ")); + if (flash.eraseSection(_addr, KB(72))) { + _time = flash.functionRunTime(); + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + void eraseBlock32KTest() { Serial.println(); uint32_t _time, _addr; diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index b4a3ad0..19e09bb 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -2,14 +2,14 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | FlashDiagnostics.ino | | SPIFlash library | - | v 3.0.0 | + | v 3.1.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 17.11.2017 | + | 04.03.2018 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | + | uncomment #define RUNDIAGNOSTIC in SPIFlash.h in the library before compiling | | and loading this application onto your Arduino. | | | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| @@ -64,6 +64,7 @@ void setup() { getID(); eraseChipTest(); + eraseSectionTest(); eraseBlock64KTest(); eraseBlock32KTest(); eraseSectorTest(); diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino old mode 100755 new mode 100644 index 23fd488..763d6ea --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -2,39 +2,28 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Struct_writer.ino | | SPIFlash library | - | v 2.6.0 | + | v 3.1.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 16.04.2017 | + | 03.03.2018 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | This program writes a struct to a random location on your flash memory chip and reads it back. | - | Uncomment #define SENSOR below to get real world readings. Real world readings require a Light dependant resistor hooked up to A0. | - | For information on how to hook up an LDR to an Arduino, please refer to Adafruit's excellent tutorial at | - | https://learn.adafruit.com/photocells/using-a-photocell | | | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| */ #include +//#define PRINTDETAIL +//#define PRINTINDIVIDUALRUNS +#define NUMBEROFREPEATS 100 + #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 - -/* - Uncomment the #define below if you would like real world readings. - For real world readings, hook up a light dependant resistor to A1. - -*/ -//#define SENSOR #if defined (SIMBLEE) #define BAUD_RATE 250000 #define LDR 1 @@ -48,19 +37,63 @@ //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; +struct ConfigurationIn { + float lux = 3.24; + float vOut = 4.45; // Voltage ouput from potential divider to Analog input + float RLDR = 1.234; // Resistance calculation of potential divider with LDR + bool light = true; + uint8_t adc = 45; + uint8_t arr[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + struct MISC { + byte tempHigh = 30; + byte tempLow = 20; + bool parkingMode = false; + bool allowDataToBeSent = false; + } misc; + struct NETWORK { + char ssid[5] = "ssid"; + char pwd[4] = "pwd"; + char userid[7] = "userid"; + } network; + struct CHARGING_INFO { + byte interval = 5; + byte highChargingDefault = 80; + } charging; +}; +ConfigurationIn configurationIn; -struct Configuration { +struct ConfigurationOut { float lux; float vOut; // Voltage ouput from potential divider to Analog input float RLDR; // Resistance calculation of potential divider with LDR bool light; uint8_t adc; uint8_t arr[8]; + struct MISC { + byte tempHigh; + byte tempLow; + bool parkingMode; + bool allowDataToBeSent; + } misc; + struct NETWORK { + char ssid[5]; + char pwd[4]; + char userid[7]; + } network; + struct CHARGING_INFO { + byte interval; + byte highChargingDefault; + } charging; }; -Configuration configuration; +ConfigurationOut configurationOut; +uint16_t eraseCount, writeCount, errorCount, readCount; void setup() { Serial.begin(BAUD_RATE); + eraseCount = 0; + writeCount = 0; + errorCount = NUMBEROFREPEATS; + readCount = 0; #if defined (ARDUINO_SAMD_ZERO) || (__AVR_ATmega32U4__) while (!Serial) ; // Wait for Serial monitor to open #endif @@ -71,94 +104,170 @@ void setup() { Serial.print(F(".")); } Serial.println(); - Serial.println(); flash.begin(); - - - uint32_t _addr = random(0, 1677215); - -#ifndef SENSOR - configuration.lux = 98.43; - configuration.vOut = 4.84; - configuration.RLDR = 889.32; - configuration.light = true; - configuration.adc = 5; - for (uint8_t i = 0; i < 8; i++) { - configuration.arr[i] = i; - } + Serial.println(); +#ifdef PRINTINDIVIDUALRUNS + printLine(); + Serial.println(); + Serial.print("\tStruct number\t\t\tSection Erase\t\t\tStruct Write\t\t\tErrorCheck\t\t\tStruct Read\t\t\t"); + Serial.println(); + printLine(); + Serial.println(); #endif -#ifdef SENSOR - readLDR(); + for (uint16_t x = 1; x <= NUMBEROFREPEATS; x++) { + Serial.println(x); + //uint32_t _addr = random(0, 1677215); + uint32_t _addr = random(0, flash.getCapacity()); +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t"); + Serial.print(x); #endif - if (flash.eraseChip()) { - Serial.println("Chip has been erased"); - } - if (flash.writeAnything(_addr, configuration)) - Serial.println ("Data write successful"); - else - Serial.println ("Data write failed"); - Serial.println(configuration.lux); - Serial.println(configuration.vOut); - Serial.println(configuration.RLDR); - Serial.println(configuration.light); - Serial.println(configuration.adc); - for (uint8_t i = 0; i < 8; i++) { - Serial.print(configuration.arr[i]); - Serial.print(", "); - } - Serial.println(); - Serial.println("Saved!"); - configuration.lux = 0; - configuration.vOut = 0; - configuration.RLDR = 0; - configuration.light = 0; - configuration.adc = 0; - for (uint8_t i = 0; i < 8; i++) { - configuration.arr[i] = 0; + if (flash.eraseSection(_addr, sizeof(configurationIn))) { + //if (flash.eraseSector(_addr)) { + eraseCount++; +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t\t Done"); +#endif + } + else { + eraseCount--; + } + /*if (flash.eraseSector(_addr)) { + Serial.println("Sector has been erased"); + }*/ + if (flash.writeAnything(_addr, configurationIn)) { +#ifdef PRINTDETAIL + Serial.println(configurationIn.lux); + Serial.println(configurationIn.vOut); + Serial.println(configurationIn.RLDR); + Serial.println(configurationIn.light); + Serial.println(configurationIn.adc); + for (uint8_t i = 0; i < 8; i++) { + Serial.print(configurationIn.arr[i]); + Serial.print(","); + } + Serial.println(); + Serial.println(configurationIn.misc.tempHigh); + Serial.println(configurationIn.misc.tempLow); + Serial.println(configurationIn.misc.parkingMode); + Serial.println(configurationIn.misc.allowDataToBeSent); + for (uint8_t i = 0; i < 4; i++) { + Serial.print(configurationIn.network.ssid[i]); + Serial.print(","); + } + Serial.println(); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(configurationIn.network.pwd[i]); + Serial.print(","); + } + Serial.println(); + for (uint8_t i = 0; i < 6; i++) { + Serial.print(configurationIn.network.userid[i]); + Serial.print(","); + } + Serial.println(); + Serial.println(configurationIn.charging.interval); + Serial.println(configurationIn.charging.highChargingDefault); +#endif + writeCount++; + errorCount--; +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t\t Done\t\t\t\t Pass"); +#endif + } + else { +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t\t Done\t\t\t\t Fail"); +#endif + } +delay(50); + if (flash.readAnything(_addr, configurationOut)) { +#ifdef PRINTDETAIL + Serial.println(configurationOut.lux); + Serial.println(configurationOut.vOut); + Serial.println(configurationOut.RLDR); + Serial.println(configurationOut.light); + Serial.println(configurationOut.adc); + for (uint8_t i = 0; i < 8; i++) { + Serial.print(configurationIn.arr[i]); + Serial.print(","); + } + Serial.println(); + Serial.println(configurationOut.misc.tempHigh); + Serial.println(configurationOut.misc.tempLow); + Serial.println(configurationOut.misc.parkingMode); + Serial.println(configurationOut.misc.allowDataToBeSent); + for (uint8_t i = 0; i < 4; i++) { + Serial.print(configurationOut.network.ssid[i]); + Serial.print(","); + } + Serial.println(); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(configurationOut.network.pwd[i]); + Serial.print(","); + } + Serial.println(); + for (uint8_t i = 0; i < 6; i++) { + Serial.print(configurationOut.network.userid[i]); + Serial.print(","); + } + Serial.println(); + Serial.println(configurationOut.charging.interval); + Serial.println(configurationOut.charging.highChargingDefault); +#endif + if (configurationIn.lux == configurationOut.lux || configurationIn.vOut == configurationOut.vOut || configurationIn.RLDR == configurationOut.RLDR || configurationIn.light == configurationOut.light || \ + configurationIn.adc == configurationOut.adc || configurationIn.arr[2] == configurationOut.arr[2] || configurationIn.misc.tempHigh == configurationOut.misc.tempHigh || configurationIn.misc.tempLow == configurationOut.misc.tempLow || \ + configurationIn.misc.parkingMode == configurationOut.misc.parkingMode || configurationIn.misc.allowDataToBeSent == configurationOut.misc.allowDataToBeSent || configurationIn.network.ssid[3] == configurationOut.network.ssid[3] || configurationIn.network.pwd[1] == configurationOut.network.pwd[1] || \ + configurationIn.network.userid[4] == configurationOut.network.userid[4] || configurationIn.charging.interval == configurationOut.charging.interval || configurationIn.charging.highChargingDefault == configurationOut.charging.highChargingDefault) { +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t\t\t Pass"); + Serial.println(); +#endif + readCount++; + } + else { +#ifdef PRINTINDIVIDUALRUNS + Serial.print("\t\t\t\t Fail"); + Serial.println(); +#endif + readCount--; + } + } } +#ifdef PRINTINDIVIDUALRUNS + printLine(); +#endif Serial.println(); - Serial.println("Local values set to 0"); - Serial.println(configuration.lux); - Serial.println(configuration.vOut); - Serial.println(configuration.RLDR); - Serial.println(configuration.light); - Serial.println(configuration.adc); - for (uint8_t i = 0; i < 8; i++) { - Serial.print(configuration.arr[i]); - Serial.print(", "); - } + printLine(); Serial.println(); + Serial.println("\t\tFinal results"); + printLine(); Serial.println(); - flash.readAnything(_addr, configuration); - flash.eraseSector(_addr); - - Serial.println("After reading"); - Serial.println(configuration.lux); - Serial.println(configuration.vOut); - Serial.println(configuration.RLDR); - Serial.println(configuration.light); - Serial.println(configuration.adc); - for (uint8_t i = 0; i < 8; i++) { - Serial.print(configuration.arr[i]); - Serial.print(", "); - } + Serial.print("\t\tNo. of successful erases: "); + Serial.print("\t\t"); + Serial.println(eraseCount); + Serial.print("\t\tNo. of successful writes: "); + Serial.print("\t\t"); + Serial.println(writeCount); + Serial.print("\t\tNo. of errors generated:"); + Serial.print("\t\t"); + Serial.print(errorCount); + Serial.println("\t(errorCheck function failures)"); + Serial.print("\t\tNo. of successful reads: "); + Serial.print("\t\t"); + Serial.println(readCount); + printLine(); Serial.println(); - } void loop() { - delay(1000); } -#ifdef SENSOR -void readLDR() -{ - configuration.adc = analogRead(LDR); - configuration.vOut = (configuration.adc * 0.0048828125); // vOut = Output voltage from potential Divider. [vOut = ADC * (Vin / 1024)] - configuration.RLDR = (10.0 * (5 - configuration.vOut)) / configuration.vOut; // Equation to calculate Resistance of LDR, [R-LDR =(R1 (Vin - vOut))/ vOut]. R1 is in KOhms - // R1 = 10 KOhms , Vin = 5.0 Vdc. - configuration.lux = (500 / configuration.RLDR); +void printLine() { + for (uint16_t i = 0; i < 160; i++) { + Serial.print("-"); + } } -#endif + diff --git a/examples/TestFlash/command_list.ino b/examples/TestFlash/command_list.ino index 823d5e6..9279781 100644 --- a/examples/TestFlash/command_list.ino +++ b/examples/TestFlash/command_list.ino @@ -1,7 +1,7 @@ void commandList() { Serial.println(F("-----------------------------------------------------------------------------------------------------------------------------------")); Serial.println(F(" Winbond Flash ")); - Serial.println(F(" SPIFlash library test v3.0.1 ")); + Serial.println(F(" SPIFlash library test v3.1.0 ")); Serial.println(F(" ----------------------------------------------------------------------------------------------------------------------------------")); Serial.println(F(" Marzogh ")); Serial.println(F(" 24.11.2015 ")); diff --git a/extras/Changes.log b/extras/Changes.log old mode 100755 new mode 100644 index 9a2cd47..136cb32 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -2,6 +2,30 @@ // SPIFlash Library // // Changes log // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Version 3.1.0 // +// Author: Prajwal Bhattaram // +// 24.02.2018 // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +--> Library name change notice inserted into flash.begin(). This notice can be dismissed by commenting out the instance of `#define PRINTNAMECHANGEALERT` in SPIFlash.h. Please refer to the Readme file for further details. + +Bugs squashed +--> An error with how _addressCheck() works with data that spans the memory boundary - when rolling over from address '_chip.capacity' to address '0x00' - has been fixed. In previous versions this caused issues with writing complex data structures across the memory boundary and led to many _writeErrorCheck() failures. Fixes issue #112 + +--> An error with how _writeErrorCheck() worked has been resolved. Writing structs is now as stable as other functions are. Fixes #106 + +--> All compilation-time, non-critical errors have been fixed. + +Enhancements: +--> A new function - 'flash.eraseSection(address, size)' - has been introduced in this version. When a user requires a large and variable (between writes) amount of data to be written to the flash memory on the fly and to have the correct amount of space erased to fit the data, this function will automatically calculate and erase the right amount of space to fit the data. Please note that if the the amount of data being written is consistently the same size, the pre-existing 'flash.eraseSector()', 'flash.eraseBlock32K()' and 'flash.eraseBlock64K()' functions will operate a lot faster. + +--> Updated Diagnostics.ino to include eraseSection(). + +--> All I/O functions now check to see if the flash chip is powered down. If it is, they prevent the function from running and returns an error. A new error code 'CHIPISPOWEREDDOWN' will be returned upon calling flash.error(). + + +New flash memory chips supported: +--> S25FL127S +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 3.0.1 // // Author: Prajwal Bhattaram // // 10.12.2017 // diff --git a/extras/DMASAMD.cpp b/extras/DMASAMD.cpp old mode 100755 new mode 100644 diff --git a/extras/Library speed comparisons.xlsx b/extras/Library speed comparisons.xlsx old mode 100755 new mode 100644 index 4ac6b3d..902eda6 Binary files a/extras/Library speed comparisons.xlsx and b/extras/Library speed comparisons.xlsx differ diff --git a/extras/SPI pinouts.md b/extras/SPI pinouts.md old mode 100755 new mode 100644 diff --git a/extras/Winbond Flash Instructions - Comparison.xlsx b/extras/Winbond Flash Instructions - Comparison.xlsx old mode 100755 new mode 100644 diff --git a/keywords.txt b/keywords.txt old mode 100755 new mode 100644 index f10adaa..bff372a --- a/keywords.txt +++ b/keywords.txt @@ -12,17 +12,17 @@ SPIFlash KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### begin KEYWORD2 -setClock KEYWORD2 -libver KEYWORD2 -error KEYWORD2 +setClock KEYWORD2 +libver KEYWORD2 +error KEYWORD2 getManID KEYWORD2 getJEDECID KEYWORD2 -getUniqueID KEYWORD2 +getUniqueID KEYWORD2 getAddress KEYWORD2 sizeofStr KEYWORD2 getCapacity KEYWORD2 getMaxPage KEYWORD2 -functionRunTime KEYWORD2 +functionRunTime KEYWORD2 readByte KEYWORD2 readByteArray KEYWORD2 readChar KEYWORD2 @@ -32,7 +32,7 @@ readShort KEYWORD2 readLong KEYWORD2 readULong KEYWORD2 readFloat KEYWORD2 -readStr KEYWORD2 +readStr KEYWORD2 readAnything KEYWORD2 writeByte KEYWORD2 writeByteArray KEYWORD2 @@ -45,28 +45,29 @@ writeULong KEYWORD2 writeFloat KEYWORD2 writeStr KEYWORD2 writeAnything KEYWORD2 +eraseSection KEYWORD2 eraseSector KEYWORD2 eraseBlock32K KEYWORD2 eraseBlock64K KEYWORD2 eraseChip KEYWORD2 suspendProg KEYWORD2 resumeProg KEYWORD2 -powerUp KEYWORD2 +powerUp KEYWORD2 powerDown KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### -WINBOND_MANID LITERAL1 -MICROCHIP_MANID LITERAL1 -CYPRESS_MANID LITERAL1 -ADESTO_MANID LITERAL1 -MICRON_MANID LITERAL1 -NULLBYTE LITERAL1 -NULLINT LITERAL1 -BYTE LITERAL1 -KiB LITERAL1 -MiB LITERAL1 +WINBOND_MANID LITERAL1 +MICROCHIP_MANID LITERAL1 +CYPRESS_MANID LITERAL1 +ADESTO_MANID LITERAL1 +MICRON_MANID LITERAL1 +NULLBYTE LITERAL1 +NULLINT LITERAL1 +BYTE LITERAL1 +KiB LITERAL1 +MiB LITERAL1 ####################################### # Built-in variables (LITERAL2) diff --git a/library.properties b/library.properties old mode 100755 new mode 100644 index 9688e9b..4c6778d --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=SPIFlash -version=3.0.1 +version=3.1.0 author=Prajwal Bhattaram maintainer=Prajwal Bhattaram sentence=SPI Flash library for Arduino. -paragraph=This library enables read, write, erase and power functions on the following Flash chips - W25X05**, W25X10**, W25X20**, W25X40**, W25Q80**, W25Q16**, W25Q32**, W25Q64**, W25Q128**, W25Q256**, SST25VF064C, SST26VF064B & S25FL116K. All other Winbond flash chips can also be used with this library from v2.6.0 onwards. A number of Microchip, Cypress & Spansion chips can be used with with the library from v3.0.0 onwards. Refer to change log for further information about this release. +paragraph=This is the last version (v3.1.0) with the name SPIFlash. For future updates (starting 15 May 2018) please download the SPIMemory library instead. This library enables read, write, erase and power functions on the following Flash chips - W25X05**, W25X10**, W25X20**, W25X40**, W25Q80**, W25Q16**, W25Q32**, W25Q64**, W25Q128**, W25Q256**, SST25VF064C, SST26VF064B & S25FL116K. All other Winbond flash chips can also be used with this library from v2.6.0 onwards. A number of Microchip, Cypress & Spansion chips can be used with with the library from v3.0.0 onwards. Refer to change log for further information about this release. category=Data Storage url=https://github.com/Marzogh/SPIFlash architectures=avr,sam,samd,esp8266,esp32,Simblee,stm32 diff --git a/src/DMASAMD.h b/src/DMASAMD.h old mode 100755 new mode 100644 diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp old mode 100755 new mode 100644 index 12644ed..7c4e318 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -1,6 +1,6 @@ -/* Arduino SPIFlash Library v.3.0.0 +/* Arduino SPIFlash Library v.3.1.0 * Copyright (C) 2017 by Prajwal Bhattaram - * Created by Prajwal Bhattaram - 04/11/2017 + * Created by Prajwal Bhattaram - 24/02/2018 * * This file is part of the Arduino SPIFlash Library. This library is for * Winbond NOR flash memory modules. In its current form it enables reading @@ -32,6 +32,7 @@ //Checks to see if page overflow is permitted and assists with determining next address to read/write. //Sets the global address variable bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { + uint32_t _submittedAddress = _addr; if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { return false; } @@ -40,19 +41,30 @@ bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { return false; } - //for (uint32_t i = 0; i < size; i++) { - if (_addr + size >= _chip.capacity) { + //Serial.print("_chip.capacity: "); + //Serial.println(_chip.capacity, HEX); + + if (_submittedAddress + size >= _chip.capacity) { + //Serial.print("_submittedAddress + size: "); + //Serial.println(_submittedAddress + size, HEX); #ifdef DISABLEOVERFLOW _troubleshoot(OUTOFBOUNDS); return false; // At end of memory - (!pageOverflow) #else - _currentAddress = 0x00; + _addressOverflow = ((_submittedAddress + size) - _chip.capacity); + _currentAddress = _addr; + //Serial.print("_addressOverflow: "); + //Serial.println(_addressOverflow, HEX); return true; // At end of memory - (pageOverflow) #endif } - //} - _currentAddress = _addr; - return true; // Not at end of memory if (address < _chip.capacity) + else { + _addressOverflow = false; + _currentAddress = _addr; + return true; // Not at end of memory if (address < _chip.capacity) + } + //Serial.print("_currentAddress: "); + //Serial.println(_currentAddress, HEX); } // Checks to see if the block of memory has been previously written to @@ -62,6 +74,7 @@ bool SPIFlash::_notPrevWritten(uint32_t _addr, uint32_t size) { for (uint32_t i = 0; i < size; i++) { if (_nextByte(READ) != 0xFF) { CHIP_DESELECT; + _troubleshoot(PREVWRITTEN); return false; } } @@ -83,11 +96,11 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { //Serial.print(F("Address being prepped: ")); //Serial.println(_addr); #ifndef HIGHSPEED - if(!_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { + if(_isChipPoweredDown() || !_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { return false; } #else - if (!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { + if (_isChipPoweredDown() || !_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { return false; } #endif @@ -95,15 +108,14 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { break; case ERASEFUNC: - _currentAddress = _addr; - if(!_notBusy()||!_writeEnable()) { + if(_isChipPoweredDown() || !_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { return false; } return true; break; default: - if (!_addressCheck(_addr, size) || !_notBusy()) { + if (_isChipPoweredDown() || !_addressCheck(_addr, size) || !_notBusy()) { return false; } #ifdef ENABLEZERODMA @@ -388,6 +400,17 @@ bool SPIFlash::_noSuspend(void) { return true; } +// Checks to see if chip is powered down. If it is, retrns true. If not, returns false. +bool SPIFlash::_isChipPoweredDown(void) { + if (chipPoweredDown) { + _troubleshoot(CHIPISPOWEREDDOWN); + return true; + } + else { + return false; + } +} + // Polls the status register 1 until busy flag is cleared or timeout bool SPIFlash::_notBusy(uint32_t timeout) { _delay_us(WINBOND_WRITE_DELAY); diff --git a/src/SAM_DMASPI.cpp b/src/SAM_DMASPI.cpp old mode 100755 new mode 100644 diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp old mode 100755 new mode 100644 index c388b6e..c8c0f24 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -1,8 +1,8 @@ -/* Arduino SPIFlash Library v.3.0.0 +/* Arduino SPIFlash Library v.3.1.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 17/11/2017 + * Modified by Prajwal Bhattaram - 24/02/2018 * * This file is part of the Arduino SPIFlash Library. This library is for * Winbond NOR flash memory modules. In its current form it enables reading @@ -67,6 +67,27 @@ SPIFlash::SPIFlash(uint8_t cs) { //Identifies chip and establishes parameters bool SPIFlash::begin(uint32_t flashChipSize) { +#ifdef PRINTNAMECHANGEALERT + if (!Serial) { + Serial.begin(115200); + } + for (uint8_t i = 0; i < 230; i++) { + Serial.print("-"); + } + Serial.println(); + Serial.println("\t\t\t\t\t\t\t\t\t\tImportant Notice"); + for (uint8_t i = 0; i < 230; i++) { + Serial.print("-"); + } + Serial.println(); + Serial.println("\t\t\t\t\tThis version of the library - v3.1.0 will be the last version to ship under the name SPIFlash."); + Serial.println("\t\t\t\tStarting early May - when v3.2.0 is due - this library will be renamed 'SPIMemory' on the Arduino library manager."); + Serial.println("\t\t\t\t\t\t\tPlease refer to the Readme file for further details."); + for (uint8_t i = 0; i < 230; i++) { + Serial.print("-"); + } + Serial.println(); +#endif #ifdef RUNDIAGNOSTIC Serial.println("Chip Diagnostics initiated."); Serial.println(); @@ -83,7 +104,7 @@ bool SPIFlash::begin(uint32_t flashChipSize) { // If no capacity is defined in user code if (!flashChipSize) { #ifdef RUNDIAGNOSTIC - Serial.println("No Chip size defined by user"); + Serial.println("No Chip size defined by user. Automated identification initiated."); #endif bool retVal = _chipID(); _endSPI(); @@ -103,7 +124,7 @@ bool SPIFlash::begin(uint32_t flashChipSize) { if (_chip.manufacturerID == CYPRESS_MANID) { setClock(SPI_CLK/4); // Cypress/Spansion chips appear to perform best at SPI_CLK/4 } - + chipPoweredDown = false; return true; } @@ -136,11 +157,16 @@ uint32_t SPIFlash::getMaxPage(void) { } //Returns the time taken to run a function. Must be called immediately after a function is run as the variable returned is overwritten each time a function from this library is called. Primarily used in the diagnostics sketch included in the library to track function time. +//This function can only be called if #define RUNDIAGNOSTIC is uncommented in SPIFlash.h float SPIFlash::functionRunTime(void) { +#ifdef RUNDIAGNOSTIC return _spifuncruntime; +#else + return 0; +#endif } -//Returns the library version as a string +//Returns the library version as three bytes bool SPIFlash::libver(uint8_t *b1, uint8_t *b2, uint8_t *b3) { *b1 = LIBVER; *b2 = LIBSUBVER; @@ -167,7 +193,7 @@ uint32_t SPIFlash::getJEDECID(void) { // Returns a 64-bit Unique ID that is unique to each flash memory chip uint64_t SPIFlash::getUniqueID(void) { - if(!_notBusy()) { + if(!_notBusy() || _isChipPoweredDown()) { return false; } _beginSPI(UNIQUEID); @@ -183,7 +209,7 @@ uint64_t SPIFlash::getUniqueID(void) { } CHIP_DESELECT - long long _uid; + long long _uid = 0; for (uint8_t i = 0; i < 8; i++) { _uid += _uniqueID[i]; _uid = _uid << 8; @@ -191,11 +217,9 @@ uint64_t SPIFlash::getUniqueID(void) { return _uid; } -//Gets the next available address for use. Has two variants: -// A. Takes the size of the data as an argument and returns a 32-bit address -// B. Takes a three variables, the size of the data and two other variables to return a page number value & an offset into. +//Gets the next available address for use. +// Takes the size of the data as an argument and returns a 32-bit address // All addresses in the in the sketch must be obtained via this function or not at all. -// Variant A uint32_t SPIFlash::getAddress(uint16_t size) { bool _loopedOver = false; if (!_addressCheck(currentAddress, size)){ @@ -239,7 +263,7 @@ uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - uint8_t data; + uint8_t data = 0; _read(_addr, data, sizeof(data), fastRead); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; @@ -255,7 +279,7 @@ int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - int8_t data; + int8_t data = 0; _read(_addr, data, sizeof(data), fastRead); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; @@ -422,14 +446,7 @@ bool SPIFlash::readStr(uint32_t _addr, String &data, bool fastRead) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _BYTE_); } // Writes a char of data to a specific location in a page. @@ -440,14 +457,7 @@ bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _CHAR_); } // Writes an array of bytes starting from a specific location in a page. @@ -624,14 +634,7 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSi // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _WORD_); } // Writes a signed int as two bytes starting from a specific location in a page @@ -642,14 +645,7 @@ bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _SHORT_); } // Writes an unsigned long as four bytes starting from a specific location in a page. @@ -660,14 +656,7 @@ bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _ULONG_); } // Writes a signed long as four bytes starting from a specific location in a page @@ -678,14 +667,7 @@ bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _LONG_); } // Writes a float as four bytes starting from a specific location in a page @@ -696,14 +678,7 @@ bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); - #endif + return _write(_addr, data, sizeof(data), errorCheck, _FLOAT_); } // Writes a string to a specific location on a page @@ -714,14 +689,106 @@ bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeStr(uint32_t _addr, String &data, bool errorCheck) { + return _write(_addr, data, sizeof(data), errorCheck, _STRING_); +} + +// Erases a number of sectors or blocks as needed by the data being input. +// Takes an address and the size of the data being input as the arguments and erases the block/s of memory containing the address. +bool SPIFlash::eraseSection(uint32_t _addr, uint32_t _sz) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); - bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + #endif + + if (!_prep(ERASEFUNC, _addr, _sz)) { + return false; + } + + // If size of data is > 4KB more than one sector needs to be erased. So the number of erase sessions is determined by the quotient of _sz/KB(4). If the _sz is not perfectly divisible by KB(4), then an additional sector has to be erased. + uint32_t noOfEraseRunsB4Boundary = 0; + uint32_t noOf4KBEraseRuns, KB64Blocks, KB32Blocks, KB4Blocks, totalBlocks; + + if (_sz/KB(4)) { + noOf4KBEraseRuns = _sz/KB(4); + } + else { + noOf4KBEraseRuns = 1; + } + KB64Blocks = noOf4KBEraseRuns/16; + KB32Blocks = (noOf4KBEraseRuns % 16) / 8; + KB4Blocks = (noOf4KBEraseRuns % 8); + totalBlocks = KB64Blocks + KB32Blocks + KB4Blocks; + //Serial.print("noOf4KBEraseRuns: "); + //Serial.println(noOf4KBEraseRuns); + //Serial.print("totalBlocks: "); + //Serial.println(totalBlocks); + + uint16_t _eraseFuncOrder[totalBlocks]; + + if (KB64Blocks) { + for (uint32_t i = 0; i < KB64Blocks; i++) { + _eraseFuncOrder[i] = BLOCK64ERASE; + } + } + if (KB32Blocks) { + for (uint32_t i = KB64Blocks; i < (KB64Blocks + KB32Blocks); i++) { + _eraseFuncOrder[i] = BLOCK32ERASE; + } + } + if (KB4Blocks) { + for (uint32_t i = (KB64Blocks + KB32Blocks); i < totalBlocks; i++) { + _eraseFuncOrder[i] = SECTORERASE; + } + } + +// Now that the number of blocks to be erased have been calculated and the information saved, the erase function is carried out. + if (_addressOverflow) { + noOfEraseRunsB4Boundary = (_sz - _addressOverflow)/16; + noOfEraseRunsB4Boundary += ((_sz - _addressOverflow) % 16) / 8; + noOfEraseRunsB4Boundary += ((_sz - _addressOverflow) % 8); + //Serial.print("noOfEraseRunsB4Boundary: "); + //Serial.println(noOfEraseRunsB4Boundary); + } + if (!_addressOverflow) { + for (uint32_t j = 0; j < totalBlocks; j++) { + _beginSPI(_eraseFuncOrder[j]); //The address is transferred as a part of this function + _endSPI(); + + + //Serial.print("_eraseFuncOrder: 0x"); + //Serial.println(_eraseFuncOrder[j], HEX); + + uint16_t _timeFactor = 0; + switch (_eraseFuncOrder[j]) { + case BLOCK64ERASE: + _timeFactor = 1200; + break; + + case BLOCK32ERASE: + _timeFactor = 1000; + break; + + case SECTORERASE: + _timeFactor = 500; + break; + + } + if(!_notBusy(_timeFactor * 1000L)) { + return false; //Datasheet says erasing a sector takes 400ms max + } + if (j == noOfEraseRunsB4Boundary) { + if (!_prep(ERASEFUNC, (_addr + (_sz - _addressOverflow)), _sz)) { + return false; + } + //Serial.print("Overflow triggered"); + } + } + } + //_writeDisable(); + #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return _write(_addr, data, sizeof(data), errorCheck); #endif + + return true; } // Erases one 4k sector. @@ -730,7 +797,7 @@ bool SPIFlash::eraseSector(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if (!_prep(ERASEFUNC, _addr)) { + if (!_prep(ERASEFUNC, _addr, KB(4))) { return false; } _beginSPI(SECTORERASE); //The address is transferred as a part of this function @@ -753,7 +820,7 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if (!_prep(ERASEFUNC, _addr)) { + if (!_prep(ERASEFUNC, _addr, KB(32))) { return false; } _beginSPI(BLOCK32ERASE); @@ -776,7 +843,7 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if (!_prep(ERASEFUNC, _addr)) { + if (!_prep(ERASEFUNC, _addr, KB(64))) { return false; } @@ -797,7 +864,7 @@ bool SPIFlash::eraseChip(void) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if(!_notBusy() || !_writeEnable()) { + if(_isChipPoweredDown() || !_notBusy() || !_writeEnable()) { return false; } @@ -824,7 +891,7 @@ bool SPIFlash::suspendProg(void) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if(_notBusy()) { + if(_isChipPoweredDown() || _notBusy()) { return false; } @@ -852,7 +919,7 @@ bool SPIFlash::resumeProg(void) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif - if(!_notBusy() || _noSuspend()) { + if(_isChipPoweredDown() || !_notBusy() || _noSuspend()) { return false; } @@ -887,10 +954,12 @@ bool SPIFlash::powerDown(void) { _delay_us(5); #ifdef RUNDIAGNOSTIC + chipPoweredDown = true; bool _retVal = !_writeEnable(false); _spifuncruntime = micros() - _spifuncruntime; return _retVal; #else + chipPoweredDown = true; return !_writeEnable(false); #endif } @@ -913,12 +982,14 @@ bool SPIFlash::powerUp(void) { if (_writeEnable(false)) { _writeDisable(); _spifuncruntime = micros() - _spifuncruntime; + chipPoweredDown = false; return true; } return false; #else if (_writeEnable(false)) { _writeDisable(); + chipPoweredDown = false; return true; } return false; diff --git a/src/SPIFlash.h b/src/SPIFlash.h old mode 100755 new mode 100644 index f824e2a..447ad37 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -1,8 +1,8 @@ -/* Arduino SPIFlash Library v.3.0.0 +/* Arduino SPIFlash Library v.3.1.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 04/11/2017 + * Modified by Prajwal Bhattaram - 24/02/2018 * * This file is part of the Arduino SPIFlash Library. This library is for * Winbond NOR flash memory modules. In its current form it enables reading @@ -61,6 +61,8 @@ //#define ENABLEZERODMA // //#define ZERO_SPISERCOM SERCOM4 // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +#define PRINTNAMECHANGEALERT + #include #include "defines.h" #include @@ -138,7 +140,7 @@ #endif #define LIBVER 3 -#define LIBSUBVER 0 +#define LIBSUBVER 1 #define BUGFIXVER 0 class SPIFlash { @@ -200,6 +202,7 @@ class SPIFlash { template bool writeAnything(uint32_t _addr, const T& data, bool errorCheck = true); template bool readAnything(uint32_t _addr, T& data, bool fastRead = false); //-------------------------------- Erase functions ------------------------------------// + bool eraseSection(uint32_t _addr, uint32_t _sz); bool eraseSector(uint32_t _addr); bool eraseBlock32K(uint32_t _addr); bool eraseBlock64K(uint32_t _addr); @@ -245,6 +248,7 @@ class SPIFlash { void _printSupportLink(void); void _endSPI(void); bool _disableGlobalBlockProtect(void); + bool _isChipPoweredDown(void); bool _prep(uint8_t opcode, uint32_t _addr, uint32_t size = 0); bool _startSPIBus(void); bool _beginSPI(uint8_t opcode); @@ -267,10 +271,10 @@ class SPIFlash { uint8_t _readStat1(void); uint8_t _readStat2(void); uint8_t _readStat3(void); - template bool _write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck); - template bool _read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead = false); + template bool _write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType); + template bool _read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead = false, uint8_t _dataType = 0x00); //template bool _writeErrorCheck(uint32_t _addr, const T& value); - template bool _writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz); + template bool _writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType = 0x00); //-------------------------------- Private variables ----------------------------------// #ifdef SPI_HAS_TRANSACTION SPISettings _settings; @@ -285,6 +289,7 @@ class SPIFlash { #endif volatile uint8_t *cs_port; bool pageOverflow, SPIBusState; + bool chipPoweredDown = false; bool address4ByteEnabled = false; uint8_t cs_mask, errorcode, stat1, stat2, stat3, _SPCR, _SPSR, _a0, _a1, _a2; char READ = 'R'; @@ -301,6 +306,7 @@ class SPIFlash { }; chipID _chip; uint32_t currentAddress, _currentAddress = 0; + uint32_t _addressOverflow = false; uint8_t _uniqueID[8]; const uint8_t _capID[14] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B, 0x00, 0x01}; @@ -319,7 +325,7 @@ class SPIFlash { // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) template bool SPIFlash::writeAnything(uint32_t _addr, const T& data, bool errorCheck) { - return _write(_addr, data, sizeof(data), errorCheck); + return _write(_addr, data, sizeof(data), errorCheck, _STRUCT_); } // Reads any type of data from a specific location in the flash memory. @@ -333,30 +339,39 @@ template bool SPIFlash::readAnything(uint32_t _addr, T& data, bool fas //---------------------------------- Private Templates ----------------------------------// -// Private template to check for errors in writing to flash memory -// Takes three arguments - -// 1. _addr --> Any address from 0 to maxAddress -// 2. const T& value --> Variable with the data to be error checked -// 3. _sz --> Size of the data variable to be error checked, in bytes (1 byte = 8 bits) -template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz) { - if (!_notBusy()) { +template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType) { + if (_isChipPoweredDown() || !_addressCheck(_addr, _sz) || !_notBusy()) { return false; } - //Serial.print(F("Address being error checked: ")); - //Serial.println(_addr); - _currentAddress = _addr; const uint8_t* p = (const uint8_t*)(const void*)&value; - CHIP_SELECT - _nextByte(WRITE, READDATA); - _transferAddress(); - for (uint16_t i = 0; i < _sz; i++) { - if (*p++ != _nextByte(READ)) { - _troubleshoot(ERRORCHKFAIL); - _endSPI(); - return false; + if (_dataType == _STRUCT_) { + uint8_t _inByte[_sz]; + _beginSPI(READDATA); + _nextBuf(READDATA, &(*_inByte), _sz); + _endSPI(); + for (uint16_t i = 0; i < _sz; i++) { + if (*p++ != _inByte[i]) { + _troubleshoot(ERRORCHKFAIL); + return false; + } + else { + return true; + } + } + } + else { + CHIP_SELECT + _nextByte(WRITE, READDATA); + _transferAddress(); + for (uint16_t i = 0; i < _sz; i++) { + if (*p++ != _nextByte(READ)) { + _troubleshoot(ERRORCHKFAIL); + _endSPI(); + return false; + } } + _endSPI(); } - _endSPI(); return true; } @@ -369,10 +384,19 @@ template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& valu // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) -template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck) { - if (!_prep(PAGEPROG, _addr, _sz)) { +template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType) { + bool _retVal; +#ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); +#endif + + uint32_t _addrIn = _addr; + if (!_prep(PAGEPROG, _addrIn, _sz)) { return false; } + _addrIn = _currentAddress; + //Serial.print("_addrIn: "); + //Serial.println(_addrIn, HEX); const uint8_t* p = ((const uint8_t*)(const void*)&value); //Serial.print(F("Address being written to: ")); //Serial.println(_addr); @@ -389,7 +413,7 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_ } else { //If data is longer than one byte (8 bits) uint32_t length = _sz; - uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = SPI_PAGESIZE-(_addrIn % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page if (maxBytes > length) { for (uint16_t i = 0; i < length; ++i) { @@ -408,16 +432,25 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_ _nextByte(WRITE, *p++); } CHIP_DESELECT - _currentAddress += writeBufSz; + if (!_addressOverflow) { + _currentAddress += writeBufSz; + } + else { + if (data_offset >= _addressOverflow) { + _currentAddress = 0x00; + _addressOverflow = false; + } + } data_offset += writeBufSz; length -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop + maxBytes = SPI_PAGESIZE; // Now we can do up to 256 bytes per loop if(!_notBusy() || !_writeEnable()) { return false; } } while (length > 0); } } + if (!errorCheck) { _endSPI(); return true; @@ -425,8 +458,12 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_ else { //Serial.print(F("Address sent to error check: ")); //Serial.println(_addr); - return _writeErrorCheck(_addr, value, _sz); + _retVal = _writeErrorCheck(_addr, value, _sz, _dataType); } +#ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; +#endif + return _retVal; } // Reads any type of data from a specific location in the flash memory. @@ -435,26 +472,39 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_ // 2. T& value --> Variable to return data into // 3. _sz --> Size of the variable in bytes (1 byte = 8 bits) // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -template bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead) { - if (_prep(READDATA, _addr, _sz)) { +template bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead, uint8_t _dataType) { + if (!_prep(READDATA, _addr, _sz)) { + return false; + } + else { uint8_t* p = (uint8_t*)(void*)&value; - CHIP_SELECT - if (fastRead) { - _nextByte(WRITE, FASTREAD); + + if (_dataType == _STRING_) { + char _inChar[_sz]; + _beginSPI(READDATA); + _nextBuf(READDATA, (uint8_t*) &(*_inChar), _sz); + _endSPI(); + for (uint16_t i = 0; i < _sz; i++) { + *p++ = _inChar[i]; + } } else { - _nextByte(WRITE, READDATA); - } - _transferAddress(); - for (uint16_t i = 0; i < _sz; i++) { - *p++ =_nextByte(READ); + CHIP_SELECT + if (fastRead) { + _nextByte(WRITE, FASTREAD); + } + else { + _nextByte(WRITE, READDATA); + } + _transferAddress(); + for (uint16_t i = 0; i < _sz; i++) { + *p++ =_nextByte(READ); + } + _endSPI(); } - _endSPI(); return true; } - else { - return false; - } + return true; } #endif // _SPIFLASH_H_ diff --git a/src/defines.h b/src/defines.h old mode 100755 new mode 100644 index ce05bbf..d81a7d6 --- a/src/defines.h +++ b/src/defines.h @@ -1,7 +1,7 @@ -/* Arduino SPIFlash Library v.3.0.0 +/* Arduino SPIFlash Library v.3.1.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 - * Modified by Prajwal Bhattaram - 04/11/2017 + * Modified by Prajwal Bhattaram - 24/02/2018 * * This file is part of the Arduino SPIFlash Library. This library is for * Winbond NOR flash memory modules. In its current form it enables reading @@ -185,8 +185,25 @@ #define UNSUPPORTEDFUNC 0x0C #define UNABLETO4BYTE 0x0D #define UNABLETO3BYTE 0x0E + #define CHIPISPOWEREDDOWN 0x0F #define UNKNOWNERROR 0xFE + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + // List of Supported data types // + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + #define _BYTE_ 0x01 + #define _CHAR_ 0x02 + #define _WORD_ 0x03 + #define _SHORT_ 0x04 + #define _ULONG_ 0x05 + #define _LONG_ 0x06 + #define _FLOAT_ 0x07 + #define _STRING_ 0x08 + #define _BYTEARRAY_ 0x09 + #define _CHARARRAY_ 0x0A + #define _STRUCT_ 0x0B + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Bit shift macros // // Thanks to @VitorBoss // diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp old mode 100755 new mode 100644 index 0e06d1f..e4fce15 --- a/src/troubleshoot.cpp +++ b/src/troubleshoot.cpp @@ -53,7 +53,7 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { #if defined (ARDUINO_ARCH_AVR) _printErrorCode(); #else - Serial.println(); + //Serial.println(); switch (_code) { case SUCCESS: Serial.println("Function executed successfully"); @@ -126,6 +126,10 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { Serial.println("Unable to disable 4-byte addressing."); break; + case CHIPISPOWEREDDOWN: + Serial.println("The Flash chip is currently powered down."); + break; + default: Serial.println("Unknown error"); break;