From e462bc214cc622d44e10e7738db369ee35267da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 5 Feb 2015 19:10:52 +0100 Subject: [PATCH 1/2] Added libraries for SPI flash, BMP180 and Si7021 --- libraries/SFE_BMP180/SFE_BMP180.cpp | 387 ++++++++++++++++++ libraries/SFE_BMP180/SFE_BMP180.h | 121 ++++++ .../BMP180_altitude_example.ino | 168 ++++++++ .../SFE_BMP180_example/SFE_BMP180_example.ino | 200 +++++++++ libraries/SFE_BMP180/keywords.txt | 27 ++ libraries/SI7021/LICENSE | 339 +++++++++++++++ libraries/SI7021/README.md | 4 + libraries/SI7021/SI7021.cpp | 135 ++++++ libraries/SI7021/SI7021.h | 51 +++ .../SI7021/examples/readsensor/readsensor.ino | 80 ++++ libraries/SPIFlash/README.md | 24 ++ libraries/SPIFlash/SPIFlash.cpp | 246 +++++++++++ libraries/SPIFlash/SPIFlash.h | 100 +++++ .../SPIFlash_ReadWrite/SPIFlash_ReadWrite.ino | 116 ++++++ libraries/SPIFlash/keywords.txt | 18 + libraries/SPIFlash/library.json | 12 + 16 files changed, 2028 insertions(+) create mode 100644 libraries/SFE_BMP180/SFE_BMP180.cpp create mode 100644 libraries/SFE_BMP180/SFE_BMP180.h create mode 100644 libraries/SFE_BMP180/examples/BMP180_altitude_example/BMP180_altitude_example.ino create mode 100644 libraries/SFE_BMP180/examples/SFE_BMP180_example/SFE_BMP180_example.ino create mode 100644 libraries/SFE_BMP180/keywords.txt create mode 100644 libraries/SI7021/LICENSE create mode 100644 libraries/SI7021/README.md create mode 100644 libraries/SI7021/SI7021.cpp create mode 100644 libraries/SI7021/SI7021.h create mode 100644 libraries/SI7021/examples/readsensor/readsensor.ino create mode 100644 libraries/SPIFlash/README.md create mode 100644 libraries/SPIFlash/SPIFlash.cpp create mode 100644 libraries/SPIFlash/SPIFlash.h create mode 100644 libraries/SPIFlash/examples/SPIFlash_ReadWrite/SPIFlash_ReadWrite.ino create mode 100644 libraries/SPIFlash/keywords.txt create mode 100644 libraries/SPIFlash/library.json diff --git a/libraries/SFE_BMP180/SFE_BMP180.cpp b/libraries/SFE_BMP180/SFE_BMP180.cpp new file mode 100644 index 0000000..4383fc5 --- /dev/null +++ b/libraries/SFE_BMP180/SFE_BMP180.cpp @@ -0,0 +1,387 @@ +/* + SFE_BMP180.cpp + Bosch BMP180 pressure sensor library for the Arduino microcontroller + Mike Grusin, SparkFun Electronics + + Uses floating-point equations from the Weather Station Data Logger project + http://wmrx00.sourceforge.net/ + http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf + + Forked from BMP085 library by M.Grusin + + version 1.0 2013/09/20 initial version + + Our example code uses the "beerware" license. You can do anything + you like with this code. No really, anything. If you find it useful, + buy me a (root) beer someday. +*/ + +#include +#include +#include +#include + + +SFE_BMP180::SFE_BMP180() +// Base library type +{ +} + + +char SFE_BMP180::begin() +// Initialize library for subsequent pressure measurements +{ + double c3,c4,b1; + + // Start up the Arduino's "wire" (I2C) library: + + Wire.begin(); + + // The BMP180 includes factory calibration data stored on the device. + // Each device has different numbers, these must be retrieved and + // used in the calculations when taking pressure measurements. + + // Retrieve calibration data from device: + + if (readInt(0xAA,AC1) && + readInt(0xAC,AC2) && + readInt(0xAE,AC3) && + readUInt(0xB0,AC4) && + readUInt(0xB2,AC5) && + readUInt(0xB4,AC6) && + readInt(0xB6,VB1) && + readInt(0xB8,VB2) && + readInt(0xBA,MB) && + readInt(0xBC,MC) && + readInt(0xBE,MD)) + { + + // All reads completed successfully! + + // If you need to check your math using known numbers, + // you can uncomment one of these examples. + // (The correct results are commented in the below functions.) + + // Example from Bosch datasheet + // AC1 = 408; AC2 = -72; AC3 = -14383; AC4 = 32741; AC5 = 32757; AC6 = 23153; + // B1 = 6190; B2 = 4; MB = -32768; MC = -8711; MD = 2868; + + // Example from http://wmrx00.sourceforge.net/Arduino/BMP180-Calcs.pdf + // AC1 = 7911; AC2 = -934; AC3 = -14306; AC4 = 31567; AC5 = 25671; AC6 = 18974; + // VB1 = 5498; VB2 = 46; MB = -32768; MC = -11075; MD = 2432; + + /* + Serial.print("AC1: "); Serial.println(AC1); + Serial.print("AC2: "); Serial.println(AC2); + Serial.print("AC3: "); Serial.println(AC3); + Serial.print("AC4: "); Serial.println(AC4); + Serial.print("AC5: "); Serial.println(AC5); + Serial.print("AC6: "); Serial.println(AC6); + Serial.print("VB1: "); Serial.println(VB1); + Serial.print("VB2: "); Serial.println(VB2); + Serial.print("MB: "); Serial.println(MB); + Serial.print("MC: "); Serial.println(MC); + Serial.print("MD: "); Serial.println(MD); + */ + + // Compute floating-point polynominals: + + c3 = 160.0 * pow(2,-15) * AC3; + c4 = pow(10,-3) * pow(2,-15) * AC4; + b1 = pow(160,2) * pow(2,-30) * VB1; + c5 = (pow(2,-15) / 160) * AC5; + c6 = AC6; + mc = (pow(2,11) / pow(160,2)) * MC; + md = MD / 160.0; + x0 = AC1; + x1 = 160.0 * pow(2,-13) * AC2; + x2 = pow(160,2) * pow(2,-25) * VB2; + y0 = c4 * pow(2,15); + y1 = c4 * c3; + y2 = c4 * b1; + p0 = (3791.0 - 8.0) / 1600.0; + p1 = 1.0 - 7357.0 * pow(2,-20); + p2 = 3038.0 * 100.0 * pow(2,-36); + + /* + Serial.println(); + Serial.print("c3: "); Serial.println(c3); + Serial.print("c4: "); Serial.println(c4); + Serial.print("c5: "); Serial.println(c5); + Serial.print("c6: "); Serial.println(c6); + Serial.print("b1: "); Serial.println(b1); + Serial.print("mc: "); Serial.println(mc); + Serial.print("md: "); Serial.println(md); + Serial.print("x0: "); Serial.println(x0); + Serial.print("x1: "); Serial.println(x1); + Serial.print("x2: "); Serial.println(x2); + Serial.print("y0: "); Serial.println(y0); + Serial.print("y1: "); Serial.println(y1); + Serial.print("y2: "); Serial.println(y2); + Serial.print("p0: "); Serial.println(p0); + Serial.print("p1: "); Serial.println(p1); + Serial.print("p2: "); Serial.println(p2); + */ + + // Success! + return(1); + } + else + { + // Error reading calibration data; bad component or connection? + return(0); + } +} + + +char SFE_BMP180::readInt(char address, int &value) +// Read a signed integer (two bytes) from device +// address: register to start reading (plus subsequent register) +// value: external variable to store data (function modifies value) +{ + unsigned char data[2]; + + data[0] = address; + if (readBytes(data,2)) + { + value = (((int)data[0]<<8)|(int)data[1]); + //if (*value & 0x8000) *value |= 0xFFFF0000; // sign extend if negative + return(1); + } + value = 0; + return(0); +} + + +char SFE_BMP180::readUInt(char address, unsigned int &value) +// Read an unsigned integer (two bytes) from device +// address: register to start reading (plus subsequent register) +// value: external variable to store data (function modifies value) +{ + unsigned char data[2]; + + data[0] = address; + if (readBytes(data,2)) + { + value = (((unsigned int)data[0]<<8)|(unsigned int)data[1]); + return(1); + } + value = 0; + return(0); +} + + +char SFE_BMP180::readBytes(unsigned char *values, char length) +// Read an array of bytes from device +// values: external array to hold data. Put starting register in values[0]. +// length: number of bytes to read +{ + char x; + + Wire.beginTransmission(BMP180_ADDR); + Wire.write(values[0]); + _error = Wire.endTransmission(); + if (_error == 0) + { + Wire.requestFrom(BMP180_ADDR,length); + while(Wire.available() != length) ; // wait until bytes are ready + for(x=0;x= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +class SFE_BMP180 +{ + public: + SFE_BMP180(); // base type + + char begin(); + // call pressure.begin() to initialize BMP180 before use + // returns 1 if success, 0 if failure (bad component or I2C bus shorted?) + + char startTemperature(void); + // command BMP180 to start a temperature measurement + // returns (number of ms to wait) for success, 0 for fail + + char getTemperature(double &T); + // return temperature measurement from previous startTemperature command + // places returned value in T variable (deg C) + // returns 1 for success, 0 for fail + + char startPressure(char oversampling); + // command BMP180 to start a pressure measurement + // oversampling: 0 - 3 for oversampling value + // returns (number of ms to wait) for success, 0 for fail + + char getPressure(double &P, double &T); + // return absolute pressure measurement from previous startPressure command + // note: requires previous temperature measurement in variable T + // places returned value in P variable (mbar) + // returns 1 for success, 0 for fail + + double sealevel(double P, double A); + // convert absolute pressure to sea-level pressure (as used in weather data) + // P: absolute pressure (mbar) + // A: current altitude (meters) + // returns sealevel pressure in mbar + + double altitude(double P, double P0); + // convert absolute pressure to altitude (given baseline pressure; sea-level, runway, etc.) + // P: absolute pressure (mbar) + // P0: fixed baseline pressure (mbar) + // returns signed altitude in meters + + char getError(void); + // If any library command fails, you can retrieve an extended + // error code using this command. Errors are from the wire library: + // 0 = Success + // 1 = Data too long to fit in transmit buffer + // 2 = Received NACK on transmit of address + // 3 = Received NACK on transmit of data + // 4 = Other error + + private: + + char readInt(char address, int &value); + // read an signed int (16 bits) from a BMP180 register + // address: BMP180 register address + // value: external signed int for returned value (16 bits) + // returns 1 for success, 0 for fail, with result in value + + char readUInt(char address, unsigned int &value); + // read an unsigned int (16 bits) from a BMP180 register + // address: BMP180 register address + // value: external unsigned int for returned value (16 bits) + // returns 1 for success, 0 for fail, with result in value + + char readBytes(unsigned char *values, char length); + // read a number of bytes from a BMP180 register + // values: array of char with register address in first location [0] + // length: number of bytes to read back + // returns 1 for success, 0 for fail, with read bytes in values[] array + + char writeBytes(unsigned char *values, char length); + // write a number of bytes to a BMP180 register (and consecutive subsequent registers) + // values: array of char with register address in first location [0] + // length: number of bytes to write + // returns 1 for success, 0 for fail + + int AC1,AC2,AC3,VB1,VB2,MB,MC,MD; + unsigned int AC4,AC5,AC6; + double c5,c6,mc,md,x0,x1,x2,y0,y1,y2,p0,p1,p2; + char _error; +}; + +#define BMP180_ADDR 0x77 // 7-bit address + +#define BMP180_REG_CONTROL 0xF4 +#define BMP180_REG_RESULT 0xF6 + +#define BMP180_COMMAND_TEMPERATURE 0x2E +#define BMP180_COMMAND_PRESSURE0 0x34 +#define BMP180_COMMAND_PRESSURE1 0x74 +#define BMP180_COMMAND_PRESSURE2 0xB4 +#define BMP180_COMMAND_PRESSURE3 0xF4 + +#endif diff --git a/libraries/SFE_BMP180/examples/BMP180_altitude_example/BMP180_altitude_example.ino b/libraries/SFE_BMP180/examples/BMP180_altitude_example/BMP180_altitude_example.ino new file mode 100644 index 0000000..fdb8358 --- /dev/null +++ b/libraries/SFE_BMP180/examples/BMP180_altitude_example/BMP180_altitude_example.ino @@ -0,0 +1,168 @@ +/* SFE_BMP180 altitude example sketch + +This sketch shows how to use the Bosch BMP180 pressure sensor +as an altimiter. +https://www.sparkfun.com/products/11824 + +Like most pressure sensors, the BMP180 measures absolute pressure. +Since absolute pressure varies with altitude, you can use the pressure +to determine your altitude. + +Because pressure also varies with weather, you must first take a pressure +reading at a known baseline altitude. Then you can measure variations +from that pressure + +Hardware connections: + +- (GND) to GND ++ (VDD) to 3.3V + +(WARNING: do not connect + to 5V or the sensor will be damaged!) + +You will also need to connect the I2C pins (SCL and SDA) to your +Arduino. The pins are different on different Arduinos: + +Any Arduino pins labeled: SDA SCL +Uno, Redboard, Pro: A4 A5 +Mega2560, Due: 20 21 +Leonardo: 2 3 + +Leave the IO (VDDIO) pin unconnected. This pin is for connecting +the BMP180 to systems with lower logic levels such as 1.8V + +Have fun! -Your friends at SparkFun. + +The SFE_BMP180 library uses floating-point equations developed by the +Weather Station Data Logger project: http://wmrx00.sourceforge.net/ + +Our example code uses the "beerware" license. You can do anything +you like with this code. No really, anything. If you find it useful, +buy me a beer someday. + +V10 Mike Grusin, SparkFun Electronics 10/24/2013 +*/ + +// Your sketch must #include this library, and the Wire library. +// (Wire is a standard library included with Arduino.): + +#include +#include + +// You will need to create an SFE_BMP180 object, here called "pressure": + +SFE_BMP180 pressure; + +double baseline; // baseline pressure + +void setup() +{ + Serial.begin(9600); + Serial.println("REBOOT"); + + // Initialize the sensor (it is important to get calibration values stored on the device). + + if (pressure.begin()) + Serial.println("BMP180 init success"); + else + { + // Oops, something went wrong, this is usually a connection problem, + // see the comments at the top of this sketch for the proper connections. + + Serial.println("BMP180 init fail (disconnected?)\n\n"); + while(1); // Pause forever. + } + + // Get the baseline pressure: + + baseline = getPressure(); + + Serial.print("baseline pressure: "); + Serial.print(baseline); + Serial.println(" mb"); +} + +void loop() +{ + double a,P; + + // Get a new pressure reading: + + P = getPressure(); + + // Show the relative altitude difference between + // the new reading and the baseline reading: + + a = pressure.altitude(P,baseline); + + Serial.print("relative altitude: "); + if (a >= 0.0) Serial.print(" "); // add a space for positive numbers + Serial.print(a,1); + Serial.print(" meters, "); + if (a >= 0.0) Serial.print(" "); // add a space for positive numbers + Serial.print(a*3.28084,0); + Serial.println(" feet"); + + delay(500); +} + + +double getPressure() +{ + char status; + double T,P,p0,a; + + // You must first get a temperature measurement to perform a pressure reading. + + // Start a temperature measurement: + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + + status = pressure.startTemperature(); + if (status != 0) + { + // Wait for the measurement to complete: + + delay(status); + + // Retrieve the completed temperature measurement: + // Note that the measurement is stored in the variable T. + // Use '&T' to provide the address of T to the function. + // Function returns 1 if successful, 0 if failure. + + status = pressure.getTemperature(T); + if (status != 0) + { + // Start a pressure measurement: + // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + + status = pressure.startPressure(3); + if (status != 0) + { + // Wait for the measurement to complete: + delay(status); + + // Retrieve the completed pressure measurement: + // Note that the measurement is stored in the variable P. + // Use '&P' to provide the address of P. + // Note also that the function requires the previous temperature measurement (T). + // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) + // Function returns 1 if successful, 0 if failure. + + status = pressure.getPressure(P,T); + if (status != 0) + { + return(P); + } + else Serial.println("error retrieving pressure measurement\n"); + } + else Serial.println("error starting pressure measurement\n"); + } + else Serial.println("error retrieving temperature measurement\n"); + } + else Serial.println("error starting temperature measurement\n"); +} + + + diff --git a/libraries/SFE_BMP180/examples/SFE_BMP180_example/SFE_BMP180_example.ino b/libraries/SFE_BMP180/examples/SFE_BMP180_example/SFE_BMP180_example.ino new file mode 100644 index 0000000..a43c905 --- /dev/null +++ b/libraries/SFE_BMP180/examples/SFE_BMP180_example/SFE_BMP180_example.ino @@ -0,0 +1,200 @@ +/* SFE_BMP180 library example sketch + +This sketch shows how to use the SFE_BMP180 library to read the +Bosch BMP180 barometric pressure sensor. +https://www.sparkfun.com/products/11824 + +Like most pressure sensors, the BMP180 measures absolute pressure. +This is the actual ambient pressure seen by the device, which will +vary with both altitude and weather. + +Before taking a pressure reading you must take a temparture reading. +This is done with startTemperature() and getTemperature(). +The result is in degrees C. + +Once you have a temperature reading, you can take a pressure reading. +This is done with startPressure() and getPressure(). +The result is in millibar (mb) aka hectopascals (hPa). + +If you'll be monitoring weather patterns, you will probably want to +remove the effects of altitude. This will produce readings that can +be compared to the published pressure readings from other locations. +To do this, use the sealevel() function. You will need to provide +the known altitude at which the pressure was measured. + +If you want to measure altitude, you will need to know the pressure +at a baseline altitude. This can be average sealevel pressure, or +a previous pressure reading at your altitude, in which case +subsequent altitude readings will be + or - the initial baseline. +This is done with the altitude() function. + +Hardware connections: + +- (GND) to GND ++ (VDD) to 3.3V + +(WARNING: do not connect + to 5V or the sensor will be damaged!) + +You will also need to connect the I2C pins (SCL and SDA) to your +Arduino. The pins are different on different Arduinos: + +Any Arduino pins labeled: SDA SCL +Uno, Redboard, Pro: A4 A5 +Mega2560, Due: 20 21 +Leonardo: 2 3 + +Leave the IO (VDDIO) pin unconnected. This pin is for connecting +the BMP180 to systems with lower logic levels such as 1.8V + +Have fun! -Your friends at SparkFun. + +The SFE_BMP180 library uses floating-point equations developed by the +Weather Station Data Logger project: http://wmrx00.sourceforge.net/ + +Our example code uses the "beerware" license. You can do anything +you like with this code. No really, anything. If you find it useful, +buy me a beer someday. + +V10 Mike Grusin, SparkFun Electronics 10/24/2013 +*/ + +// Your sketch must #include this library, and the Wire library. +// (Wire is a standard library included with Arduino.): + +#include +#include + +// You will need to create an SFE_BMP180 object, here called "pressure": + +SFE_BMP180 pressure; + +#define ALTITUDE 1655.0 // Altitude of SparkFun's HQ in Boulder, CO. in meters + +void setup() +{ + Serial.begin(9600); + Serial.println("REBOOT"); + + // Initialize the sensor (it is important to get calibration values stored on the device). + + if (pressure.begin()) + Serial.println("BMP180 init success"); + else + { + // Oops, something went wrong, this is usually a connection problem, + // see the comments at the top of this sketch for the proper connections. + + Serial.println("BMP180 init fail\n\n"); + while(1); // Pause forever. + } +} + +void loop() +{ + char status; + double T,P,p0,a; + + // Loop here getting pressure readings every 10 seconds. + + // If you want sea-level-compensated pressure, as used in weather reports, + // you will need to know the altitude at which your measurements are taken. + // We're using a constant called ALTITUDE in this sketch: + + Serial.println(); + Serial.print("provided altitude: "); + Serial.print(ALTITUDE,0); + Serial.print(" meters, "); + Serial.print(ALTITUDE*3.28084,0); + Serial.println(" feet"); + + // If you want to measure altitude, and not pressure, you will instead need + // to provide a known baseline pressure. This is shown at the end of the sketch. + + // You must first get a temperature measurement to perform a pressure reading. + + // Start a temperature measurement: + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + + status = pressure.startTemperature(); + if (status != 0) + { + // Wait for the measurement to complete: + delay(status); + + // Retrieve the completed temperature measurement: + // Note that the measurement is stored in the variable T. + // Function returns 1 if successful, 0 if failure. + + status = pressure.getTemperature(T); + if (status != 0) + { + // Print out the measurement: + Serial.print("temperature: "); + Serial.print(T,2); + Serial.print(" deg C, "); + Serial.print((9.0/5.0)*T+32.0,2); + Serial.println(" deg F"); + + // Start a pressure measurement: + // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). + // If request is successful, the number of ms to wait is returned. + // If request is unsuccessful, 0 is returned. + + status = pressure.startPressure(3); + if (status != 0) + { + // Wait for the measurement to complete: + delay(status); + + // Retrieve the completed pressure measurement: + // Note that the measurement is stored in the variable P. + // Note also that the function requires the previous temperature measurement (T). + // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) + // Function returns 1 if successful, 0 if failure. + + status = pressure.getPressure(P,T); + if (status != 0) + { + // Print out the measurement: + Serial.print("absolute pressure: "); + Serial.print(P,2); + Serial.print(" mb, "); + Serial.print(P*0.0295333727,2); + Serial.println(" inHg"); + + // The pressure sensor returns abolute pressure, which varies with altitude. + // To remove the effects of altitude, use the sealevel function and your current altitude. + // This number is commonly used in weather reports. + // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m. + // Result: p0 = sea-level compensated pressure in mb + + p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO) + Serial.print("relative (sea-level) pressure: "); + Serial.print(p0,2); + Serial.print(" mb, "); + Serial.print(p0*0.0295333727,2); + Serial.println(" inHg"); + + // On the other hand, if you want to determine your altitude from the pressure reading, + // use the altitude function along with a baseline pressure (sea-level or other). + // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb. + // Result: a = altitude in m. + + a = pressure.altitude(P,p0); + Serial.print("computed altitude: "); + Serial.print(a,0); + Serial.print(" meters, "); + Serial.print(a*3.28084,0); + Serial.println(" feet"); + } + else Serial.println("error retrieving pressure measurement\n"); + } + else Serial.println("error starting pressure measurement\n"); + } + else Serial.println("error retrieving temperature measurement\n"); + } + else Serial.println("error starting temperature measurement\n"); + + delay(5000); // Pause for 5 seconds. +} diff --git a/libraries/SFE_BMP180/keywords.txt b/libraries/SFE_BMP180/keywords.txt new file mode 100644 index 0000000..664167d --- /dev/null +++ b/libraries/SFE_BMP180/keywords.txt @@ -0,0 +1,27 @@ +####################################### +# Syntax Coloring Map for SFE_BMP180 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SFE_BMP180 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +startTemperature KEYWORD2 +getTemperature KEYWORD2 +startPressure KEYWORD2 +getPressure KEYWORD2 +sealevel KEYWORD2 +altitude KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +BMP180_ADDR LITERAL1 \ No newline at end of file diff --git a/libraries/SI7021/LICENSE b/libraries/SI7021/LICENSE new file mode 100644 index 0000000..d7f1051 --- /dev/null +++ b/libraries/SI7021/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/libraries/SI7021/README.md b/libraries/SI7021/README.md new file mode 100644 index 0000000..38f42bf --- /dev/null +++ b/libraries/SI7021/README.md @@ -0,0 +1,4 @@ +SI7021 +====== + +Arduino library for SI7020 and SI7021 environmental sensors diff --git a/libraries/SI7021/SI7021.cpp b/libraries/SI7021/SI7021.cpp new file mode 100644 index 0000000..2bde080 --- /dev/null +++ b/libraries/SI7021/SI7021.cpp @@ -0,0 +1,135 @@ +/* +Copyright 2014 Marcus Sorensen + +This program is licensed under the GNU GPL v2 +*/ +#include "Arduino.h" +#include "SI7021.h" +#include + +#define I2C_ADDR 0x40 + +// I2C commands +byte RH_READ[] = { 0xE5 }; +byte TEMP_READ[] = { 0xE3 }; +byte POST_RH_TEMP_READ[] = { 0xE0 }; +byte RESET[] = { 0xFE }; +byte USER1_READ[] = { 0xE7 }; +byte USER1_WRITE[] = { 0xE6 }; +byte SERIAL1_READ[] = { 0xFA, 0x0F }; +byte SERIAL2_READ[] = { 0xFC, 0xC9 }; + +bool _si_exists = false; + +SI7021::SI7021() { +} + +bool SI7021::begin() { + Wire.begin(); + Wire.beginTransmission(I2C_ADDR); + if (Wire.endTransmission() == 0) { + _si_exists = true; + } + return _si_exists; +} + +bool SI7021::sensorExists() { + return _si_exists; +} + +int SI7021::getFahrenheitHundredths() { + unsigned int c = getCelsiusHundredths(); + return (1.8 * c) + 3200; +} + +int SI7021::getCelsiusHundredths() { + byte tempbytes[2]; + _command(TEMP_READ, tempbytes); + long tempraw = (long)tempbytes[0] << 8 | tempbytes[1]; + return ((17572 * tempraw) >> 16) - 4685; +} + +int SI7021::_getCelsiusPostHumidity() { + byte tempbytes[2]; + _command(POST_RH_TEMP_READ, tempbytes); + long tempraw = (long)tempbytes[0] << 8 | tempbytes[1]; + return ((17572 * tempraw) >> 16) - 4685; +} + + +unsigned int SI7021::getHumidityPercent() { + byte humbytes[2]; + _command(RH_READ, humbytes); + long humraw = (long)humbytes[0] << 8 | humbytes[1]; + return ((125 * humraw) >> 16) - 6; +} + +unsigned int SI7021::getHumidityBasisPoints() { + byte humbytes[2]; + _command(RH_READ, humbytes); + long humraw = (long)humbytes[0] << 8 | humbytes[1]; + return ((12500 * humraw) >> 16) - 600; +} + +void SI7021::_command(byte * cmd, byte * buf ) { + _writeReg(cmd, sizeof cmd); + _readReg(buf, sizeof buf); +} + +void SI7021::_writeReg(byte * reg, int reglen) { + Wire.beginTransmission(I2C_ADDR); + for(int i = 0; i < reglen; i++) { + reg += i; + Wire.write(*reg); + } + Wire.endTransmission(); +} + +int SI7021::_readReg(byte * reg, int reglen) { + Wire.requestFrom(I2C_ADDR, reglen); + while(Wire.available() < reglen) { + } + for(int i = 0; i < reglen; i++) { + reg[i] = Wire.read(); + } + return 1; +} + +//note this has crc bytes embedded, per datasheet, so provide 12 byte buf +int SI7021::getSerialBytes(byte * buf) { + _writeReg(SERIAL1_READ, sizeof SERIAL1_READ); + _readReg(buf, 6); + + _writeReg(SERIAL2_READ, sizeof SERIAL2_READ); + _readReg(buf + 6, 6); + + // could verify crc here and return only the 8 bytes that matter + return 1; +} + +int SI7021::getDeviceId() { + byte serial[12]; + getSerialBytes(serial); + int id = serial[6]; + return id; +} + +void SI7021::setHeater(bool on) { + byte userbyte; + if (on) { + userbyte = 0x3E; + } else { + userbyte = 0x3A; + } + byte userwrite[] = {USER1_WRITE[0], userbyte}; + _writeReg(userwrite, sizeof userwrite); +} + +// get humidity, then get temperature reading from humidity measurement +struct si7021_env SI7021::getHumidityAndTemperature() { + si7021_env ret = {0, 0, 0}; + ret.humidityBasisPoints = getHumidityBasisPoints(); + ret.celsiusHundredths = _getCelsiusPostHumidity(); + ret.fahrenheitHundredths = (1.8 * ret.celsiusHundredths) + 3200; + return ret; +} diff --git a/libraries/SI7021/SI7021.h b/libraries/SI7021/SI7021.h new file mode 100644 index 0000000..5aa9f4b --- /dev/null +++ b/libraries/SI7021/SI7021.h @@ -0,0 +1,51 @@ +/* + Copyright 2014 Marcus Sorensen + +This program is licensed under the GNU GPL v2 +*/ +#ifndef si7021_h +#define si7021_h + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#ifdef __AVR_ATtiny85__ + #include "TinyWireM.h" + #define Wire TinyWireM +#else + #include + #include +#endif + +typedef struct si7021_env { + int celsiusHundredths; + int fahrenheitHundredths; + unsigned int humidityBasisPoints; +} si7021_env; + +class SI7021 +{ + public: + SI7021(); + bool begin(); + bool sensorExists(); + int getFahrenheitHundredths(); + int getCelsiusHundredths(); + unsigned int getHumidityPercent(); + unsigned int getHumidityBasisPoints(); + struct si7021_env getHumidityAndTemperature(); + int getSerialBytes(byte * buf); + int getDeviceId(); + void setHeater(bool on); + private: + void _command(byte * cmd, byte * buf ); + void _writeReg(byte * reg, int reglen); + int _readReg(byte * reg, int reglen); + int _getCelsiusPostHumidity(); +}; + +#endif + diff --git a/libraries/SI7021/examples/readsensor/readsensor.ino b/libraries/SI7021/examples/readsensor/readsensor.ino new file mode 100644 index 0000000..95194cf --- /dev/null +++ b/libraries/SI7021/examples/readsensor/readsensor.ino @@ -0,0 +1,80 @@ +#include +#include + + +SI7021 sensor; +int led1 = 3; +int led2 = 4; + +void setup() { + pinMode(led1, OUTPUT); + pinMode(led2, OUTPUT); + sensor.begin(); +} + + +void loop() { + + // temperature is an integer in hundredths + int temperature = sensor.getCelsiusHundredths(); + temperature = temperature / 100; + for (int i = 0; i < temperature; i++) { + pulse(led1); + } + + delay(5000); + + // humidity is an integer representing percent + int humidity = sensor.getHumidityPercent(); + for (int i = 0; i < humidity; i++) { + pulse(led2); + } + + delay(5000); + + // this driver should work for SI7020 and SI7021, this returns 20 or 21 + int deviceid = sensor.getDeviceId(); + for (int i = 0; i < deviceid; i++) { + pulse(led1); + } + delay(5000); + + // enable internal heater for testing + sensor.setHeater(true); + delay(20000); + sensor.setHeater(false); + + // see if heater changed temperature + int temperature = sensor.getCelsiusHundredths(); + temperature = temperature / 100; + for (int i = 0; i < temperature; i++) { + pulse(led2); + } + + //cool down + delay(20000); + + // get humidity and temperature in one shot, saves power because sensor takes temperature when doing humidity anyway + si7021_env data = sensor.getHumidityAndTemperature(); + for (int i = 0; i < data.celsiusHundredths/100; i++) { + pulse(led1); + } + for (int i = 0; i < data.humidityPercent; i++) { + pulse(led2); + } + delay(5000); +} + +void pulse(int pin) { + // software pwm, flash light for ~1 second with short duty cycle + for (int i = 0; i < 20; i++) { + digitalWrite(pin, HIGH); + delay(1); + digitalWrite(pin,LOW); + delay(9); + } + digitalWrite(pin,LOW); + delay(300); +} + + diff --git a/libraries/SPIFlash/README.md b/libraries/SPIFlash/README.md new file mode 100644 index 0000000..63a1cac --- /dev/null +++ b/libraries/SPIFlash/README.md @@ -0,0 +1,24 @@ +SPIFlash +======== +Arduino/Moteino library for read/write access to SPI flash memory chips. +This works with 256byte/page SPI flash memory such as the 4MBIT W25X40CLSNIG used on (Moteinos)[www.moteino.com] for data storage and wireless programming. +
+For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes). +
Minimal modifications should allow chips that have different page size to work. +
DEPENDS ON: Arduino *SPI library*. +
+This library was primarily developed to enable **safe** wireless programming on Moteino nodes and Moteino based applications such as the SwitchMote. This has been documented at [lowpowerlab](http://lowpowerlab.com/blog/category/moteino/wireless-programming/). [Dualoptiboot](https://github.com/LowPowerLab/DualOptiboot) (all Moteinos come with it) and [WirelessProgramming library](https://github.com/LowPowerLab/WirelessProgramming) are required to be able to wirelessly re-flash a remote Moteino. + +###Installation +Copy the content of this library in the "Arduino/libraries/SPIFlash" folder. +
+To find your Arduino folder go to File>Preferences in the Arduino IDE. +
+See [this tutorial](http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries) on Arduino libraries. + +###License +Copyright (c) 2013 by Felix Rusu +
+This library is free software; you can redistribute it and/or modify it under the terms of either the GNU General Public License version 2 or the GNU Lesser General Public License version 2.1, both as published by the Free Software Foundation. +
+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. diff --git a/libraries/SPIFlash/SPIFlash.cpp b/libraries/SPIFlash/SPIFlash.cpp new file mode 100644 index 0000000..03d6a1a --- /dev/null +++ b/libraries/SPIFlash/SPIFlash.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013 by Felix Rusu + * SPI Flash memory library for arduino/moteino. + * This works with 256byte/page SPI flash memory + * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * Minimal modifications should allow chips that have different page size but modifications + * DEPENDS ON: Arduino SPI library + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include + +byte SPIFlash::UNIQUEID[8]; + +/// IMPORTANT: NAND FLASH memory requires erase before write, because +/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s +/// See http://en.wikipedia.org/wiki/Flash_memory +/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command + +/// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response +/// get this from the datasheet of your flash chip +/// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) +/// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) +SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { + _slaveSelectPin = slaveSelectPin; + _jedecID = jedecID; +} + +/// Select the flash chip +void SPIFlash::select() { + noInterrupts(); + //save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + //set FLASH chip SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + SPI.begin(); + digitalWrite(_slaveSelectPin, LOW); +} + +/// UNselect the flash chip +void SPIFlash::unselect() { + digitalWrite(_slaveSelectPin, HIGH); + //restore SPI settings to what they were before talking to the FLASH chip + SPCR = _SPCR; + SPSR = _SPSR; + interrupts(); +} + +/// setup SPI, read device ID etc... +boolean SPIFlash::initialize() +{ + _SPCR = SPCR; + _SPSR = SPSR; + pinMode(_slaveSelectPin, OUTPUT); + unselect(); + wakeup(); + + if (_jedecID == 0 || readDeviceId() == _jedecID) { + command(SPIFLASH_STATUSWRITE, true); // Write Status Register + SPI.transfer(0); // Global Unprotect + unselect(); + return true; + } + return false; +} + +/// Get the manufacturer and device ID bytes (as a short word) +word SPIFlash::readDeviceId() +{ +#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo + command(SPIFLASH_IDREAD); // Read JEDEC ID +#else + select(); + SPI.transfer(SPIFLASH_IDREAD); +#endif + word jedecid = SPI.transfer(0) << 8; + jedecid |= SPI.transfer(0); + unselect(); + return jedecid; +} + +/// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize +/// Returns the byte pointer to the UNIQUEID byte array +/// Read UNIQUEID like this: +/// flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); } +/// or like this: +/// flash.readUniqueId(); byte* MAC = flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); } +byte* SPIFlash::readUniqueId() +{ + command(SPIFLASH_MACREAD); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + for (byte i=0;i<8;i++) + UNIQUEID[i] = SPI.transfer(0); + unselect(); + return UNIQUEID; +} + +/// read 1 byte from flash memory +byte SPIFlash::readByte(long addr) { + command(SPIFLASH_ARRAYREADLOWFREQ); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + byte result = SPI.transfer(0); + unselect(); + return result; +} + +/// read unlimited # of bytes +void SPIFlash::readBytes(long addr, void* buf, word len) { + command(SPIFLASH_ARRAYREAD); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(0); //"dont care" + for (word i = 0; i < len; ++i) + ((byte*) buf)[i] = SPI.transfer(0); + unselect(); +} + +/// Send a command to the flash chip, pass TRUE for isWrite when its a write command +void SPIFlash::command(byte cmd, boolean isWrite){ +#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo + DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH! + PORTB |= B00000001; +#endif + if (isWrite) + { + command(SPIFLASH_WRITEENABLE); // Write Enable + unselect(); + } + //wait for any write/erase to complete + // a time limit cannot really be added here without it being a very large safe limit + // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations + // a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the + // open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present + while(busy()); + select(); + SPI.transfer(cmd); +} + +/// check if the chip is busy erasing/writing +boolean SPIFlash::busy() +{ + /* + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + byte status = SPI.transfer(0); + unselect(); + return status & 1; + */ + return readStatus() & 1; +} + +/// return the STATUS register +byte SPIFlash::readStatus() +{ + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + byte status = SPI.transfer(0); + unselect(); + return status; +} + + +/// Write 1 byte to flash memory +/// WARNING: you can only write to previously erased memory locations (see datasheet) +/// use the block erase commands to first clear memory (write 0xFFs) +void SPIFlash::writeByte(long addr, uint8_t byt) { + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(byt); + unselect(); +} + +/// write 1-256 bytes to flash memory +/// WARNING: you can only write to previously erased memory locations (see datasheet) +/// use the block erase commands to first clear memory (write 0xFFs) +/// WARNING: if you write beyond a page boundary (or more than 256bytes), +/// the bytes will wrap around and start overwriting at the beginning of that same page +/// see datasheet for more details +void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + for (uint16_t i = 0; i < len; i++) + SPI.transfer(((byte*) buf)[i]); + unselect(); +} + +/// erase entire flash memory array +/// may take several seconds depending on size, but is non blocking +/// so you may wait for this to complete using busy() or continue doing +/// other things and later check if the chip is done with busy() +/// note that any command will first wait for chip to become available using busy() +/// so no need to do that twice +void SPIFlash::chipErase() { + command(SPIFLASH_CHIPERASE, true); + unselect(); +} + +/// erase a 4Kbyte block +void SPIFlash::blockErase4K(long addr) { + command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); +} + +/// erase a 32Kbyte block +void SPIFlash::blockErase32K(long addr) { + command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); +} + +void SPIFlash::sleep() { + command(SPIFLASH_SLEEP); + unselect(); +} + +void SPIFlash::wakeup() { + command(SPIFLASH_WAKE); + unselect(); +} + +/// cleanup +void SPIFlash::end() { + SPI.end(); +} \ No newline at end of file diff --git a/libraries/SPIFlash/SPIFlash.h b/libraries/SPIFlash/SPIFlash.h new file mode 100644 index 0000000..f0c071a --- /dev/null +++ b/libraries/SPIFlash/SPIFlash.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013 by Felix Rusu + * SPI Flash memory library for arduino/moteino. + * This works with 256byte/page SPI flash memory + * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * Minimal modifications should allow chips that have different page size but modifications + * DEPENDS ON: Arduino SPI library + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPIFLASH_H_ +#define _SPIFLASH_H_ + +#if ARDUINO >= 100 +#include +#else +#include +#include "pins_arduino.h" +#endif + +#include + +/// IMPORTANT: NAND FLASH memory requires erase before write, because +/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s +/// See http://en.wikipedia.org/wiki/Flash_memory +/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command + +/// Standard SPI flash commands +/// Assuming the WP pin is pulled up (to disable hardware write protection) +/// To use any write commands the WEL bit in the status register must be set to 1. +/// This is accomplished by sending a 0x06 command before any such write/erase command. +/// The WEL bit in the status register resets to the logical “0” state after a +/// device power-up or reset. In addition, the WEL bit will be reset to the logical “0” state automatically under the following conditions: +/// • Write Disable operation completes successfully +/// • Write Status Register operation completes successfully or aborts +/// • Protect Sector operation completes successfully or aborts +/// • Unprotect Sector operation completes successfully or aborts +/// • Byte/Page Program operation completes successfully or aborts +/// • Sequential Program Mode reaches highest unprotected memory location +/// • Sequential Program Mode reaches the end of the memory array +/// • Sequential Program Mode aborts +/// • Block Erase operation completes successfully or aborts +/// • Chip Erase operation completes successfully or aborts +/// • Hold condition aborts +#define SPIFLASH_WRITEENABLE 0x06 // write enable +#define SPIFLASH_WRITEDISABLE 0x04 // write disable + +#define SPIFLASH_BLOCKERASE_4K 0x20 // erase one 4K block of flash memory +#define SPIFLASH_BLOCKERASE_32K 0x52 // erase one 32K block of flash memory +#define SPIFLASH_BLOCKERASE_64K 0xD8 // erase one 64K block of flash memory +#define SPIFLASH_CHIPERASE 0x60 // chip erase (may take several seconds depending on size) + // but no actual need to wait for completion (instead need to check the status register BUSY bit) +#define SPIFLASH_STATUSREAD 0x05 // read status register +#define SPIFLASH_STATUSWRITE 0x01 // write status register +#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy byte after 3 address bytes) +#define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) + +#define SPIFLASH_SLEEP 0xB9 // deep power down +#define SPIFLASH_WAKE 0xAB // deep power wake up +#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256bytes) +#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) + // Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) + // Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) +#define SPIFLASH_MACREAD 0x4B // read unique ID number (MAC) + +class SPIFlash { +public: + static byte UNIQUEID[8]; + SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + boolean initialize(); + void command(byte cmd, boolean isWrite=false); + byte readStatus(); + byte readByte(long addr); + void readBytes(long addr, void* buf, word len); + void writeByte(long addr, byte byt); + void writeBytes(long addr, const void* buf, uint16_t len); + boolean busy(); + void chipErase(); + void blockErase4K(long address); + void blockErase32K(long address); + word readDeviceId(); + byte* readUniqueId(); + + void sleep(); + void wakeup(); + void end(); +protected: + void select(); + void unselect(); + byte _slaveSelectPin; + uint16_t _jedecID; + byte _SPCR; + byte _SPSR; +}; + +#endif \ No newline at end of file diff --git a/libraries/SPIFlash/examples/SPIFlash_ReadWrite/SPIFlash_ReadWrite.ino b/libraries/SPIFlash/examples/SPIFlash_ReadWrite/SPIFlash_ReadWrite.ino new file mode 100644 index 0000000..dd8d0e8 --- /dev/null +++ b/libraries/SPIFlash/examples/SPIFlash_ReadWrite/SPIFlash_ReadWrite.ino @@ -0,0 +1,116 @@ +// ********************************************************************************** +// This sketch is an example of using the SPIFlash library with a Moteino +// that has an onboard SPI Flash chip. This sketch listens to a few serial commands +// Hence type the following commands to interact with the SPI flash memory array: +// - 'd' dumps the first 256bytes of the flash chip to screen +// - 'e' erases the entire memory chip +// - 'i' print manufacturer/device ID +// - [0-9] writes a random byte to addresses [0-9] (either 0xAA or 0xBB) +// Get the SPIFlash library from here: https://github.com/LowPowerLab/SPIFlash +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// License +// ********************************************************************************** +// This program 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 program 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 along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** + + +#include //get it here: https://github.com/LowPowerLab/SPIFlash +#include + +#define SERIAL_BAUD 115200 +char input = 0; +long lastPeriod = -1; + +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define FLASH_SS 23 // and FLASH SS on D23 +#else + #define LED 9 // Moteinos have LEDs on D9 + #define FLASH_SS 8 // and FLASH SS on D8 +#endif + +////////////////////////////////////////// +// flash(SPI_CS, MANUFACTURER_ID) +// SPI_CS - CS pin attached to SPI flash chip (8 in case of Moteino) +// MANUFACTURER_ID - OPTIONAL, 0x1F44 for adesto(ex atmel) 4mbit flash +// 0xEF30 for windbond 4mbit flash +////////////////////////////////////////// +SPIFlash flash(FLASH_SS, 0xEF30); + +void setup(){ + Serial.begin(SERIAL_BAUD); + Serial.print("Start..."); + + if (flash.initialize()) + Serial.println("Init OK!"); + else + Serial.println("Init FAIL!"); +} + +void loop(){ + // Handle serial input (to allow basic DEBUGGING of FLASH chip) + // ie: display first 256 bytes in FLASH, erase chip, write bytes at first 10 positions, etc + if (Serial.available() > 0) { + input = Serial.read(); + if (input == 'd') //d=dump flash area + { + Serial.println("Flash content:"); + int counter = 0; + + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + + Serial.println(); + } + else if (input == 'e') + { + Serial.print("Erasing Flash chip ... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + else if (input == 'i') + { + Serial.print("DeviceID: "); + Serial.println(flash.readDeviceId(), HEX); + } + else if (input >= 48 && input <= 57) //0-9 + { + Serial.print("\nWriteByte("); Serial.print(input); Serial.print(")"); + flash.writeByte(input-48, millis()%2 ? 0xaa : 0xbb); + } + } + + // Periodically blink the onboard LED while listening for serial commands + if ((int)(millis()/500) > lastPeriod) + { + lastPeriod++; + pinMode(9, OUTPUT); + digitalWrite(9, lastPeriod%2); + } +} \ No newline at end of file diff --git a/libraries/SPIFlash/keywords.txt b/libraries/SPIFlash/keywords.txt new file mode 100644 index 0000000..652da98 --- /dev/null +++ b/libraries/SPIFlash/keywords.txt @@ -0,0 +1,18 @@ +SPIFlash KEYWORD1 +initialize KEYWORD2 +command KEYWORD2 +readStatus KEYWORD2 +readByte KEYWORD2 +readBytes KEYWORD2 +writeByte KEYWORD2 +writeBytes KEYWORD2 +flashBusy KEYWORD2 +chipErase KEYWORD2 +blockErase4K KEYWORD2 +blockErase32K KEYWORD2 +readDeviceId KEYWORD2 +readUniqueId KEYWORD2 +UNIQUEID KEYWORD2 +sleep KEYWORD2 +wakeup KEYWORD2 +end KEYWORD2 \ No newline at end of file diff --git a/libraries/SPIFlash/library.json b/libraries/SPIFlash/library.json new file mode 100644 index 0000000..b199318 --- /dev/null +++ b/libraries/SPIFlash/library.json @@ -0,0 +1,12 @@ +{ + "name": "SPIFlash", + "keywords": "flash, spi", + "description": "Library for read/write access to SPI flash memory chips", + "repository": + { + "type": "git", + "url": "https://github.com/LowPowerLab/SPIFlash.git" + }, + "frameworks": "arduino", + "platforms": "atmelavr" +} From c3e30662afa0d227acf3ad26686bfbfff467a8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 5 Feb 2015 19:17:44 +0100 Subject: [PATCH 2/2] Added default mysensorMicro sketch --- .../examples/MysensorMicro/MysensorMicro.ino | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino new file mode 100644 index 0000000..11bf608 --- /dev/null +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -0,0 +1,191 @@ +// Default sensor sketch for MySensor Micro module +// Act as a temperature / humidity sensor by default. +// +// If A1 is held low while powering on, it will clear eeprom (and thereby the stored nodeid) +// +// Battery voltage is repported as child sensorId 199, as well as battery percentage + + +#include +#include +#include +#include +#include + +// Define a static node address, remove if you want auto address assignment +//#define NODE_ADDRESS 3 + +// Child sensor ID's +#define CHILD_ID_TEMP 1 +#define CHILD_ID_HUM 2 +#define CHILD_ID_BATT 199 + +//Pin definitions +#define RESET_CFG_PIN A1 +#define LED_PIN A2 + +#define MEASURE_INTERVAL 60000 + +SI7021 humiditySensor; +MySensor gw; + +// Sensor messages +MyMessage msgHum(CHILD_ID_HUM, V_HUM); +MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); +MyMessage msgBattery(CHILD_ID_BATT, V_VOLTAGE); + +// Global settings +int measureCount = 0; + +// Storage of old measurements +float lastTemperature = -100; +int lastHumidity = -100; +long lastBattery = -100; + + +void setup() { + + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + // First check if we should boot into clear eeprom mode + pinMode(RESET_CFG_PIN, INPUT); + digitalWrite(RESET_CFG_PIN, HIGH); // Enable pullup + if (!digitalRead(RESET_CFG_PIN)) resetEEP(); + digitalWrite(RESET_CFG_PIN, LOW); + + digitalWrite(LED_PIN, HIGH); + +#ifdef NODE_ADDRESS + gw.begin(NULL, NODE_ADDRESS, false); +#else + gw.begin(NULL,AUTO,false); +#endif + + digitalWrite(LED_PIN, LOW); + + humiditySensor.begin(); + + gw.sendSketchInfo("EnvironmentSensor", "1.0"); + + gw.present(CHILD_ID_TEMP,S_TEMP); + gw.present(CHILD_ID_HUM,S_HUM); + + gw.present(CHILD_ID_BATT, S_POWER); +} + + +// Main loop function +void loop() { + measureCount ++; + bool forceTransmit = false; + + if (measureCount > 30) {// Every 60th time we wake up, force a transmission on all sensors. + forceTransmit = true; + measureCount = 0; + } + + gw.process(); + sendBattLevel(forceTransmit); + sendTempHumidityMeasurements(forceTransmit); + + gw.sleep(MEASURE_INTERVAL); +} + +/* + * Sends temperature and humidity from Si7021 sensor + * + * Parameters + * - force : Forces transmission of a value (even if it's the same as previous measurement) + */ +void sendTempHumidityMeasurements(bool force) +{ + if (force) { + lastHumidity = -100; + lastTemperature = -100; + } + + float temperature = humiditySensor.getCelsiusHundredths()/10; + + temperature = temperature / 10; + + int humidity = humiditySensor.getHumidityPercent(); + + if (lastTemperature != temperature) { + gw.send(msgTemp.set(temperature,1)); + lastTemperature = temperature; + Serial.print("temperature "); + Serial.println(temperature); + } + if (lastHumidity != humidity) { + gw.send(msgHum.set(humidity)); + lastHumidity = humidity; + Serial.print("Humidity "); + Serial.println(humidity); + } +} + +/* + * Sends battery information (both voltage, and battery percentage) + * + * Parameters + * - force : Forces transmission of a value + */ +void sendBattLevel(bool force) +{ + if (force) lastBattery = -1; + long vcc = readVcc(); + if (vcc != lastBattery) { + lastBattery = vcc; + // Calculate percentage + gw.send(msgBattery.set(vcc)); + vcc = vcc - 1900; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at + + long percent = vcc / 14; + gw.sendBatteryLevel(percent); + } +} + +long readVcc() { + // Read 1.1V reference against AVcc + // set the reference to Vcc and the measurement to the internal 1.1V reference + #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + ADMUX = _BV(MUX5) | _BV(MUX0); + #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = _BV(MUX3) | _BV(MUX2); + #else + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + #endif + + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Start conversion + while (bit_is_set(ADCSRA,ADSC)); // measuring + + uint8_t low = ADCL; // must read ADCL first - it then locks ADCH + uint8_t high = ADCH; // unlocks both + + long result = (high<<8) | low; + + result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 + return result; // Vcc in millivolts +} + + +/* + * Resets eeprom to default value (while blinking LED_PIN) + */ +void resetEEP() +{ + for (int i=0;i<512;i++) { + digitalWrite(LED_PIN, HIGH); + delay(100); + digitalWrite(LED_PIN, LOW); + delay(100); + EEPROM.write(i, 0xff); + } +} + +