diff --git a/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino b/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 00000000..07f6613c --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,25 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0xFF. + * Please see eeprom_iteration for a more in depth + * look at how to traverse the EEPROM. + * + * This example code is in the public domain. + */ + +#include + +void setup() { + // initialize the LED pin as an output. + pinMode(13, OUTPUT); + + EEPROM.clear(); + + // turn the LED on when we're done + digitalWrite(13, HIGH); +} + +void loop() { + /** Empty loop. **/ +} diff --git a/libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino b/libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino new file mode 100644 index 00000000..df860428 --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino @@ -0,0 +1,53 @@ +/*** + Written by Christopher Andrews. + CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ). + + A CRC is a simple way of checking whether data has changed or become corrupted. + This example calculates a CRC value directly on the EEPROM values. + The purpose of this example is to highlight how the EEPROM object can be used just like an array. + + 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan +***/ + +#include + +void setup() { + + //Start serial + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + //Print length of data to run CRC on. + Serial.print("EEPROM length: "); + Serial.println(EEPROM.length()); + + //Print the result of calling eeprom_crc() + Serial.print("CRC32 of EEPROM data: 0x"); + Serial.println(eeprom_crc(), HEX); + Serial.print("\n\nDone!"); +} + +void loop() { + /* Empty loop */ +} + +unsigned long eeprom_crc(void) { + + const unsigned long crc_table[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + + unsigned long crc = ~0L; + + for (int index = 0 ; index < EEPROM.length()/4 ; ++index) { + crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4); + crc = ~crc; + } + return crc; +} \ No newline at end of file diff --git a/libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino b/libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino new file mode 100644 index 00000000..bd30e6b5 --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino @@ -0,0 +1,68 @@ +/*** + eeprom_get example. + + This shows how to use the EEPROM.get() method. + + To pre-set the EEPROM data, run the example sketch eeprom_put. + This sketch will run without it, however, the values shown + will be shown from what ever is already on the EEPROM. + + This may cause the serial object to print out a large string + of garbage if there is no null character inside one of the strings + loaded. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + float f = 0.00f; //Variable to store data read from EEPROM. + int eeAddress = 0; //EEPROM address to start reading from + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.print("Read float from EEPROM: "); + + //Get the float data from the EEPROM at position 'eeAddress' + EEPROM.get(eeAddress, f); + Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float. + + /*** + As get also returns a reference to 'f', you can use it inline. + E.g: Serial.print( EEPROM.get( eeAddress, f ) ); + ***/ + + /*** + Get can be used with custom structures too. + I have separated this into an extra function. + ***/ + + secondTest(); //Run the next test. +} + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void secondTest() { + int eeAddress = sizeof(float); //Move address to the next byte after float 'f'. + + MyObject customVar; //Variable to store custom object read from EEPROM. + EEPROM.get(eeAddress, customVar); + + Serial.println("Read custom object from EEPROM: "); + Serial.println(customVar.field1); + Serial.println(customVar.field2); + Serial.println(customVar.name); +} + +void loop() { + /* Empty loop */ +} diff --git a/libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino b/libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino new file mode 100644 index 00000000..ead52aba --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino @@ -0,0 +1,58 @@ +/*** + eeprom_put example. + + This shows how to use the EEPROM.put() method. + Also, this sketch will pre-set the EEPROM data for the + example sketch eeprom_get. + + Note, unlike the single byte version EEPROM.write(), + the put method will use update semantics. As in a byte + will only be written to the EEPROM if the data is actually + different. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void setup() { + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + float f = 123.456f; //Variable to store in EEPROM. + int eeAddress = 0; //Location we want the data to be put. + + + //One simple call, with the address first and the object second. + EEPROM.put(eeAddress, f); + + Serial.println("Written float data type!"); + + /** Put is designed for use with custom structures also. **/ + + //Data to store. + MyObject customVar = { + 3.14f, + 65, + "Working!" + }; + + eeAddress += sizeof(float); //Move address to the next byte after float 'f'. + + EEPROM.put(eeAddress, customVar); + Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!"); +} + +void loop() { + /* Empty loop */ +} diff --git a/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino b/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 00000000..6bef6937 --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,40 @@ +/* + * EEPROM Read + * + * Reads the value of each DWORD of the EEPROM and prints it + * to the computer. + * This example code is in the public domain. + * 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan + */ + +#include + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +unsigned long value; + +void setup() { + // initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } +} + +void loop() { + // read a byte from the current address of the EEPROM + value = EEPROM.read(address); + + Serial.print(address); + Serial.print("\t"); + Serial.print(value, DEC); + Serial.println(); + + //increment address by 4 since we are using DWORDs and we have a granularity of a DWORD or 4 bytes + address = address + 4; + if (address == EEPROM.length()) { + address = 0; + } + + delay(500); +} diff --git a/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino b/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 00000000..48d69aa5 --- /dev/null +++ b/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,53 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + * 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan + */ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int addr = 0; + +void setup() { + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + //use write for the first half of the EEPROM area + Serial.println("Writing with write()"); + for(int i = 0; i < EEPROM.length()/8; i++) + { + unsigned long val = analogRead(0); + addr +=4; //increment address by 4 since we are using DWORDs + Serial.print("Addr:\t"); + Serial.print(addr); + Serial.print("\tWriting: "); + Serial.println(val); + EEPROM.write(addr, val); + delay(100); + } + + //use write8 for the second half of the EEPROM area + Serial.println("Writing with write8()"); + for(int i = EEPROM.length()/2; i < EEPROM.length(); i++) + { + byte val8 = analogRead(0)/4; + addr++; + Serial.print("Addr:\t"); + Serial.print(addr); + Serial.print("\tWriting: "); + Serial.println(val8); + EEPROM.write(addr, val8); + delay(100); + } + + Serial.println("done writing"); +} + +void loop() { + +} \ No newline at end of file diff --git a/libraries/CurieEEPROM/keywords.txt b/libraries/CurieEEPROM/keywords.txt new file mode 100644 index 00000000..2225b9ce --- /dev/null +++ b/libraries/CurieEEPROM/keywords.txt @@ -0,0 +1,29 @@ +####################################### +# Syntax Coloring Map For EEPROM +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +CurieEEPROM KEYWORD1 +EEPROM KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +write KEYWORD2 +write8 KEYWORD2 +update KEYWORD2 +update8 KEYWORD2 +clear KEYWORD2 +begin KEYWORD2 +end KEYWORD2 +length KEYWORD2 +put KEYWORD2 +get KEYWORD2 +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/CurieEEPROM/library.properties b/libraries/CurieEEPROM/library.properties new file mode 100644 index 00000000..6319a77e --- /dev/null +++ b/libraries/CurieEEPROM/library.properties @@ -0,0 +1,10 @@ +name=CurieEEPROM +version=1.0 +author=Intel +maintainer=Intel +sentence=Enables reading and writing to OTP flash area of Curie +paragraph= +category=Data Storage +url=http://www.arduino.cc/en/Reference/EEPROM +architectures=arc32 + diff --git a/libraries/CurieEEPROM/releasenotes.txt b/libraries/CurieEEPROM/releasenotes.txt new file mode 100644 index 00000000..d7c6e2cb --- /dev/null +++ b/libraries/CurieEEPROM/releasenotes.txt @@ -0,0 +1,7 @@ +01/05/2016 v1.0 + +-Initial commit for CurieEEPROM library +-Implements EEPROM functionality using an available area of the ROM +-supports both BYTE and DWORD reading/writing +-EEPROM[] currently only supports reading +-an empty DWORD cell has a value of 0xFFFFFFFF diff --git a/libraries/CurieEEPROM/src/CurieEEPROM.cpp b/libraries/CurieEEPROM/src/CurieEEPROM.cpp new file mode 100644 index 00000000..6e7d4d5b --- /dev/null +++ b/libraries/CurieEEPROM/src/CurieEEPROM.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "CurieEEPROM.h" + +CurieEEPROM EEPROM; + +void CurieEEPROM::clear() +{ + //erase the 2k bytes of the eeprom section inside the otp area + *(uint32_t*)(ROM_WR_CTRL) = 0x4002; + //wait for erase to be complete + //TODO: while(((*(uint32_t*)FLASH_STTS) & 0x01) == 0) //wait for FLASH_STTS.ER_DONE to be set to 1 + delay(1000); +} + +void CurieEEPROM::write(uint32_t address, uint32_t data) +{ + uint32_t currentValue = read(address); + //only do something if value is different from what is currently stored + if(currentValue==data) + { + return; + } + + uint32_t rom_wr_ctrl = 0; + //make sure address is valid + if((address > 0x7FC) || (address%4)) + { + return; + } + + //check if address is available for writing a new value. If not erase the whole 2K block and re-write the rest of the data + if(currentValue!=0xFFFFFFFF) + { + //read entire 2k of data + uint32_t blockdata[EEPROM_SIZE/4]; + for(int i = 0; i < EEPROM_SIZE/4; i++) + { + blockdata[i] = read(i*sizeof(uint32_t)); + } + + //update blockdata buffer + int blockIndex = address/4; + blockdata[blockIndex] = data; + + //clear EEPROM area + clear(); + + //write back all data with update data on passed address + for(int i = 0; i < EEPROM_SIZE/4; i++) + { + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; + address = EEPROM_OFFSET + i*sizeof(uint32_t); + rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + delay(3); //give it enough time to finish writing + } + } + else + { + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = data; + address += EEPROM_OFFSET; + rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + delay(3); //give it enough time to finish writing + } +} + +void CurieEEPROM::write8(uint32_t address, uint8_t data) +{ + uint8_t currentValue = read8(address); + //only do something if value is different from what is currently stored + if(currentValue==data) + { + return; + } + + uint32_t rom_wr_ctrl = 0; + //make sure address is valid + if((address > 0x7FF)) + { + return; + } + + //check if address is available for writing a new value. If not erase the whole 2K block and re-write the rest of the data + if(currentValue!=0xFF) + { + //read entire 2k of data + uint32_t blockdata[EEPROM_SIZE/4]; + for(int i = 0; i < EEPROM_SIZE/4; i++) + { + blockdata[i] = read(i*sizeof(uint32_t)); + } + + //update blockdata buffer + int offset = address%4; + int blockIndex = address/4; + uint32_t data32 = blockdata[blockIndex]; + uint8_t data_array[sizeof(uint32_t)]; + memcpy(data_array, &data32, sizeof(uint32_t)); + data_array[offset] = data; + memcpy(&data32, &data_array, sizeof(uint32_t)); + blockdata[blockIndex] = data32; + + //clear EEPROM area + clear(); + + //write back all data with update data on passed address + for(int i = 0; i < EEPROM_SIZE/4; i++) + { + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; + address = EEPROM_OFFSET + i*sizeof(uint32_t); + rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + delay(3); //give it enough time to finish writing + } + } + else + { + int offset = address%4; + uint32_t data32 = 0xffffff00 + (uint32_t)data; + for(int i = 0; i < offset; i++) + { + data32<<=8; + data32+=0x000000ff; + } + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = data32; + address -= offset; + address += EEPROM_OFFSET; + rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + delay(3); //give it enough time to finish writing + } +} + +void CurieEEPROM::update(uint32_t addr, uint32_t value) +{ + write(addr, value); +} +void CurieEEPROM::update8(uint32_t addr, uint8_t value) +{ + write8(addr, value); +} + +uint32_t CurieEEPROM::read(uint32_t address) +{ + //make sure address is valid + if((address > 0x7FC) || (address%4)) + { + return 0; + } + address += EEPROM_ADDR; + return *(uint32_t*)(address); +} + +uint8_t CurieEEPROM::read8(uint32_t address) +{ + if((address > 0x7FF)) + { + return 0; + } + int offset = address%4; + uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address-offset)); + for(int i = 0; i < offset; i++) + { + value>>=8; + } + value &= 0x000000FF; + return (uint8_t)value; +} + +uint32_t& CurieEEPROM::operator[](int i) +{ + return *(uint32_t*)(EEPROM_ADDR+i*sizeof(uint32_t)); +} + +int CurieEEPROM::length() +{ + return EEPROM_SIZE; +} + +int CurieEEPROM::begin() +{ + return 0x00; +} + +int CurieEEPROM::end() +{ + return length(); +} diff --git a/libraries/CurieEEPROM/src/CurieEEPROM.h b/libraries/CurieEEPROM/src/CurieEEPROM.h new file mode 100644 index 00000000..9832047c --- /dev/null +++ b/libraries/CurieEEPROM/src/CurieEEPROM.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define ROM_WR_CTRL 0xb0100004 +#define ROM_WR_DATA 0xb0100008 +#define FLASH_STTS 0xb0000014 +#define EEPROM_ADDR 0xfffff000 +#define EEPROM_OFFSET 0x00001000 +#define CTRL_REG 0xb0000018 + +#define EEPROM_SIZE 2048 //EEPROM size in bytes + +//#define EEPROM([(X)])=Y (EEPROM.write((X)*sizeof(uint32_t), Y)) + +#include +#include "Arduino.h" +#include + +class CurieEEPROM +{ +public: + CurieEEPROM() + { + + } + void clear(); + void write(uint32_t address, uint32_t data); + void write8(uint32_t address, uint8_t data); + void update(uint32_t addr, uint32_t value); + void update8(uint32_t addr, uint8_t value); + uint32_t read(uint32_t addr); + uint8_t read8(uint32_t addr); + + uint32_t& operator[](int i); + + int length(); + int begin(); + int end(); + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template< typename T > T &get(uint32_t addr, T &t) + { + int byteCount = sizeof(T); + //return if size of object is greater than size of EEPROM + if(byteCount > EEPROM_SIZE) + { + return t; + } + auto bytes = to_bytes(t); + for(int i = 0; i < byteCount; i++) + { + bytes[i] = read8(addr+i); + } + from_bytes(bytes, t); + return t; + } + template< typename T > T put(uint32_t addr, T t) + { + uint32_t rom_wr_ctrl = 0; + int byteCount = sizeof(T); + //return if size of object is greater than size of EEPROM + if(byteCount > EEPROM_SIZE) + { + return t; + } + const auto dwords = to_dwords(t); + + //check if address is empty and available for writing new data + bool blockAvailable = true; + for(int i =0; i < (sizeof(T)/4 + (((sizeof(T)%4)>1) ? 1 : 0)); i++) + { + uint32_t data32 = read(addr+i*sizeof(uint32_t)); + if(data32 != 0xFFFFFFFF) + { + blockAvailable = false; + } + } + if(blockAvailable) + { + for(int i = 0; i std::array< byte, sizeof(T) > to_bytes(const T& object) + { + std::array< byte, sizeof(T) > bytes ; + + const byte* begin = reinterpret_cast< const byte* >( std::addressof(object)) ; + const byte* end = begin + sizeof(T) ; + std::copy( begin, end, std::begin(bytes)) ; + + return bytes; + } + + template< typename T > std::array< uint32_t, (sizeof(T)/4 + (((sizeof(T)%4)>1) ? 1 : 0)) > to_dwords( const T& object ) + { + std::array< uint32_t, (sizeof(T)/4 + (((sizeof(T)%4)>1) ? 1 : 0)) > dwords; + + const uint32_t* begin = reinterpret_cast< const uint32_t* >( std::addressof(object)) ; + const uint32_t* end = begin + (sizeof(T)/4 + (((sizeof(T)%4)>1) ? 1 : 0)); + std::copy( begin, end, std::begin(dwords)); + + return dwords; + } + + template< typename T > T& from_bytes(std::array< byte, sizeof(T) >& bytes, T& object ) + { + byte* begin_object = reinterpret_cast< byte* >( std::addressof(object) ) ; + std::copy( std::begin(bytes), std::end(bytes), begin_object ) ; + + return object; + } +}; + +extern CurieEEPROM EEPROM;