diff --git a/README.md b/README.md
index bfe4211..ef2c5a5 100644
--- a/README.md
+++ b/README.md
@@ -12,64 +12,58 @@ This Arduino library is for use with flash memory chips that communicate using t
-### Compatibility
-
-#### 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
-
-##### Completely supported
-
-- ATmega328P (Arduino Uno, Arduino Micro, Arduino Fio, Arduino Nano)
-- ATmega32u4 (Arduino Leonardo, Arduino Fio v3)
-- ATmega2560 (Arduino Mega)
-- ATSAMD21G18 ARM Cortex M0+ (Adafruit Feather M0, Adafruit Feather M0 Express)
-- AT91SAM3X8E ARM Cortex M3 (Arduino Due)
-- ATSAMD51J19 ARM Cortex M4 (Adafruit Metro M4)
-- STM32F091RCT6 (Nucleo-F091RC)
-- ESP8266 Boards (Adafruit ESP8266 Feather)
-- Simblee Boards (Sparkfun Simblee)
-
-##### In BETA
-- ESP32 Boards (Tested on the Adafruit ESP32 Feather) The library is known to work with the ESP32 core as of the commit 25dff4f on 05.04.2018. ```ESP32 support will remain in beta till the ESP32 core can be installed via the Arduino boards manager.```
-NOTE: ESP32 boards usually have an SPI Flash 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
-
-##### Completely supported (Actually tested with)
-- Winbond
- - W25Q16BV
- - W25Q64FV
- - W25Q80BV
- - W25Q256FV
-- Microchip
- - SST25VF064C
- - SST26VF064B
-- Cypress/Spansion
- - S25FL032P
- - S25FL116K
- - S25FL127S
-- ON Semiconductor
- - LE25U40CMC
-- AMIC
- - A25L512A0
-- Micron
- - M25P40
-- Adesto
- - AT25SF041
-
-##### Should work with (Similar enough to the ones actually tested with)
-- Winbond (All SPI Flash chips)
-- Microchip (SST25 & SST26 series)
-- Cypress/Spansion (S25FL series)
-- Any flash memory that is compatible with the SFDP standard as defined in JESD216B
+### IDE Compatibility (actually tested with)
+
+- Arduino IDE v1.5.x
+- Arduino IDE v1.6.x
+- Arduino IDE v1.8.x
+
+
+
+### Platform compatibility
+
+| Micro controllers | Dev boards tested with | Notes |
+| ----------------- | ---------------------- | ----- |
+| ATmega328P | Arduino Uno, Arduino Micro,
Arduino Fio, Arduino Nano | - |
+| ATmega32u4 | Arduino Leonardo, Arduino Fio v3 | - |
+| ATmega2560 | Arduino Mega | - |
+| ATSAMD21G18 (ARM Cortex M0+) | Adafruit Feather M0,
Adafruit Feather M0 Express,
Adafruit ItsyBitsy M0 Express | - |
+| AT91SAM3X8E (ARM Cortex M3) | Arduino Due | - |
+| ATSAMD51J19 (ARM Cortex M4) | Adafruit Metro M4 | - |
+| STM32F091RCT6 | Nucleo-F091RC | |
+| ESP8266 | Adafruit ESP8266 Feather,
Sparkfun ESP8266 Thing | - |
+| ESP32 | Adafruit ESP32 Feather,
Sparkfun ESP32 Thing | In BETA. Refer to footnote£ below. |
+| Simblee | Sparkfun Simblee | - |
+
+£ ESP32 Boards (Tested on the Adafruit ESP32 Feather) The library is known to work with the ESP32 core as of the commit 25dff4f on 05.04.2018. ```ESP32 support will remain in beta till the ESP32 core can be installed via the Arduino boards manager.```
+NOTE: ESP32 boards usually have an SPI Flash already attached to their default SS pin, so the user has to explicitly declare the `ChipSelect` pin being used with the constructor
+
+
+
+### Flash memory compatibility - Actually tested with
+
+| Manufacturer | Flash IC | Notes |
+| ------------ | -------- | ----- |
+| Winbond | W25Q16BV
W25Q64FV
W25Q64JV
W25Q80BV
W25Q256FV | Should work with the W25QXXXBV, W25QXXXFV &
W25QXXXJV families |
+| Microchip | SST25VF064C
SST26VF064B | Should work with the SST25 & SST26 families |
+| Cypress/Spansion | S25FL032P
S25FL116K
S25FL127S | Should work with the S25FL family |
+| ON Semiconductor | LE25U40CMC | |
+| AMIC| A25L512A0 | |
+| Micron| M25P40 | |
+| Adesto| AT25SF041 | |
+| Giga devices| GD25Q16C | (Used on the Adafruit ItsyBitsy M0 Express) |
+
+##### Should work with any flash memory that is compatible with the SFDP standard as defined in JESD216B
+
+
+
+### FRAM memory compatibility - Actually tested with
+
+| Manufacturer | Flash IC | Notes |
+| ------------ | -------- | ----- |
+| Cypress/Spansion | FM25W256 | Should work with the FM25W family |
+
+
### Installation
@@ -102,6 +96,8 @@ As of v3.2.1, SFDP parameter discovery is an user controlled option. To get the
##### 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 SPIMemory.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:
@@ -110,45 +106,27 @@ The library enables the following functions:
#### 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/SPIMemory/wiki/Chipsize) or look at defines.h .
+###### `begin(_chipsize)`
###### `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)`
-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/SPIMemory/wiki/Error-reporting) section the Wiki for further reference.
###### `getManID()`
-Returns the Manufacturer ID as a 16-bit value.
###### `getJEDECID()`
-Returns the JEDEC ID as a 32-bit value.
###### `getUniqueID()`
-Returns the Unique ID as a 64-bit value.
###### `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.
-
-In library versions >= v3.0.0 This function can be called anytime - even if there is preexisting data on the flash chip. It will simply find the next empty address block for the data.
-
-###### sizeofStr()
-Use this function to find the size of a String to use as the argument in getAddress(size). Using size = sizeof(String) will cause the getAddress(size) function to fail.
-size = sizeof(variable) can be used for all types of data but String objects.
+###### `sizeofStr()`
-###### getCapacity()
-Returns the capacity in bytes as a 32-bit value.
+###### `getCapacity()`
-###### getMaxPage()
-Returns the maximum number of pages in the flash memory as a 32-bit value.
+###### `getMaxPage()`
-###### functionRunTime()
-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.
- NOTE: Can only be called when '#define RUNDIAGNOSTIC' is uncommented in SPIMemory.h
+###### `functionRunTime()`
@@ -162,35 +140,25 @@ All read commands take a last boolean argument 'fastRead'. This argument default
All read commands only take a 32-bit address variable instead of the optional 16-bit page number & 8-bit offset variables in previous versions of the library (< v3.0.0)
-###### readAnything(address, value)
-Reads _any type of variable/struct_ (any sized value) from a specific location. Takes the address (0-maxAddress) of the data and the variable/struct to write the data back to, as arguments.
+###### `readAnything(address, value)`
-###### readByte(address)
-Reads a _byte_ (unsigned 8 bit value) from a specific location. Takes the address (0-maxAddress) of the byte as an argument.
+###### `readByte(address)`
-###### readChar(address)
-Reads a _char_ (signed 8 bit value) from a specific location. Takes the address (0-maxAddress) of the char as an argument.
+###### `readChar(address)`
-###### readWord(address)
-Reads a _word_ (unsigned 16 bit value) from a specific location. Takes the address (0-maxAddress) of the word as an argument.
+###### `readWord(address)`
-###### readShort(address)
-Reads a _short_ (signed 16 bit value) from a specific location. Takes the address (0-maxAddress) of the short as an argument.
+###### `readShort(address)`
-###### readULong(address)
-Reads an _unsigned long_ (unsigned 32 bit value) from a specific location. Takes the address (0-maxAddress) of the unsigned long as an argument.
+###### `readULong(address)`
-###### readLong(address)
-Reads a _long_ (signed 32 bit value) from a specific location. Takes the address (0-maxAddress) of the long as an argument.
+###### `readLong(address)`
-###### readFloat(address)
-Reads a _float_ (decimal value) from a specific location. Takes the address (0-maxAddress) of the float as an argument.
+###### `readFloat(address)`
-###### readStr(address, outputStr)
-Reads a _string_ (String Object) from a specific location to an outputStr variable. Takes the address (0-maxAddress) of the String and a String as arguments.
+###### `readStr(address, outputStr)`
-###### readAnything(address, value)
-Reads _any type of variable/struct_ (any sized value) from a specific location. Takes the address (0-maxAddress) of the data and the variable/struct to write the data to, as arguments.
+###### `readAnything(address, value)`
##### Write commands
@@ -201,32 +169,24 @@ All write commands take a boolean last argument 'errorCheck'. This argument defa
All write commands only take a 32-bit address variable instead of the optional 16-bit page number & 8-bit offset variables in previous versions of the library (< v3.0.0)
-###### writeByte(address, data)
-Writes a byte of data to a specific location. Takes the address (0-maxAddress) of data byte and one byte of data as arguments.
+###### `writeByte(address, data)`
-###### writeChar(address, data)
-Writes a _char_ (signed 8 bit value) to a specific location. Takes the address (0-maxAddress) of the char and one char of data as arguments.
+###### `writeChar(address, data)`
-###### writeWord(address, data)
-Writes a _word_ (unsigned 16 bit value) to a specific location. Takes the address (0-maxAddress) of the word and one word of data as arguments.
+###### `writeWord(address, data)`
-###### writeShort(address, data)
-Writes a _short_ (signed 16 bit value) to a specific location. Takes the address (0-maxAddress) of the short and one short of data as arguments.
+###### `writeShort(address, data)`
-###### writeULong(address, data)
-Writes an _unsigned long_ (unsigned 32 bit value) to a specific location. Takes the address (0-maxAddress) of the unsigned long and one unsigned long of data as arguments.
+###### `writeULong(address, data)`
-###### writeLong(address, data)
-Writes a _long_ (signed 32 bit value) to a specific location. Takes the address (0-maxAddress) of the long and one long of data as arguments.
+###### `writeLong(address, data)`
-###### writeFloat(address, data)
-Writes a _float_ (decimal value) to a specific location. Takes the address (0-maxAddress) of the float and one float of data as arguments.
+###### `writeFloat(address, data)`
-###### writeStr(address, data)
-Writes a _string_ (String Object) to a specific location. Takes the address (0-maxAddress) of the String and a String as arguments.
+###### `writeStr(address, data)`
+
+###### `writeAnything(address, value)`
-###### writeAnything(address, value)
-Writes _any type of variable/struct_ (any sized value) from a specific location. Takes the address (0-maxAddress) of the data and the variable/struct to write the data from, as arguments.
##### Continuous read/write commands
@@ -235,17 +195,14 @@ All write commands take a boolean last argument 'errorCheck'. This argument defa
-###### readByteArray(address, *data_buffer, bufferSize)
-Reads an array of bytes starting from a specific address Takes the address (0-maxAddress) & a data_buffer - i.e. an array of bytes to be read from the flash memory - and size of the array as arguments. ```uint8_t data_buffer[n];``` The data buffer **must** be an array of n **bytes**. 'n' is determined by the amount of RAM available on the Arduino board.
+###### `readByteArray(address, *data_buffer, bufferSize)`
+
+###### `writeByteArray(address, *data_buffer, bufferSize)`
-###### writeByteArray(address, *data_buffer, bufferSize)
-Writes an array of bytes starting from a specific address. Takes the address (0-maxAddress) & a data_buffer - i.e. an array of bytes to be written to the flash memory - and size of the array as arguments. ```uint8_t data_buffer[n];``` The data buffer **must** be an array of 'n' **bytes**. The number of bytes - 'n' - is determined by the amount of RAM available on the Arduino board.
+###### `readCharArray(address, *data_buffer, bufferSize)`
-###### readCharArray(address, *data_buffer, bufferSize)
-Reads an array of chars starting from a specific address. Takes the address (0-maxAddress) & a data_buffer - i.e. an array of chars to be read from the flash memory - and size of the array as arguments. ```char data_buffer[n];``` The data buffer **must** be an array of n **chars**. 'n' is determined by the amount of RAM available on the Arduino board.
+###### `writeCharArray(address, *data_buffer, bufferSize)`
-###### writeCharArray(address, *data_buffer, bufferSize)
-Writes an array of chars starting from a specific address. Takes the address (0-maxAddress) & a data_buffer - i.e. an array of chars to be written to the flash memory - and size of the array as arguments. ```char data_buffer[n];``` The data buffer **must** be an array of 'n' **chars**. The number of chars - 'n' - is determined by the amount of RAM available on the Arduino board.
##### Erase commands
@@ -254,74 +211,61 @@ All erase commands only take a 32-bit address variable instead of the optional 1
-###### eraseSector(address)
-Erases one 4KB sector - 16 pages - containing the address to be erased. The sectors are numbered 0 - 255 containing 16 pages each.
-Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255, and so on...
+###### `eraseSector(address)`
-###### eraseBlock32K(address)
-Erases one 32KB block - 128 pages - containing the address to be erased. The blocks are numbered 0 - 31 containing 128 pages each.
-Page 0-127 --> Block 0; Page 128-255 --> Block 1;......Page 3968-4095 --> Block 31, and so on...
+###### `eraseBlock32K(address)`
-###### eraseBlock64K(address)
-Erases one 64KB block - 256 pages - containing the address to be erased. The blocks are numbered 0 - 15 containing 256 pages each.
-// Page 0-255 --> Block 0; Page 256-511 --> Block 1;......Page 3840-4095 --> Block 15, and so on...
+###### `eraseBlock64K(address)`
-###### eraseChip()
-Erases entire chip. Use with care.
+###### `eraseChip()`
-###### 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.
+###### `eraseSection(address, sizeOfData)`
-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
-###### suspendProg()
-Suspends current Block Erase/Sector Erase/Page Program. Does not suspend chipErase(). Page Program, Write Status Register, Erase instructions are not allowed. Erase suspend is only allowed during Block/Sector erase. Program suspend is only allowed during Page/Quad Page Program
+###### `suspendProg()`
-###### resumeProg()
-Resumes previously suspended Block Erase/Sector Erase/Page Program.
+###### `resumeProg()`
##### Power operation commands
-###### powerDown()
-Puts device in low power state. Useful for battery powered operations. Typical current consumption during power-down is 1mA with a maximum of 5mA. (Datasheet 7.4). In powerDown() the chip will only respond to powerUp()
+###### `powerDown()`
+
+###### `powerUp()`
-###### powerUp()
-Wakes chip from low power state.
##### Error codes explained
-* **0x00** - Action completed successfully. No Error.
-* **0x01** - *constructor_of_choice*.begin() was not called in void setup()
-* **0x02** - Unable to identify chip. Are you sure this is a Winbond Flash chip? Please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with your chip type and I will try to add support to your chip
-* **0x03** - Unable to identify capacity. Please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with your chip type and I will work on adding support to your chip
-* **0x04** - Chip is busy. Make sure all pins have been connected properly. If it still doesn't work,please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with the details of what your were doing when this error occurred
-* **0x05** - Page overflow has been disabled and the address called exceeds the memory
-* **0x06** - Unable to Enable Writing to chip. Please make sure the HOLD & WRITEPROTECT pins are connected properly to VCC & GND respectively. If you are still facing issues, please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with the details of what your were doing when this error occurred
-* **0x07** - This sector already contains data. Please make sure the sectors being written to are erased. If you are still facing issues, please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with the details of what your were doing when this error occurred.
-* **0x08** - You are running low on SRAM. Please optimise your program for better RAM usage
-* **0x09** - Unable to suspend/resume operation.
-* **0x0A** - Write Function has failed errorcheck.
-* **0x0B** - Check your wiring. Flash chip is non-responsive.
-* **0x0C** - This function is not supported by the flash memory hardware.
-* **0x0D** - Unable to enable 4-byte addressing.
-* **0x0E** - Unable to disable 4-byte addressing.
-* **0xFE** - Unknown error. Please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with the details of what your were doing when this error occurred
-
-
-###### How to get data off Flash memory via Serial
-(Works only for Unix based Operating Systems)
+Note: If you are unable to fix the error/s, please raise an issue [here](http://www.github.com/Marzogh/SPIMemory/issues) with the details of your flash chip and what you were doing when this error occurred. **Please follow the issue template that show up at the link**
+
+| Error code | Explanation |
+| :-----------: | ------------- |
+| **0x00** | Function executed successfully |
+| **0x01** | `*constructor_of_choice*.begin()` was not called in `void setup()` |
+| **0x02** | Unable to identify chip.
Is this chip officially supported? |
+| **0x03** | Unable to identify capacity.
Is this chip officially supported?
If not, please define a `CAPACITY` constant and include it in `flash.begin(CAPACITY)`. |
+| **0x04** | Chip is busy. Make sure all pins have been connected properly. |
+| **0x05** | Page overflow has been disabled and the address called exceeds the memory |
+| **0x06** | Unable to Enable Writing to chip.
Please make sure the HOLD & WRITEPROTECT pins are pulled up to VCC. |
+| **0x07** | This sector already contains data.
Please make sure the sectors being written to are erased. |
+| **0x08** | You are running low on RAM.
Please optimise your code for better RAM usage |
+| **0x09** | Unable to suspend/resume operation.
Please raise an issue. |
+| **0x0A** | Write Function has failed errorcheck.
Please raise an issue. |
+| **0x0B** | Check your wiring. Flash chip is non-responsive. |
+| **0x0C** | This function is not supported by the memory hardware. |
+| **0x0D** | Unable to enable 4-byte addressing.
Please raise an issue. |
+| **0x0E** | Unable to disable 4-byte addressing.
Please raise an issue. |
+| **0x0F** | The chip is currently powered down. |
+| **0x10** | The Flash chip does not support SFDP. |
+| **0x11** | Unable to read Erase Parameters from chip.
Reverting to library defaults. |
+| **0x12** | Unable to read erase times from flash memory.
Reverting to library defaults. |
+| **0x13** | Unable to read program times from flash memory.
Reverting to library defaults. |
+| **0xFE** | Unknown error.
Please raise an issue. |
- - Make sure you include code to let you dump entire flash memory/specific address' content to Serial (Refer to the code in the _TestFlash.h_ for details on how to do this)
- - Connect your Arduino board to the computer.
- - Open the Arduino IDE, the IDE's Serial Monitor, and an OSX POSIX terminal.
- - Type the following command into the terminal window. ```% tail -f /dev/tty.usbmodem1411 > FlashDump.txt``` Make sure to replace the _/dev/tty.usbmodem1411_ with the port your arduino is connected to. (You can find this in Tools --> Ports in Arduino IDE 1.6.x)
- - Then type the command to read all pages into the Serial console. If you use my code from the example file the command is ```read_all_pages```
- - Wait a few seconds before typing ```Ctrl+C``` to end the tail process
- - Check that you have actually received all the data by typing ```% cat FlashDump.txt```. This should output the entire text file into your terminal window.
+
diff --git a/extras/Changes.log b/extras/Changes.log
index cd9deec..c37c4a1 100644
--- a/extras/Changes.log
+++ b/extras/Changes.log
@@ -2,6 +2,28 @@
// SPIMemory Library //
// Changes log //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+// Version 3.3.0 //
+// Author: Prajwal Bhattaram //
+// 13.04.2018 //
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+Library now supports FRAM memory. Refer to the RAM section of the ReadMe file for more information
+
+Bugs squashed:
+--> Fixed a major bug in how SFDP data is used to calculate chip capacity. The previous version of the library returned a wrong value. This has now been fixed. Refer to comments in _getSFDPFlashParam(void) for further details.
+--> Fixes bug that causes ballooning of pagesize when SFDP is not read. This is because no default _pageSize value was set in this scenario. This has now been fixed.
+
+Enhancements:
+--> Now supports FRAM memory chips via the `SPIFram` constructor
+--> Changed Diagnostics output in _chipID() to match situation better.
+--> Fixed _chipID() to run more efficiently.
+
+New flash memory chips supported:
+--> GD25Q16C from Giga devices (Used on the Adafruit ItsyBitsy M0 Express)
+--> W25Q64JV from Winbond
+
+New FRAM memory chips supported:
+--> FM25W256 from Cypress
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Version 3.2.1 //
// Author: Prajwal Bhattaram //
// 13.04.2018 //
diff --git a/keywords.txt b/keywords.txt
index bc25ab5..87f6577 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -7,6 +7,7 @@
#######################################
SPIFlash KEYWORD1
+SPIFram KEYWORD1
SPIMemory KEYWORD1
#######################################
@@ -62,6 +63,7 @@ powerDown KEYWORD2
WINBOND_MANID LITERAL1
MICROCHIP_MANID LITERAL1
CYPRESS_MANID LITERAL1
+RAMTRON_FRAM_MANID LITERAL1
ADESTO_MANID LITERAL1
MICRON_MANID LITERAL1
NULLBYTE LITERAL1
diff --git a/library.properties b/library.properties
index c2b4978..f4aa52a 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
name=SPIMemory
-version=3.2.1
+version=3.3.0
author=Prajwal Bhattaram
maintainer=Prajwal Bhattaram
sentence=SPI Memory library for Arduino. (Formerly SPIFlash)
-paragraph=This library enables read, write, erase and power functions on number of compatible flash memory chips. Refer to change log for further information about this release. To download any version of this library pre v3.2.0 (pre name-change from SPIFlash please visit https://github.com/Marzogh/SPIMemory/releases?after=v3.2.0 )
+paragraph=This library enables read, write, erase and power functions on number of compatible flash and fram memory chips. Refer to change log for further information about this release. To download any version of this library pre v3.2.0 (pre name-change from SPIFlash please visit https://github.com/Marzogh/SPIMemory/releases?after=v3.2.0 )
category=Data Storage
url=https://github.com/Marzogh/SPIMemory
architectures=avr,sam,samd,esp8266,esp32,Simblee,stm32
diff --git a/src/DMASAM.cpp b/src/DMASAM.cpp
index 57bbcc3..1d59885 100644
--- a/src/DMASAM.cpp
+++ b/src/DMASAM.cpp
@@ -1,13 +1,12 @@
-/* Arduino SPIMemory Library v.2.6.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 30/09/2016
- * Modified by Prajwal Bhattaram - 14/04/2017
* Original code from @manitou48
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
diff --git a/src/DMASAM.h b/src/DMASAM.h
index bfade08..36fb077 100644
--- a/src/DMASAM.h
+++ b/src/DMASAM.h
@@ -1,12 +1,11 @@
-/* Arduino SPIMemory Library v.3.2.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/04/2018
- * Modified by Prajwal Bhattaram - 20/04/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp
index c96612d..43cfea4 100644
--- a/src/SPIFlash.cpp
+++ b/src/SPIFlash.cpp
@@ -1,13 +1,12 @@
-/* Arduino SPIMemory Library v.3.2.1
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
* Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 21/05/2018
+ * Modified by Prajwal Bhattaram - 11/08/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -82,6 +81,7 @@ bool SPIFlash::begin(uint32_t flashChipSize) {
bool retVal = _chipID(flashChipSize);
_endSPI();
chipPoweredDown = false;
+ _disableGlobalBlockProtect();
return retVal;
}
@@ -182,7 +182,7 @@ uint64_t SPIFlash::getUniqueID(void) {
//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.
+// This function can be called anytime - even if there is preexisting data on the flash chip. It will simply find the next empty address block for the data.
uint32_t SPIFlash::getAddress(uint16_t size) {
if (!_addressCheck(currentAddress, size)){
return false;
@@ -348,7 +348,49 @@ float SPIFlash::readFloat(uint32_t _addr, bool fastRead) {
// 2. outputString --> String variable to write the output to
// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true
bool SPIFlash::readStr(uint32_t _addr, String &data, bool fastRead) {
- return _read(_addr, data, sizeof(data), fastRead);
+ //return _read(_addr, data, sizeof(data), fastRead, _STRING_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+
+ uint32_t _sz = 0;
+
+ if (!_prep(READDATA, _addr, _sz)) {
+ return false;
+ }
+ else {
+ if (fastRead) {
+ _beginSPI(FASTREAD);
+ }
+ else {
+ _beginSPI(READDATA);
+ }
+ for (uint16_t i = 0; i < sizeof(_sz); i++) {
+ _sz |= (_nextByte(READ) << (8*i));
+ }
+ _endSPI();
+ }
+
+ char _inChar[_sz];
+
+ if (!_addressCheck((_addr + sizeof(_sz)), _sz) || !_notBusy()) {
+ return false;
+ }
+ if(fastRead) {
+ _beginSPI(FASTREAD);
+ }
+ else {
+ _beginSPI(READDATA);
+ }
+ _nextBuf(READDATA, (uint8_t*) &(*_inChar), _sz);
+ _endSPI();
+
+ data = String(_inChar);
+
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
}
// Writes a byte of data to a specific location in a page.
@@ -928,7 +970,105 @@ 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_);
+
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+
+ uint32_t _sz = (sizeof(char)*(data.length()+1));
+
+ char _outCharArray[_sz];
+ data.toCharArray(_outCharArray, _sz);
+
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(_sz)) || !_notPrevWritten(_addr, sizeof(_sz)+_sz) || !_notBusy() || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(_sz); i++) {
+ _nextByte(WRITE, _sz >> (8*i));
+ }
+ CHIP_DESELECT
+ _endSPI();
+
+ if(!_addressCheck(_addr+sizeof(_sz), _sz) || !_notBusy() || !_writeEnable()) {
+ return false;
+ }
+ uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
+
+ if (_sz <= maxBytes) {
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ //_nextBuf(PAGEPROG, &_outCharArray[0], _sz);
+ for (uint16_t i = 0; i < _sz; ++i) {
+ _nextByte(WRITE, _outCharArray[i]);
+ }
+ CHIP_DESELECT
+ }
+ else {
+ uint16_t length = _sz;
+ uint16_t writeBufSz;
+ uint16_t data_offset = 0;
+
+ do {
+ writeBufSz = (length<=maxBytes) ? length : maxBytes;
+
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ for (uint16_t i = 0; i < writeBufSz; ++i) {
+ _nextByte(WRITE, _outCharArray[data_offset + i]);
+ }
+ CHIP_DESELECT
+
+ _currentAddress += writeBufSz;
+ data_offset += writeBufSz;
+ length -= writeBufSz;
+ maxBytes = 256; // Now we can do up to 256 bytes per loop
+
+ if(!_notBusy() || !_writeEnable()){
+ return false;
+ }
+
+ } while (length > 0);
+ }
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ if (!_notBusy()) {
+ return false;
+ }
+ _currentAddress = (_addr + sizeof(_sz));
+ char _inCharArray[_sz];
+
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < _sz; i++) {
+ _inCharArray[i] = _nextByte(READ);
+ }
+ _endSPI();
+
+ for (uint8_t i = 0; i < _sz; i++) {
+ if (_inCharArray[i] != _outCharArray[i]) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
}
diff --git a/src/SPIFlash.h b/src/SPIFlash.h
index 7204abf..b873b27 100644
--- a/src/SPIFlash.h
+++ b/src/SPIFlash.h
@@ -1,13 +1,12 @@
-/* Arduino SPIMemory Library v.3.2.1
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
* Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 21/05/2018
+ * Modified by Prajwal Bhattaram - 11/08/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -163,7 +162,8 @@ class SPIFlash {
gpio_t csPin;
#endif
volatile uint8_t *cs_port;
- bool pageOverflow, SPIBusState;
+ bool pageOverflow;
+ bool SPIBusState = false;
bool chipPoweredDown = false;
bool address4ByteEnabled = false;
bool _loopedOver = false;
@@ -193,14 +193,14 @@ class SPIFlash {
uint32_t _addressOverflow = false;
uint32_t _BasicParamTableAddr, _SectorMapParamTableAddr, _byteFirstPrgmTime, _byteAddnlPrgmTime, _pagePrgmTime;
uint8_t _uniqueID[8];
- const uint8_t _capID[16] =
- {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B, 0x00, 0x01, 0x13, 0x37};
+ const uint8_t _capID[18] =
+ {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x41, 0x42, 0x43, 0x4B, 0x00, 0x01, 0x13, 0x37};
- const uint32_t _memSize[16] =
- {KB(64), KB(128), KB(256), KB(512), MB(1), MB(2), MB(4), MB(8), MB(16), MB(32), MB(8), MB(8), KB(256), KB(512), MB(4), KB(512)};
+ const uint32_t _memSize[18] =
+ {KB(64), KB(128), KB(256), KB(512), MB(1), MB(2), MB(4), MB(8), MB(16), MB(32), MB(2), MB(4), MB(8), MB(8), KB(256), KB(512), MB(4), KB(512)};
// To understand the _memSize definitions check defines.h
- const uint8_t _supportedManID[7] = {WINBOND_MANID, MICROCHIP_MANID, CYPRESS_MANID, ADESTO_MANID, MICRON_MANID, ON_MANID, AMIC_MANID};
+ const uint8_t _supportedManID[8] = {WINBOND_MANID, MICROCHIP_MANID, CYPRESS_MANID, ADESTO_MANID, MICRON_MANID, ON_MANID, GIGA_MANID, AMIC_MANID};
const uint8_t _altChipEraseReq[3] = {A25L512, M25P40, SST26};
};
@@ -312,7 +312,11 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_
do {
writeBufSz = (length<=maxBytes) ? length : maxBytes;
-
+ if(_currentAddress % SPI_PAGESIZE==0){
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ }
for (uint16_t i = 0; i < writeBufSz; ++i) {
_nextByte(WRITE, *p++);
}
@@ -337,6 +341,9 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_
if (!errorCheck) {
_endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
return true;
}
else {
@@ -367,6 +374,7 @@ template bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz,
uint8_t* p = (uint8_t*)(void*)&value;
if (_dataType == _STRING_) {
+ _sz++;
char _inChar[_sz];
_beginSPI(READDATA);
_nextBuf(READDATA, (uint8_t*) &(*_inChar), _sz);
@@ -378,12 +386,11 @@ template bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz,
else {
CHIP_SELECT
if (fastRead) {
- _nextByte(WRITE, FASTREAD);
+ _beginSPI(FASTREAD);
}
else {
- _nextByte(WRITE, READDATA);
+ _beginSPI(READDATA);
}
- _transferAddress();
for (uint16_t i = 0; i < _sz; i++) {
*p++ =_nextByte(READ);
}
diff --git a/src/SPIFlashIO.cpp b/src/SPIFlashIO.cpp
index ba57863..3807c36 100644
--- a/src/SPIFlashIO.cpp
+++ b/src/SPIFlashIO.cpp
@@ -1,13 +1,12 @@
-/* Arduino SPIMemory Library v.3.2.1
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
* Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 21/05/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -531,6 +530,7 @@
kb256Erase.supported = false;
chipErase.opcode = CHIPERASE;
chipErase.time = kb64Erase.time * 100L;
+ _pageSize = SPI_PAGESIZE;
_getJedecId();
@@ -559,7 +559,7 @@
if (_chip.supportedMan) {
#ifdef RUNDIAGNOSTIC
- Serial.println(F("No Chip size defined by user. Automated identification initiated."));
+ Serial.println(F("No Chip size defined by user. Checking library support."));
#endif
//Identify capacity
for (uint8_t j = 0; j < sizeof(_capID); j++) {
@@ -574,8 +574,17 @@
}
}
else {
- _troubleshoot(UNKNOWNCHIP); //Error code for unidentified capacity
- return false;
+ if (_chip.sfdpAvailable) {
+ #ifdef RUNDIAGNOSTIC
+ Serial.println("SFDP ID finished.");
+ #endif
+ return true;
+ }
+ else {
+ _troubleshoot(UNKNOWNCHIP); //Error code for unidentified capacity
+ return false;
+ }
+
}
if (!_chip.capacity) {
diff --git a/src/SPIFlashSFDP.cpp b/src/SPIFlashSFDP.cpp
index 8b473eb..eaeab79 100644
--- a/src/SPIFlashSFDP.cpp
+++ b/src/SPIFlashSFDP.cpp
@@ -1,13 +1,11 @@
-/* Arduino SPIMemory Library v.3.1.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
- * Created by Prajwal Bhattaram - 19/05/2015
- * Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 24/02/2018
+ * Created by Prajwal Bhattaram - 18/04/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -327,19 +325,17 @@ bool SPIFlash::_getSFDPFlashParam(void) {
}
_noOfBasicParamDwords = _getSFDPbyte(SFDP_BASIC_PARAM_TABLE_HDR_ADDR, SFDP_PARAM_TABLE_LENGTH_DWORD, SFDP_PARAM_TABLE_LENGTH_BYTE);
_BasicParamTableAddr = _getSFDPTableAddr(SFDP_BASIC_PARAM_TABLE_NO);
+
// Calculate chip capacity
+
_chip.capacity = _getSFDPdword(_BasicParamTableAddr, SFDP_MEMORY_DENSITY_DWORD);
- uint8_t _multiplier = Highest(_chip.capacity); //----
- Highest(_chip.capacity) = 0x00; // |
- if (_multiplier <= 0x0F) { // |
- _chip.capacity = (_chip.capacity + 1) * (_multiplier + 1); // |---> This section calculates the chip capacity as
- } // |---> detailed in JESD216B
- else { // |
- _chip.capacity = ((_chip.capacity + 1) * 2); // |
- } //----
- #ifdef RUNDIAGNOSTIC
- Serial.println("Chip identified using sfdp. Most of this chip's functions are supported by the library.");
- #endif
+ if (bitIsSet(Highest(_chip.capacity), 7)) { // If bit 31 (bit 7 of byte 3) is set, then the density is double the value read in bits from 30:0 (Refer to Page 16 of JESD216B)
+ clearBit(Highest(_chip.capacity), 7); // Clear bit 31
+ _chip.capacity*=2;
+ }
+ // Else _chip.capacity is the value as read in bits.
+
+ _chip.capacity = (_chip.capacity/8) + 1; // Since the value read in is in bits, convert it to bytes here (1 is added because the number of bits is zero based - i.e. if there are 8 bytes, then they are numbered 0 -> 7)
// Get Erase Parameters if available
_getSFDPEraseParam();
@@ -350,6 +346,9 @@ bool SPIFlash::_getSFDPFlashParam(void) {
//Serial.print("dWord 9: 0x");
//Serial.println(_getSFDPdword(_BasicParamTableAddr, DWORD(9)), HEX);
+ #ifdef RUNDIAGNOSTIC
+ Serial.println("Chip identified using sfdp. Most of this chip's functions are supported by the library.");
+ #endif
return true;
}
diff --git a/src/SPIFram.cpp b/src/SPIFram.cpp
new file mode 100644
index 0000000..dd0959f
--- /dev/null
+++ b/src/SPIFram.cpp
@@ -0,0 +1,980 @@
+/* Arduino SPIMemory Library v.3.3.0
+ * Copyright (C) 2017 by Prajwal Bhattaram
+ * Created by Prajwal Bhattaram - 19/06/2018
+ *
+ * This file is part of the Arduino SPIMemory Library. This library is for
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
+ * suspending and resuming programming/erase and powering down for low power operation.
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License v3.0
+ * along with the Arduino SPIMemory Library. If not, see
+ * .
+ */
+
+#include "SPIFram.h"
+
+// Constructor
+//If board has multiple SPI interfaces, this constructor lets the user choose between them
+// Adding Low level HAL API to initialize the Chip select pinMode on RTL8195A - @boseji 2nd March 2017
+#if defined (ARDUINO_ARCH_AVR)
+SPIFram::SPIFram(uint8_t cs) {
+ csPin = cs;
+ cs_mask = digitalPinToBitMask(csPin);
+ pinMode(csPin, OUTPUT);
+ CHIP_DESELECT
+}
+#elif defined (ARDUINO_ARCH_SAMD) || defined (ARCH_STM32)
+SPIFram::SPIFram(uint8_t cs, SPIClass *spiinterface) {
+ _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI
+ csPin = cs;
+ pinMode(csPin, OUTPUT);
+ CHIP_DESELECT
+}
+#elif defined (BOARD_RTL8195A)
+SPIFram::SPIFram(PinName cs) {
+ gpio_init(&csPin, cs);
+ gpio_dir(&csPin, PIN_OUTPUT);
+ gpio_mode(&csPin, PullNone);
+ gpio_write(&csPin, 1);
+ CHIP_DESELECT
+}
+#else
+SPIFram::SPIFram(uint8_t cs) {
+ csPin = cs;
+ pinMode(csPin, OUTPUT);
+ CHIP_DESELECT
+}
+#endif
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+// Public functions used for read, write and erase operations //
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+
+//Identifies chip and establishes parameters
+bool SPIFram::begin(uint32_t flashChipSize) {
+#ifdef RUNDIAGNOSTIC
+ Serial.println("Chip Diagnostics initiated.");
+ Serial.println();
+#endif
+#ifdef HIGHSPEED
+ Serial.println("Highspeed mode initiated.");
+ Serial.println();
+#endif
+ BEGIN_SPI
+#ifdef SPI_HAS_TRANSACTION
+ //Define the settings to be used by the SPI bus
+ _settings = SPISettings(SPI_CLK, MSBFIRST, SPI_MODE0);
+#endif
+ bool retVal = _chipID(flashChipSize);
+ _endSPI();
+ chipPoweredDown = false;
+ return retVal;
+}
+
+//Allows the setting of a custom clock speed for the SPI bus to communicate with the chip.
+//Only works if the SPI library in use supports SPI Transactions
+#ifdef SPI_HAS_TRANSACTION
+void SPIFram::setClock(uint32_t clockSpeed) {
+ _settings = SPISettings(clockSpeed, MSBFIRST, SPI_MODE0);
+}
+#endif
+
+uint8_t SPIFram::error(bool _verbosity) {
+ if (!_verbosity) {
+ return diagnostics.errorcode;
+ }
+ else {
+ _troubleshoot(diagnostics.errorcode, PRINTOVERRIDE);
+ return diagnostics.errorcode;
+ }
+}
+
+//Returns capacity of chip
+uint32_t SPIFram::getCapacity(void) {
+ return _chip.capacity;
+}
+
+//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 SPIFram.h
+float SPIFram::functionRunTime(void) {
+#ifdef RUNDIAGNOSTIC
+ return _spifuncruntime;
+#else
+ return 0;
+#endif
+}
+
+//Returns the library version as three bytes
+bool SPIFram::libver(uint8_t *b1, uint8_t *b2, uint8_t *b3) {
+ *b1 = LIBVER;
+ *b2 = LIBSUBVER;
+ *b3 = BUGFIXVER;
+ return true;
+}
+
+//Returns JEDEC ID which is returned as a 32 bit int
+uint32_t SPIFram::getJEDECID(void) {
+ uint32_t id = 0;
+ id = _chip.manufacturerID;
+ id = (id << 8)|(_chip.devID1 << 0);
+ id = (id << 8)|(_chip.devID2 << 0);
+ return id;
+}
+
+// Returns a 64-bit Unique ID that is unique to each flash memory chip
+uint64_t SPIFram::getUniqueID(void) {
+ _beginSPI(FRAMSERNO);
+ for (uint8_t i = 0; i < 4; i++) {
+ _nextByte(WRITE, DUMMYBYTE);
+ }
+
+ for (uint8_t i = 0; i < 8; i++) {
+ _uniqueID[i] = _nextByte(READ);
+ }
+ CHIP_DESELECT
+
+ long long _uid = 0;
+ for (uint8_t i = 0; i < 8; i++) {
+ _uid += _uniqueID[i];
+ _uid = _uid << 8;
+ }
+ return _uid;
+}
+
+//Gets the next available address for use.
+// Takes the size of the data as an argument and returns a 32-bit address
+// This function can be called anytime - even if there is preexisting data on the flash chip. It will simply find the next empty address block for the data.
+uint32_t SPIFram::getAddress(uint16_t size) {
+ if (!_addressCheck(currentAddress, size)){
+ return false;
+ }
+ while (!_notPrevWritten(currentAddress, size)) {
+ currentAddress+=size;
+ _currentAddress = currentAddress;
+ if (_currentAddress >= _chip.capacity) {
+ if (_loopedOver) {
+ return false;
+ }
+ #ifdef DISABLEOVERFLOW
+ _troubleshoot(OUTOFBOUNDS);
+ return false; // At end of memory - (!pageOverflow)
+ #else
+ currentAddress = 0x00;// At end of memory - (pageOverflow)
+ _loopedOver = true;
+ #endif
+ }
+ }
+ uint32_t _addr = currentAddress;
+ currentAddress+=size;
+ return _addr;
+}
+
+//Function for returning the size of the string (only to be used for the getAddress() function)
+uint16_t SPIFram::sizeofStr(String &inputStr) {
+ uint16_t size;
+ size = (sizeof(char)*(inputStr.length()+1));
+ size+=sizeof(inputStr.length()+1);
+
+ return size;
+}
+
+// Reads a byte of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+uint8_t SPIFram::readByte(uint32_t _addr, bool fastRead) {
+ uint8_t data = 0;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads a char of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+int8_t SPIFram::readChar(uint32_t _addr, bool fastRead) {
+ int8_t data = 0;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads an array of bytes starting from a specific location in a page.
+// Takes four arguments
+// 1. _addr --> Any address from 0 to capacity
+// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated
+// 3. bufferSize --> The size of the buffer - in number of bytes.
+// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true
+
+bool SPIFram::readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, bufferSize)) {
+ return false;
+ }
+ if(fastRead) {
+ _beginSPI(FASTREAD);
+ }
+ else {
+ _beginSPI(READDATA);
+ }
+ _nextBuf(READDATA, &(*data_buffer), bufferSize);
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+}
+
+// Reads an array of chars starting from a specific location in a page..
+// Takes four arguments
+// 1. _addr --> Any address from 0 to capacity
+// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated
+// 3. bufferSize --> The size of the buffer - in number of bytes.
+// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true
+bool SPIFram::readCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool fastRead) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, bufferSize)) {
+ return false;
+ }
+ if(fastRead) {
+ _beginSPI(FASTREAD);
+ }
+ else {
+ _beginSPI(READDATA);
+ }
+ _nextBuf(READDATA, (uint8_t*) &(*data_buffer), bufferSize);
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+}
+
+// Reads an unsigned int of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+uint16_t SPIFram::readWord(uint32_t _addr, bool fastRead) {
+ uint16_t data;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads a signed int of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+int16_t SPIFram::readShort(uint32_t _addr, bool fastRead) {
+ int16_t data;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads an unsigned long of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+uint32_t SPIFram::readULong(uint32_t _addr, bool fastRead) {
+ uint32_t data;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads a signed long of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+int32_t SPIFram::readLong(uint32_t _addr, bool fastRead) {
+ int32_t data;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads a float of data from a specific location in a page.
+// Takes two arguments -
+// 1. _addr --> Any address from 0 to capacity
+// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true
+float SPIFram::readFloat(uint32_t _addr, bool fastRead) {
+ float data;
+ _read(_addr, data, sizeof(data), fastRead);
+ return data;
+}
+
+// Reads a string from a specific location on a page.
+// Takes three arguments
+// 1. _addr --> Any address from 0 to capacity
+// 2. outputString --> String variable to write the output to
+// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true
+bool SPIFram::readStr(uint32_t _addr, String &data, bool fastRead) {
+ return _read(_addr, data, sizeof(data), fastRead);
+}
+
+// Writes a byte of data to a specific location in a page.
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One byte to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _BYTE_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ _nextByte(WRITE, data);
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ if (data != _nextByte(READ)) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ else {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ }
+ return true;
+}
+
+// Writes a char of data to a specific location in a page.
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One char to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeChar(uint32_t _addr, int8_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _CHAR_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ _nextByte(WRITE, data);
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ if (data != (int8_t)_nextByte(READ)) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ else {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ }
+ return true;
+}
+
+// Writes an array of bytes starting from a specific location in a page.
+// Takes four arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data_buffer --> The pointer to the array of bytes be written to a particular location on a page
+// 3. bufferSize --> Size of the array of bytes - in number of bytes
+// 4. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, bufferSize) || !_notPrevWritten(_addr, bufferSize) || !_writeEnable()) {
+ return false;
+ }
+ uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
+
+ if (bufferSize <= maxBytes) {
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ //_nextBuf(PAGEPROG, &data_buffer[0], bufferSize);
+ for (uint16_t i = 0; i < bufferSize; ++i) {
+ _nextByte(WRITE, data_buffer[i]);
+ }
+ CHIP_DESELECT
+ }
+ else {
+ uint16_t length = bufferSize;
+ uint16_t writeBufSz;
+ uint16_t data_offset = 0;
+
+ do {
+ writeBufSz = (length<=maxBytes) ? length : maxBytes;
+
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ //_nextBuf(PAGEPROG, &data_buffer[data_offset], writeBufSz);
+ for (uint16_t i = 0; i < writeBufSz; ++i) {
+ _nextByte(WRITE, data_buffer[data_offset + i]);
+ }
+ CHIP_DESELECT
+
+ _currentAddress += writeBufSz;
+ data_offset += writeBufSz;
+ length -= writeBufSz;
+ maxBytes = 256; // Now we can do up to 256 bytes per loop
+
+ if(!_writeEnable()){
+ return false;
+ }
+
+ } while (length > 0);
+ }
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint16_t j = 0; j < bufferSize; j++) {
+ if (_nextByte(READ) != data_buffer[j]) {
+ return false;
+ }
+ }
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+}
+
+// Writes an array of bytes starting from a specific location in a page.
+// Takes four arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data_buffer --> The pointer to the array of chars be written to a particular location on a page
+// 3. bufferSize --> Size of the array of chars - in number of bytes
+// 4. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, bufferSize) || !_notPrevWritten(_addr, bufferSize) || !_writeEnable()) {
+ return false;
+ }
+ uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
+
+ if (bufferSize <= maxBytes) {
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ //_nextBuf(PAGEPROG, &data_buffer[0], bufferSize);
+ for (uint16_t i = 0; i < bufferSize; ++i) {
+ _nextByte(WRITE, data_buffer[i]);
+ }
+ CHIP_DESELECT
+ }
+ else {
+ uint16_t length = bufferSize;
+ uint16_t writeBufSz;
+ uint16_t data_offset = 0;
+
+ do {
+ writeBufSz = (length<=maxBytes) ? length : maxBytes;
+
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+ for (uint16_t i = 0; i < writeBufSz; ++i) {
+ _nextByte(WRITE, data_buffer[data_offset + i]);
+ }
+ CHIP_DESELECT
+
+ _currentAddress += writeBufSz;
+ data_offset += writeBufSz;
+ length -= writeBufSz;
+ maxBytes = 256; // Now we can do up to 256 bytes per loop
+
+ if(!_writeEnable()){
+ return false;
+ }
+
+ } while (length > 0);
+ }
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint16_t j = 0; j < bufferSize; j++) {
+ if ((char)_nextByte(READ) != data_buffer[j]) {
+ return false;
+ }
+ }
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+}
+
+// Writes an unsigned int as two bytes starting from a specific location in a page.
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One word to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _WORD_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ _nextByte(WRITE, data >> (8*i));
+ }
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ union {
+ uint8_t byte[2];
+ uint16_t word;
+ } dataIn;
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ dataIn.byte[i] = _nextByte(READ);
+ }
+ _endSPI();
+ if (dataIn.word != data) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
+}
+
+// Writes a signed int as two bytes starting from a specific location in a page
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One short to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeShort(uint32_t _addr, int16_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _SHORT_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ _nextByte(WRITE, data >> (8*i));
+ }
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ union {
+ uint8_t byte[2];
+ int16_t short_;
+ } dataIn;
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ dataIn.byte[i] = _nextByte(READ);
+ }
+ _endSPI();
+ if (dataIn.short_ != data) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
+}
+
+// Writes an unsigned long as four bytes starting from a specific location in a page.
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One unsigned long to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _ULONG_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ _nextByte(WRITE, data >> (8*i));
+ }
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ union {
+ uint8_t byte[4];
+ uint32_t uLong;
+ } dataIn;
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ dataIn.byte[i] = _nextByte(READ);
+ }
+ _endSPI();
+ if (dataIn.uLong != data) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
+}
+
+// Writes a signed long as four bytes starting from a specific location in a page
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One signed long to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeLong(uint32_t _addr, int32_t data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _LONG_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ _nextByte(WRITE, data >> (8*i));
+ }
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ union {
+ uint8_t byte[4];
+ int32_t Long;
+ } dataIn;
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ dataIn.byte[i] = _nextByte(READ);
+ }
+ _endSPI();
+ if (dataIn.Long != data) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
+}
+
+// Writes a float as four bytes starting from a specific location in a page
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One float to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeFloat(uint32_t _addr, float data, bool errorCheck) {
+ //return _write(_addr, data, sizeof(data), errorCheck, _FLOAT_);
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) {
+ return false;
+ }
+
+ union {
+ float Float;
+ uint8_t byte[sizeof(float)];
+ } dataOut;
+ dataOut.Float = data;
+
+ _beginSPI(PAGEPROG);
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ _nextByte(WRITE, dataOut.byte[i]);
+ }
+ CHIP_DESELECT
+
+ if (!errorCheck) {
+ _endSPI();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+ }
+ else {
+ union {
+ uint8_t byte[4];
+ float Float;
+ } dataIn;
+ _currentAddress = _addr;
+ CHIP_SELECT
+ _nextByte(WRITE, READDATA);
+ _transferAddress();
+ for (uint8_t i = 0; i < sizeof(data); i++) {
+ dataIn.byte[i] = _nextByte(READ);
+ }
+ _endSPI();
+ if (dataIn.Float != data) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return false;
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ }
+ return true;
+}
+
+// Writes a string to a specific location on a page
+// Takes three arguments -
+// 1. _addr --> Any address - from 0 to capacity
+// 2. data --> One String to be written to a particular location on a page
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::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 SPIFram::eraseSection(uint32_t _addr, uint32_t _sz) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+
+ if (!SPIBusState) {
+ _startSPIBus();
+ }
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _nextByte(WRITE, Hi(_addr));
+ _nextByte(WRITE, Lo(_addr));
+ for (uint32_t i = 0; i < _sz; i++) {
+ _nextByte(WRITE, NULLBYTE);
+ }
+ CHIP_DESELECT
+
+ //_writeDisable();
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+
+ return true;
+}
+
+//Erases whole chip. Think twice before using.
+bool SPIFram::eraseChip(void) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+
+ uint32_t _startingAddress = 0x00;
+ if (!SPIBusState) {
+ _startSPIBus();
+ }
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _nextByte(WRITE, Hi(_startingAddress));
+ _nextByte(WRITE, Lo(_startingAddress));
+ for (uint32_t i = 0; i < _chip.capacity; i++) {
+ _nextByte(WRITE, NULLBYTE);
+ }
+ CHIP_DESELECT
+
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+
+}
+
+//Puts device in low power state. Good for battery powered operations.
+//In powerDown() the chip will only respond to powerUp()
+bool SPIFram::powerDown(void) {
+#ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+#endif
+
+ _beginSPI(POWERDOWN);
+ _endSPI();
+
+ _delay_us(5);
+
+#ifdef RUNDIAGNOSTIC
+ chipPoweredDown = true;
+ _spifuncruntime = micros() - _spifuncruntime;
+#else
+ chipPoweredDown = true;
+#endif
+
+ return chipPoweredDown;
+}
+
+//Wakes chip from low power state.
+bool SPIFram::powerUp(void) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+ _beginSPI(READDATA);
+ _endSPI();
+ _delay_us(400); //Max release enable time according to the Datasheet
+
+ if (_writeEnable(false)) {
+ _writeDisable();
+ chipPoweredDown = false;
+ }
+ else {
+ chipPoweredDown = true;
+ }
+
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return !chipPoweredDown;
+}
+
+/* Note: _writeDisable() is not required at the end of any function that writes to the Flash memory because the Write Enable Latch (WEL) flag is cleared to 0 i.e. to write disable state upon the following conditions being completed:
+Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register, Erase Security Register and Program Security register */
diff --git a/src/SPIFram.h b/src/SPIFram.h
new file mode 100644
index 0000000..97fdbe5
--- /dev/null
+++ b/src/SPIFram.h
@@ -0,0 +1,357 @@
+/* Arduino SPIMemory Library v.3.3.0
+ * Copyright (C) 2017 by Prajwal Bhattaram
+ * Created by Prajwal Bhattaram - 19/06/2018
+ *
+ * This file is part of the Arduino SPIMemory Library. This library is for
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
+ * suspending and resuming programming/erase and powering down for low power operation.
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License v3.0
+ * along with the Arduino SPIMemory Library. If not, see
+ * .
+ */
+
+#ifndef SPIFRAM_H
+#define SPIFRAM_H
+
+#include "SPIMemory.h"
+
+//#define OVERWRITE
+
+class SPIFram {
+public:
+ //------------------------------------ Constructor ------------------------------------//
+ //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17
+ #if defined (ARDUINO_ARCH_SAMD) || defined(ARCH_STM32)
+ SPIFram(uint8_t cs = CS, SPIClass *spiinterface=&SPI);
+ #elif defined (BOARD_RTL8195A)
+ SPIFram(PinName cs = CS);
+ #else
+ SPIFram(uint8_t cs = CS);
+ #endif
+ //----------------------------- Initial / Chip Functions ------------------------------//
+ bool begin(uint32_t flashChipSize = 0);
+ void setClock(uint32_t clockSpeed);
+ bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3);
+ uint8_t error(bool verbosity = false);
+ uint16_t getManID(void);
+ uint32_t getJEDECID(void);
+ uint64_t getUniqueID(void);
+ uint32_t getAddress(uint16_t size);
+ uint16_t sizeofStr(String &inputStr);
+ uint32_t getCapacity(void);
+ float functionRunTime(void);
+ //-------------------------------- Write / Read Bytes ---------------------------------//
+ bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true);
+ uint8_t readByte(uint32_t _addr, bool fastRead = false);
+ //----------------------------- Write / Read Byte Arrays ------------------------------//
+ bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck = true);
+ bool readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead = false);
+ //-------------------------------- Write / Read Chars ---------------------------------//
+ bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true);
+ int8_t readChar(uint32_t _addr, bool fastRead = false);
+ //------------------------------ Write / Read Char Arrays -----------------------------//
+ bool writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck = true);
+ bool readCharArray(uint32_t _addr, char *data_buffer, size_t buffer_size, bool fastRead = false);
+ //-------------------------------- Write / Read Shorts --------------------------------//
+ bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true);
+ int16_t readShort(uint32_t _addr, bool fastRead = false);
+ //-------------------------------- Write / Read Words ---------------------------------//
+ bool writeWord(uint32_t _addr, uint16_t data, bool errorCheck = true);
+ uint16_t readWord(uint32_t _addr, bool fastRead = false);
+ //-------------------------------- Write / Read Longs ---------------------------------//
+ bool writeLong(uint32_t _addr, int32_t data, bool errorCheck = true);
+ int32_t readLong(uint32_t _addr, bool fastRead = false);
+ //--------------------------- Write / Read Unsigned Longs -----------------------------//
+ bool writeULong(uint32_t _addr, uint32_t data, bool errorCheck = true);
+ uint32_t readULong(uint32_t _addr, bool fastRead = false);
+ //-------------------------------- Write / Read Floats --------------------------------//
+ bool writeFloat(uint32_t _addr, float data, bool errorCheck = true);
+ float readFloat(uint32_t _addr, bool fastRead = false);
+ //-------------------------------- Write / Read Strings -------------------------------//
+ bool writeStr(uint32_t _addr, String &data, bool errorCheck = true);
+ bool readStr(uint32_t _addr, String &data, bool fastRead = false);
+ //------------------------------- Write / Read Anything -------------------------------//
+
+ 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 eraseChip(void);
+ //-------------------------------- Power functions ------------------------------------//
+ bool powerDown(void);
+ bool powerUp(void);
+ //-------------------------- Public Arduino Due Functions -----------------------------//
+//#if defined (ARDUINO_ARCH_SAM)
+ //uint32_t freeRAM(void);
+//#endif
+ //------------------------------- Public variables ------------------------------------//
+
+private:
+ //------------------------------- Private functions -----------------------------------//
+ unsigned _createMask(unsigned a, unsigned b);
+ void _troubleshoot(uint8_t _code, bool printoverride = false);
+ void _endSPI(void);
+ bool _disableGlobalBlockProtect(void);
+ bool _isChipPoweredDown(void);
+ bool _prep(uint32_t _addr, uint32_t size = 0);
+ bool _startSPIBus(void);
+ bool _beginSPI(uint8_t opcode);
+ bool _noSuspend(void);
+ bool _notPrevWritten(uint32_t _addr, uint32_t size = 1);
+ bool _writeEnable(bool _troubleshootEnable = true);
+ bool _writeDisable(void);
+ bool _getJedecId(void);
+ bool _chipID(uint32_t flashChipSize = 0);
+ bool _transferAddress(void);
+ bool _addressCheck(uint32_t _addr, uint32_t size = 1);
+ uint8_t _nextByte(char IOType, uint8_t data = NULLBYTE);
+ uint16_t _nextInt(uint16_t = NULLINT);
+ void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size);
+ uint8_t _readStat1(void);
+ 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, uint8_t _dataType = 0x00);
+ //-------------------------------- Private variables ----------------------------------//
+ #ifdef SPI_HAS_TRANSACTION
+ SPISettings _settings;
+ #endif
+ //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.)
+ SPIClass *_spi;
+ #if !defined (BOARD_RTL8195A)
+ uint8_t csPin;
+ #else
+ // Object declaration for the GPIO HAL type for csPin - @boseji 02.03.17
+ gpio_t csPin;
+ #endif
+ volatile uint8_t *cs_port;
+ bool pageOverflow;
+ bool chipPoweredDown = false;
+ bool SPIBusState = false;
+ bool _loopedOver = false;
+ uint8_t cs_mask, errorcode, stat1, stat2, stat3, _SPCR, _SPSR, _a0, _a1, _a2;
+ char READ = 'R';
+ char WRITE = 'W';
+ float _spifuncruntime = 0;
+ uint32_t _chipCapacity;
+ struct chipID {
+ bool supported;
+ bool supportedMan;
+ uint8_t manufacturerID;
+ uint8_t devID1;
+ uint8_t devID2;
+ uint32_t capacity;
+ };
+ chipID _chip;
+ uint32_t currentAddress, _currentAddress = 0;
+ uint32_t _addressOverflow = false;
+ uint8_t _uniqueID[8];
+
+ const uint8_t _supportedManID[1] = {RAMTRON_FRAM_MANID};
+};
+
+//--------------------------------- Public Templates ------------------------------------//
+
+// Writes any type of data to a specific location in the flash memory.
+// Takes three arguments -
+// 1. _addr --> Any address from 0 to maxAddress
+// 2. T& value --> Variable to write
+// 3. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::writeAnything(uint32_t _addr, const T& data, bool errorCheck) {
+ return _write(_addr, data, sizeof(data), errorCheck, _STRUCT_);
+}
+
+// Reads any type of data from a specific location in the flash memory.
+// Takes three arguments -
+// 1. _addr --> Any address from 0 to maxAddress
+// 2. T& value --> Variable to return data into
+// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true
+template bool SPIFram::readAnything(uint32_t _addr, T& data, bool fastRead) {
+ return _read(_addr, data, sizeof(data), fastRead);
+}
+
+//---------------------------------- Private Templates ----------------------------------//
+
+template bool SPIFram::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType) {
+ if (!_addressCheck(_addr, _sz)) {
+ return false;
+ }
+ const uint8_t* p = (const uint8_t*)(const void*)&value;
+ /*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(0x0A); //0x0A is 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(0x0A); //0x0A is ERRORCHKFAIL
+ _endSPI();
+ return false;
+ }
+ }
+ _endSPI();
+ //}
+ return true;
+}
+
+// Writes any type of data to a specific location in the flash memory.
+// Takes four arguments -
+// 1. _addr --> Any address from 0 to maxAddress
+// 2. T& value --> Variable to write
+// 3. _sz --> Size of variable in bytes (1 byte = 8 bits)
+// 4. errorCheck --> Turned on by default. Checks for writing errors
+// 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 SPIFram::_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(_isChipPoweredDown() || !_addressCheck(_addrIn, _sz) || !_notPrevWritten(_addrIn, _sz) || !_writeEnable()) {
+ 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);
+ uint32_t length = _sz;
+ uint16_t maxBytes = SPI_PAGESIZE-(_addrIn % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
+
+ if (!SPIBusState) {
+ _startSPIBus();
+ }
+ CHIP_SELECT
+ _nextByte(WRITE, PAGEPROG);
+ _transferAddress();
+
+ if (maxBytes > length) {
+ for (uint16_t i = 0; i < length; ++i) {
+ _nextByte(WRITE, *p++);
+ }
+ CHIP_DESELECT
+ }
+ else {
+ uint32_t writeBufSz;
+ uint16_t data_offset = 0;
+
+ do {
+ writeBufSz = (length<=maxBytes) ? length : maxBytes;
+
+ for (uint16_t i = 0; i < writeBufSz; ++i) {
+ _nextByte(WRITE, *p++);
+ }
+ CHIP_DESELECT
+ if (!_addressOverflow) {
+ _currentAddress += writeBufSz;
+ }
+ else {
+ if (data_offset >= _addressOverflow) {
+ _currentAddress = 0x00;
+ _addressOverflow = false;
+ }
+ }
+ data_offset += writeBufSz;
+ length -= writeBufSz;
+ maxBytes = SPI_PAGESIZE; // Now we can do up to 256 bytes per loop
+ if(!_writeEnable()) {
+ return false;
+ }
+ } while (length > 0);
+ }
+
+ if (!errorCheck) {
+ _endSPI();
+ return true;
+ }
+ else {
+ //Serial.print(F("Address sent to error check: "));
+ //Serial.println(_addr);
+ _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.
+// Takes four arguments -
+// 1. _addr --> Any address from 0 to maxAddress
+// 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 SPIFram::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead, uint8_t _dataType) {
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros();
+ #endif
+
+ if(_isChipPoweredDown() || !_addressCheck(_addr, _sz)) {
+ return false;
+ }
+ else {
+ uint8_t* p = (uint8_t*)(void*)&value;
+
+ 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 {
+ CHIP_SELECT
+ if (fastRead) {
+ _nextByte(WRITE, FASTREAD);
+ }
+ else {
+ _nextByte(WRITE, READDATA);
+ }
+ _transferAddress();
+ for (uint16_t i = 0; i < _sz; i++) {
+ *p++ =_nextByte(READ);
+ }
+ _endSPI();
+ }
+ }
+ #ifdef RUNDIAGNOSTIC
+ _spifuncruntime = micros() - _spifuncruntime;
+ #endif
+ return true;
+}
+
+#endif // _SPIFRAM_H_
diff --git a/src/SPIFramIO.cpp b/src/SPIFramIO.cpp
new file mode 100644
index 0000000..213c970
--- /dev/null
+++ b/src/SPIFramIO.cpp
@@ -0,0 +1,377 @@
+/* Arduino SPIMemory Library v.3.3.0
+ * Copyright (C) 2017 by Prajwal Bhattaram
+ * Created by Prajwal Bhattaram - 19/06/2018
+ *
+ * This file is part of the Arduino SPIMemory Library. This library is for
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
+ * suspending and resuming programming/erase and powering down for low power operation.
+ *
+ * This Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License v3.0
+ * along with the Arduino SPIMemory Library. If not, see
+ * .
+ */
+
+ #include "SPIFram.h"
+
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+ // Private functions used by read, write and erase operations //
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
+ // Creates bit mask from bit x to bit y
+ unsigned SPIFram::_createMask(unsigned x, unsigned y) {
+ unsigned r = 0;
+ for (unsigned i=x; i<=y; i++) {
+ r |= 1 << i;
+ }
+ return r;
+ }
+
+ //Checks to see if page overflow is permitted and assists with determining next address to read/write.
+ //Sets the global address variable
+ bool SPIFram::_addressCheck(uint32_t _addr, uint32_t size) {
+ uint32_t _submittedAddress = _addr;
+ uint8_t _errorcode = error();
+ if (_errorcode == UNKNOWNCAP || _errorcode == NORESPONSE) {
+ return false;
+ }
+ if (!_chip.capacity) {
+ _troubleshoot(CALLBEGIN);
+ return false;
+ }
+
+ //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
+ _addressOverflow = ((_submittedAddress + size) - _chip.capacity);
+ _currentAddress = _addr;
+ //Serial.print("_addressOverflow: ");
+ //Serial.println(_addressOverflow, HEX);
+ return true; // At end of memory - (pageOverflow)
+ #endif
+ }
+ 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 (unless OVERWRITE is enabled)
+ bool SPIFram::_notPrevWritten(uint32_t _addr, uint32_t size) {
+ #if !defined (OVERWRITE)
+ _beginSPI(READDATA);
+ for (uint32_t i = 0; i < size; i++) {if (_nextByte(READ) != 0x00) {
+ CHIP_DESELECT;
+ _troubleshoot(PREVWRITTEN);
+ return false;
+ }
+ }
+ CHIP_DESELECT
+ #endif
+ return true;
+ }
+
+ //Double checks all parameters before calling a read or write. Comes in two variants
+ //Takes address and returns the address if true, else returns false. Throws an error if there is a problem.
+ bool SPIFram::_prep(uint32_t _addr, uint32_t size) {
+ if(_isChipPoweredDown() || !_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_writeEnable()) {
+ return false;
+ }
+ return true;
+ }
+
+ // Transfer Address.
+ bool SPIFram::_transferAddress(void) {
+ _nextByte(WRITE, Hi(_currentAddress));
+ _nextByte(WRITE, Lo(_currentAddress));
+ return true;
+ }
+
+ bool SPIFram::_startSPIBus(void) {
+ #ifndef SPI_HAS_TRANSACTION
+ noInterrupts();
+ #endif
+
+ #if defined (ARDUINO_ARCH_SAM)
+ due.SPIInit(DUE_SPI_CLK);
+ #elif defined (ARDUINO_ARCH_SAMD)
+ #ifdef SPI_HAS_TRANSACTION
+ _spi->beginTransaction(_settings);
+ #else
+ _spi->setClockDivider(SPI_CLOCK_DIV_4);
+ _spi->setDataMode(SPI_MODE0);
+ _spi->setBitOrder(MSBFIRST);
+ #endif
+ #if defined ENABLEZERODMA
+ dma_init();
+ #endif
+ #else
+ #if defined (ARDUINO_ARCH_AVR)
+ //save current SPI settings
+ _SPCR = SPCR;
+ _SPSR = SPSR;
+ #endif
+ #ifdef SPI_HAS_TRANSACTION
+ SPI.beginTransaction(_settings);
+ #else
+ SPI.setClockDivider(SPI_CLOCK_DIV4);
+ SPI.setDataMode(SPI_MODE0);
+ SPI.setBitOrder(MSBFIRST);
+ #endif
+ #endif
+ SPIBusState = true;
+ return true;
+ }
+
+ //Initiates SPI operation - but data is not transferred yet. Always call _prep() before this function (especially when it involves writing or reading to/from an address)
+ bool SPIFram::_beginSPI(uint8_t opcode) {
+ if (!SPIBusState) {
+ _startSPIBus();
+ }
+ CHIP_SELECT
+ switch (opcode) {
+ case READDATA:
+ _nextByte(WRITE, opcode);
+ _transferAddress();
+ break;
+
+ case PAGEPROG:
+ _nextByte(WRITE, opcode);
+ _transferAddress();
+ break;
+
+ case FASTREAD:
+ _nextByte(WRITE, opcode);
+ _nextByte(WRITE, DUMMYBYTE);
+ _transferAddress();
+ break;
+
+ default:
+ _nextByte(WRITE, opcode);
+ break;
+ }
+ return true;
+ }
+ //SPI data lines are left open until _endSPI() is called
+
+ //Reads/Writes next byte. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI()
+ uint8_t SPIFram::_nextByte(char IOType, uint8_t data) {
+ #if defined (ARDUINO_ARCH_SAMD)
+ #ifdef ENABLEZERODMA
+ union {
+ uint8_t dataBuf[1];
+ uint8_t val;
+ } rxData, txData;
+ txData.val = data;
+ spi_transfer(txData.dataBuf, rxData.dataBuf, 1);
+ return rxData.val;
+ #else
+ return xfer(data);
+ #endif
+ #else
+ return xfer(data);
+ #endif
+ }
+
+ //Reads/Writes next int. Call 'n' times to read/write 'n' number of integers. Should be called after _beginSPI()
+ uint16_t SPIFram::_nextInt(uint16_t data) {
+ #if defined (ARDUINO_ARCH_SAMD)
+ return _spi->transfer16(data);
+ #else
+ return SPI.transfer16(data);
+ #endif
+ }
+
+ //Reads/Writes next data buffer. Should be called after _beginSPI()
+ void SPIFram::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) {
+ uint8_t *_dataAddr = &(*data_buffer);
+ switch (opcode) {
+ case READDATA:
+ #if defined (ARDUINO_ARCH_SAM)
+ due.SPIRecByte(&(*data_buffer), size);
+ #elif defined (ARDUINO_ARCH_SAMD)
+ #ifdef ENABLEZERODMA
+ spi_read(&(*data_buffer), size);
+ #else
+ _spi->transfer(&data_buffer[0], size);
+ #endif
+ #elif defined (ARDUINO_ARCH_AVR)
+ SPI.transfer(&(*data_buffer), size);
+ #else
+ for (uint16_t i = 0; i < size; i++) {
+ *_dataAddr = xfer(NULLBYTE);
+ _dataAddr++;
+ }
+ #endif
+ break;
+
+ case PAGEPROG:
+ #if defined (ARDUINO_ARCH_SAM)
+ due.SPISendByte(&(*data_buffer), size);
+ #elif defined (ARDUINO_ARCH_SAMD)
+ #ifdef ENABLEZERODMA
+ spi_write(&(*data_buffer), size);
+ #else
+ _spi->transfer(&data_buffer[0], size);
+ #endif
+ #elif defined (ARDUINO_ARCH_AVR)
+ SPI.transfer(&(*data_buffer), size);
+ #else
+ for (uint16_t i = 0; i < size; i++) {
+ xfer(*_dataAddr);
+ _dataAddr++;
+ }
+ #endif
+ break;
+ }
+ }
+
+ //Stops all operations. Should be called after all the required data is read/written from repeated _nextByte() calls
+ void SPIFram::_endSPI(void) {
+ CHIP_DESELECT
+
+ #ifdef SPI_HAS_TRANSACTION
+ #if defined (ARDUINO_ARCH_SAMD)
+ _spi->endTransaction();
+ #else
+ SPI.endTransaction();
+ #endif
+ #else
+ interrupts();
+ #endif
+ #if defined (ARDUINO_ARCH_AVR)
+ SPCR = _SPCR;
+ SPSR = _SPSR;
+ #endif
+ SPIBusState = false;
+ }
+
+ // Checks if status register 1 can be accessed - used to check chip status, during powerdown and power up and for debugging
+ uint8_t SPIFram::_readStat1(void) {
+ _beginSPI(READSTAT1);
+ stat1 = _nextByte(READ);
+ CHIP_DESELECT
+ return stat1;
+ }
+
+ // Checks to see if chip is powered down. If it is, retrns true. If not, returns false.
+ bool SPIFram::_isChipPoweredDown(void) {
+ if (chipPoweredDown) {
+ _troubleshoot(CHIPISPOWEREDDOWN);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ //Enables writing to chip by setting the WRITEENABLE bit
+ bool SPIFram::_writeEnable(bool _troubleshootEnable) {
+ _beginSPI(WRITEENABLE);
+ CHIP_DESELECT
+ if (!(_readStat1() & WRTEN)) {
+ if (_troubleshootEnable) {
+ _troubleshoot(CANTENWRITE);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ //Disables writing to chip by setting the Write Enable Latch (WEL) bit in the Status Register to 0
+ //_writeDisable() is not required under the following conditions because the Write Enable Latch (WEL) flag is cleared to 0
+ // i.e. to write disable state:
+ // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register,
+ // Erase Security Register and Program Security register
+ bool SPIFram::_writeDisable(void) {
+ _beginSPI(WRITEDISABLE);
+ CHIP_DESELECT
+ return true;
+}
+
+ //Checks for presence of chip by requesting JEDEC ID
+ bool SPIFram::_getJedecId(void) {
+ _beginSPI(JEDECID);
+ do {
+ _chip.manufacturerID = _nextByte(READ); // manufacturer id
+ } while (_chip.manufacturerID == 0x7F); // 0x7F is a continuation code according to JEDEC. So, the code loops till a manufacturer ID is read.
+ _chip.devID1 = _nextByte(READ); // memory type
+ _chip.devID2 = _nextByte(READ); // capacity
+ CHIP_DESELECT
+ if (_chip.manufacturerID == 0x00) {
+ _troubleshoot(NORESPONSE);
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ bool SPIFram::_disableGlobalBlockProtect(void) {
+ // TODO: write function for _disableGlobalBlockProtect()
+ return true;
+ }
+
+ //Identifies the chip
+ bool SPIFram::_chipID(uint32_t flashChipSize) {
+
+ if (!_chip.capacity) {
+ if (flashChipSize) {
+ // If a custom chip size is defined
+ #ifdef RUNDIAGNOSTIC
+ Serial.println("Custom Chipsize defined");
+ #endif
+ _chip.capacity = flashChipSize;
+ _chip.supported = false;
+ return true;
+ }
+
+ else {
+ _getJedecId();
+ for (uint8_t i = 0; i < sizeof(_supportedManID); i++) {
+ if (_chip.manufacturerID == _supportedManID[i]) {
+ _chip.supportedMan = true;
+ break;
+ }
+ }
+ if (_chip.supportedMan) {
+ #ifdef RUNDIAGNOSTIC
+ Serial.println("No Chip size defined by user. Checking library support.");
+ #endif
+ //Identify capacity
+ _chip.capacity = ((_chip.devID1 & _createMask(0, 4)) * KB(16)); // Currently only tested to be compatible with the FM25 series FRAM from Cypress. Refer to datasheet for FM25V05, Page 9
+ }
+ else {
+ _troubleshoot(UNKNOWNCHIP); //Error code for unidentified capacity
+ return false;
+ }
+ }
+ _troubleshoot(UNKNOWNCAP);
+ return false;
+ }
+ return true;
+ }
+
+ //Troubleshooting function. Called when #ifdef RUNDIAGNOSTIC is uncommented at the top of this file.
+ void SPIFram::_troubleshoot(uint8_t _code, bool printoverride) {
+ diagnostics.troubleshoot(_code, printoverride);
+ }
diff --git a/src/SPIMemory.cpp b/src/SPIMemory.cpp
index 3cab6e9..5628aa9 100644
--- a/src/SPIMemory.cpp
+++ b/src/SPIMemory.cpp
@@ -1,13 +1,12 @@
-/* Arduino SPIMemory Library v.3.2.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
* Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 24/02/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
diff --git a/src/SPIMemory.h b/src/SPIMemory.h
index 67d7160..0e9e151 100644
--- a/src/SPIMemory.h
+++ b/src/SPIMemory.h
@@ -1,12 +1,11 @@
-/* Arduino SPIMemory Library v.3.2.1
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 18/04/2018
- * Modified by Prajwal Bhattaram - 21/05/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -74,6 +73,7 @@
#include
#include "defines.h"
#include "SPIFlash.h"
+ #include "SPIFram.h"
#include "diagnostics.h"
#if defined (ARDUINO_ARCH_SAM)
diff --git a/src/defines.h b/src/defines.h
index 0be893e..25adb6d 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -1,12 +1,11 @@
-/* Arduino SPIMemory Library v.3.2.1
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
- * Modified by Prajwal Bhattaram - 21/05/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -87,6 +86,7 @@
#define RELEASE 0xAB
#define READSFDP 0x5A
#define UNIQUEID 0x4B
+#define FRAMSERNO 0xC3
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// General size definitions //
@@ -151,6 +151,7 @@
//~~~~~~~~~~~~~~~~~~~~~~~~ Cypress ~~~~~~~~~~~~~~~~~~~~~~~~//
#define CYPRESS_MANID 0x01
+ #define RAMTRON_FRAM_MANID 0xC2
//~~~~~~~~~~~~~~~~~~~~~~~~ Adesto ~~~~~~~~~~~~~~~~~~~~~~~~//
#define ADESTO_MANID 0x1F
@@ -162,6 +163,9 @@
//~~~~~~~~~~~~~~~~~~~~~~~~ ON ~~~~~~~~~~~~~~~~~~~~~~~~//
#define ON_MANID 0x62
+//~~~~~~~~~~~~~~~~~~~~~~~~ Giga ~~~~~~~~~~~~~~~~~~~~~~~~//
+ #define GIGA_MANID 0xC8
+
//~~~~~~~~~~~~~~~~~~~~~~~~ AMIC ~~~~~~~~~~~~~~~~~~~~~~~~//
#define AMIC_MANID 0x37
#define A25L512 0x30
@@ -184,6 +188,7 @@
#define NULLBYTE 0x00
#define NULLINT 0x0000
#define NO_CONTINUE 0x00
+#define NOVERBOSE 0x00
#define PASS 0x01
#define FAIL 0x00
#define NOOVERFLOW false
diff --git a/src/diagnostics.cpp b/src/diagnostics.cpp
index e3768dd..15c74aa 100644
--- a/src/diagnostics.cpp
+++ b/src/diagnostics.cpp
@@ -1,12 +1,11 @@
-/* Arduino SPIMemory Library v.3.2.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 14/11/2016
- * Modified by Prajwal Bhattaram - 20/04/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
@@ -70,7 +69,8 @@ void Diagnostics::troubleshoot(uint8_t _code, bool printoverride) {
case UNKNOWNCHIP:
Serial.println(F("Unable to identify chip. Are you sure this chip is supported?"));
- Serial.println(F("Chip details:"));
+ //Serial.println(F("Chip details:"));
+ //TODO: Insert a diagnostics subroutine here.
break;
case UNKNOWNCAP:
@@ -125,7 +125,7 @@ void Diagnostics::troubleshoot(uint8_t _code, bool printoverride) {
break;
case CHIPISPOWEREDDOWN:
- Serial.println(F("The Flash chip is currently powered down."));
+ Serial.println(F("The chip is currently powered down."));
break;
case NOSFDP:
diff --git a/src/diagnostics.h b/src/diagnostics.h
index 173d089..d7ceb01 100644
--- a/src/diagnostics.h
+++ b/src/diagnostics.h
@@ -1,13 +1,11 @@
-/* Arduino SPIMemory Library v.3.1.0
+/* Arduino SPIMemory Library v.3.3.0
* Copyright (C) 2017 by Prajwal Bhattaram
* Created by Prajwal Bhattaram - 19/05/2015
- * Modified by @boseji - 02/03/2017
- * Modified by Prajwal Bhattaram - 24/02/2018
+ * Modified by Prajwal Bhattaram - 19/06/2018
*
* This file is part of the Arduino SPIMemory Library. This library is for
- * Winbond NOR flash memory modules. In its current form it enables reading
- * and writing individual data variables, structs and arrays from and to various locations;
- * reading and writing pages; continuous read functions; sector, block and chip erase;
+ * Flash and FRAM memory modules. In its current form it enables reading,
+ * writing and erasing data from and to various locations;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify