Merge branch 'master' into development

Conflicts:
	.gitignore
	libraries/MySensors/MyGateway.cpp
	libraries/MySensors/MyMQTT.cpp
	libraries/MySensors/MyMQTT.h
	libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino
This commit is contained in:
Henrik Ekblad
2015-04-01 01:17:51 +02:00
18 changed files with 1869 additions and 422 deletions
@@ -81,7 +81,8 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway
#define RADIO_SPI_SS_PIN 8 // radio SPI serial select
#define RADIO_ERROR_LED_PIN A2 // Error led pin
#define RADIO_RX_LED_PIN A1 // Receive led pin
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED
*/
// * Use this for default configured pro mini / nano etc :
///*
@@ -94,7 +95,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway
#define TCP_PORT 1883 // Set your MQTT Broker Listening port.
IPAddress TCP_IP ( 192, 168, 0, 234 ); // Configure your static ip-address here
uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above!
byte TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above!
//////////////////////////////////////////////////////////////////
@@ -115,6 +116,7 @@ MySensor gw(transport, hw /*, signer*/);
EthernetServer server = EthernetServer(TCP_PORT);
EthernetClient *currentClient = NULL;
MyMessage msg;
char convBuf[MAX_PAYLOAD*2+1];
char broker[] PROGMEM = MQTT_BROKER_PREFIX;
@@ -137,26 +139,44 @@ void writeEthernet(const char *writeBuffer, uint8_t *writeSize) {
void processEthernetMessages() {
char inputString[MQTT_MAX_PACKET_SIZE] = "";
uint8_t inputSize = 0;
EthernetClient client = server.available();
if (client) {
while (client.available()) {
char inChar = client.read();
inputString[inputSize] = inChar;
inputSize++;
}
char inputString[MQTT_MAX_PACKET_SIZE] = "";
byte inputSize = 0;
byte readCnt = 0;
byte length = 0;
EthernetClient client = server.available();
if (client) {
while (client.available()) {
// Save the current client we are talking with
currentClient = &client;
byte inByte = client.read();
readCnt++;
if (inputSize < MQTT_MAX_PACKET_SIZE) {
inputString[inputSize] = (char)inByte;
inputSize++;
}
if (readCnt == 2) {
length = (inByte & 127) * 1;
}
if (readCnt == (length+2)) {
break;
}
}
#ifdef TCPDUMP
Serial.print("<<");
char buf[4];
for (uint8_t a=0; a<inputSize; a++) { sprintf(buf,"%02X ", (uint8_t)inputString[a]); Serial.print(buf); } Serial.println("");
Serial.print("<<");
char buf[4];
for (byte a=0; a<inputSize; a++) { sprintf(buf, "%02X ", (byte)inputString[a]); Serial.print(buf); } Serial.println();
#endif
processMQTTMessage(inputString, inputSize);
}
processMQTTMessage(inputString, inputSize);
currentClient = NULL;
}
}
void incomingMessage(const MyMessage &message) {
rxBlink(1);
sendMQTT(message);
@@ -1,7 +1,7 @@
// 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)
// If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals
//
// Battery voltage is repported as child sensorId 199, as well as battery percentage
@@ -10,7 +10,10 @@
#include <Wire.h>
#include <SI7021.h>
#include <SPI.h>
#include <SPIFlash.h>
#include <EEPROM.h>
#include <sha204_lib_return_codes.h>
#include <sha204_library.h>
// Define a static node address, remove if you want auto address assignment
//#define NODE_ADDRESS 3
@@ -20,13 +23,26 @@
#define CHILD_ID_HUM 2
#define CHILD_ID_BATT 199
//Pin definitions
#define RESET_CFG_PIN A1
#define LED_PIN A2
// How many milli seconds between each measurement
#define MEASURE_INTERVAL 60000
// FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
#define FORCE_TRANSMIT_INTERVAL 30
// When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes.
// Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement
//Pin definitions
#define TEST_PIN A0
#define LED_PIN A2
#define ATSHA204_PIN 17 // A3
const int sha204Pin = ATSHA204_PIN;
atsha204Class sha204(sha204Pin);
SI7021 humiditySensor;
SPIFlash flash(8, 0x1F65);
MySensor gw;
// Sensor messages
@@ -45,16 +61,17 @@ 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);
Serial.begin(115200);
// First check if we should boot into test mode
pinMode(TEST_PIN,INPUT);
digitalWrite(TEST_PIN, HIGH); // Enable pullup
if (!digitalRead(TEST_PIN)) testMode();
digitalWrite(TEST_PIN,LOW);
digitalWrite(LED_PIN, HIGH);
#ifdef NODE_ADDRESS
@@ -67,12 +84,13 @@ void setup() {
humiditySensor.begin();
gw.sendSketchInfo("EnvironmentSensor", "1.0");
gw.sendSketchInfo("MysensorMicro", "1.0");
gw.present(CHILD_ID_TEMP,S_TEMP);
gw.present(CHILD_ID_HUM,S_HUM);
gw.present(CHILD_ID_BATT, S_POWER);
switchClock(1<<CLKPS2); // Switch to 1Mhz for the reminder of the sketch, save power.
}
@@ -81,7 +99,8 @@ void loop() {
measureCount ++;
bool forceTransmit = false;
if (measureCount > 30) {// Every 60th time we wake up, force a transmission on all sensors.
if (measureCount > FORCE_TRANSMIT_INTERVAL
) { // force a transmission
forceTransmit = true;
measureCount = 0;
}
@@ -106,23 +125,19 @@ void sendTempHumidityMeasurements(bool force)
lastTemperature = -100;
}
float temperature = humiditySensor.getCelsiusHundredths()/10;
si7021_env data = humiditySensor.getHumidityAndTemperature();
temperature = temperature / 10;
int humidity = humiditySensor.getHumidityPercent();
float temperature = data.celsiusHundredths/100;
int humidity = data.humidityPercent;
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);
}
}
@@ -155,7 +170,7 @@ long readVcc() {
#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);
ADcdMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
@@ -173,19 +188,110 @@ long readVcc() {
return result; // Vcc in millivolts
}
/*
* Resets eeprom to default value (while blinking LED_PIN)
*/
void resetEEP()
void switchClock(unsigned char clk)
{
for (int i=0;i<512;i++) {
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
delay(100);
EEPROM.write(i, 0xff);
}
cli();
CLKPR = 1<<CLKPCE; // Set CLKPCE to enable clk switching
CLKPR = clk;
sei();
}
// Verify all peripherals, and signal via the LED if any problems.
void testMode()
{
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
byte tests = 0;
digitalWrite(LED_PIN, HIGH); // Turn on LED.
Serial.println(F("Testing peripherals!"));
Serial.flush();
Serial.print(F("-> SI7021 : "));
Serial.flush();
if (humiditySensor.begin())
{
Serial.println(F("ok!"));
tests ++;
}
else
{
Serial.println(F("failed!"));
}
Serial.flush();
Serial.print(F("-> Flash : "));
Serial.flush();
if (flash.initialize())
{
Serial.println(F("ok!"));
tests ++;
}
else
{
Serial.println(F("failed!"));
}
Serial.flush();
Serial.print(F("-> SHA204 : "));
ret_code = sha204.sha204c_wakeup(rx_buffer);
Serial.flush();
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX);
}
Serial.flush();
if (ret_code == SHA204_SUCCESS)
{
ret_code = sha204.getSerialNumber(rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
}
else
{
Serial.print(F("Ok (serial : "));
for (int i=0; i<9; i++)
{
if (rx_buffer[i] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
}
Serial.println(")");
tests ++;
}
}
Serial.flush();
Serial.println(F("Test finished"));
if (tests == 3)
{
Serial.println(F("Selftest ok!"));
while (1) // Blink OK pattern!
{
digitalWrite(LED_PIN, HIGH);
delay(800);
digitalWrite(LED_PIN, LOW);
delay(200);
}
}
else
{
Serial.println(F("----> Selftest failed!"));
while (1) // Blink FAILED pattern! Rappidly blinking..
{
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
delay(100);
}
}
}
@@ -1,5 +1,7 @@
#include <SPI.h>
#include <MySensor.h>
/*
Vera Arduino UVM-30A
Arduino UVM-30A
connect the sensor as follows :
@@ -7,44 +9,55 @@
- >>> GND
out >>> A0
Contribution: epierre, bulldoglowell
Converted to 1.4 by Henrik Ekblad
Contribution: epierre, bulldoglowell, gizmocuz
Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html
Because this table is pretty lineair, we can calculate a UVI with one decimal
License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
*/
#include <MySensor.h>
#include <SPI.h>
#define CHILD_ID_UV 0
#define UV_SENSOR_ANALOG_PIN 0
#define CHILD_ID_UV 0
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
MySensor gw;
MyMessage uvMsg(CHILD_ID_UV, V_UV);
int lastUV = -1;
int uvIndexValue [13] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170, 3000};
int uvIndex;
unsigned long lastSend =0;
float uvIndex;
float lastUV = -1;
int uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170};
void setup()
{
gw.begin();
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("UV Sensor", "1.1");
gw.sendSketchInfo("UV Sensor", "1.2");
// Register all sensors to gateway (they will be created as child devices)
gw.present(CHILD_ID_UV, S_UV);
}
void loop()
{
uint16_t uv = analogRead(0);// Get UV value
Serial.print("Uv reading: ");
Serial.println(uv);
for (int i = 0; i < 13; i++)
{
unsigned long currentTime = millis();
uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);// Get UV value
if (uv>1170)
uv=1170;
//Serial.print("UV Analog reading: ");
//Serial.println(uv);
int i;
for (i = 0; i < 12; i++)
{
if (uv <= uvIndexValue[i])
{
@@ -52,11 +65,21 @@ void loop()
break;
}
}
Serial.print("Uv index: ");
Serial.println(uvIndex);
//calculate 1 decimal if possible
if (i>0) {
float vRange=uvIndexValue[i]-uvIndexValue[i-1];
float vCalc=uv-uvIndexValue[i-1];
uvIndex+=(1.0/vRange)*vCalc-1.0;
}
if (uvIndex != lastUV) {
gw.send(uvMsg.set(uvIndex));
//Serial.print("UVI: ");
//Serial.println(uvIndex,2);
//Send value to gateway if changed, or at least every 5 minutes
if ((uvIndex != lastUV)||(currentTime-lastSend >= 5*60*1000)) {
lastSend=currentTime;
gw.send(uvMsg.set(uvIndex,2));
lastUV = uvIndex;
}
@@ -13,15 +13,23 @@
#include <MySensor.h>
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter)
#define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false.
#define MAX_FLOW 40 // Max flow (l/min) value to report. This filetrs outliers.
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 5 // Id of the sensor child
#define MAX_FLOW 40 // Max flow (l/min) value to report. This filters outliers.
#define CHILD_ID 1 // Id of the sensor child
unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway.
MySensor gw;
MyMessage flowMsg(CHILD_ID,V_FLOW);
MyMessage volumeMsg(CHILD_ID,V_VOLUME);
MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter
volatile unsigned long pulseCount = 0;
@@ -31,108 +39,119 @@ boolean pcReceived = false;
unsigned long oldPulseCount = 0;
unsigned long newBlink = 0;
double oldflow = 0;
double volume;
double oldvolume;
unsigned long lastSend;
unsigned long lastPulse;
unsigned long currentTime;
boolean metric;
MyMessage flowMsg(CHILD_ID,V_FLOW);
MyMessage volumeMsg(CHILD_ID,V_VOLUME);
MyMessage pcMsg(CHILD_ID,V_VAR1);
double volume =0;
double oldvolume =0;
unsigned long lastSend =0;
unsigned long lastPulse =0;
void setup()
{
gw.begin(incomingMessage);
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Water Meter", "1.0");
gw.sendSketchInfo("Water Meter", "1.2");
// Register this device as Waterflow sensor
gw.present(CHILD_ID, S_WATER);
pulseCount = oldPulseCount = 0;
// Fetch last known pulse count value from gw
gw.request(CHILD_ID, V_VAR1);
attachInterrupt(INTERRUPT, onPulse, RISING);
lastSend = millis();
lastSend = lastPulse = millis();
attachInterrupt(SENSOR_INTERRUPT, onPulse, RISING);
}
void loop()
{
gw.process();
currentTime = millis();
unsigned long currentTime = millis();
// Only send values at a maximum frequency or woken up from sleep
bool sendTime = currentTime - lastSend > SEND_FREQUENCY;
if (pcReceived && (SLEEP_MODE || sendTime)) {
// New flow value has been calculated
if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY))
{
lastSend=currentTime;
if (!pcReceived) {
//Last Pulsecount not yet received from controller, request it again
gw.request(CHILD_ID, V_VAR1);
return;
}
if (!SLEEP_MODE && flow != oldflow) {
oldflow = flow;
Serial.print("l/min:");
Serial.println(flow);
// Check that we dont get unresonable large flow value.
// could hapen when long wraps or false interrupt triggered
if (flow<((unsigned long)MAX_FLOW)) {
gw.send(flowMsg.set(flow, 2)); // Send flow value to gw
}
//Serial.print("l/min:");
//Serial.println(flow);
oldflow = flow;
}
// No Pulse count in 2min
// No Pulse count received in 2min
if(currentTime - lastPulse > 120000){
flow = 0;
}
// Pulse count has changed
if (pulseCount != oldPulseCount) {
gw.send(pcMsg.set(pulseCount)); // Send volumevalue to gw VAR1
double volume = ((double)pulseCount/((double)PULSE_FACTOR));
oldPulseCount = pulseCount;
Serial.print("pulsecount:");
Serial.println(pulseCount);
gw.send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1
double volume = ((double)pulseCount/((double)PULSE_FACTOR));
if (volume != oldvolume) {
gw.send(volumeMsg.set(volume, 3)); // Send volume value to gw
oldvolume = volume;
Serial.print("volume:");
Serial.println(volume, 3);
gw.send(volumeMsg.set(volume, 3)); // Send volume value to gw
}
}
lastSend = currentTime;
} else if (sendTime && !pcReceived) {
// No count received. Try requesting it again
gw.request(CHILD_ID, V_VAR1);
lastSend=currentTime;
}
if (SLEEP_MODE) {
gw.sleep(SEND_FREQUENCY);
}
}
void incomingMessage(const MyMessage &message) {
if (message.type==V_VAR1) {
pulseCount = oldPulseCount = message.getLong();
if (message.type==V_VAR1) {
unsigned long gwPulseCount=message.getULong();
pulseCount += gwPulseCount;
Serial.print("Received last pulse count from gw:");
Serial.println(pulseCount);
pcReceived = true;
}
}
void onPulse()
{
if (!SLEEP_MODE) {
{
if (!SLEEP_MODE)
{
unsigned long newBlink = micros();
unsigned long interval = newBlink-lastBlink;
lastPulse = millis();
if (interval<500000L) {
// Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
return;
if (interval!=0)
{
lastPulse = millis();
if (interval<500000L) {
// Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
return;
}
flow = (60000000.0 /interval) / ppl;
}
flow = (60000000.0 /interval) / ppl;
lastBlink = newBlink;
}
pulseCount++;
}
+1 -1
View File
@@ -128,7 +128,7 @@ void SI7021::setHeater(bool on) {
// get humidity, then get temperature reading from humidity measurement
struct si7021_env SI7021::getHumidityAndTemperature() {
si7021_env ret = {0, 0, 0};
ret.humidityBasisPoints = getHumidityBasisPoints();
ret.humidityPercent = getHumidityPercent();
ret.celsiusHundredths = _getCelsiusPostHumidity();
ret.fahrenheitHundredths = (1.8 * ret.celsiusHundredths) + 3200;
return ret;
+1 -1
View File
@@ -23,7 +23,7 @@ This program is licensed under the GNU GPL v2
typedef struct si7021_env {
int celsiusHundredths;
int fahrenheitHundredths;
unsigned int humidityBasisPoints;
unsigned int humidityPercent;
} si7021_env;
class SI7021
+44 -16
View File
@@ -6,6 +6,9 @@
* Minimal modifications should allow chips that have different page size but modifications
* DEPENDS ON: Arduino SPI library
*
* Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
* Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
*
* 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
@@ -32,15 +35,22 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) {
/// Select the flash chip
void SPIFlash::select() {
noInterrupts();
//save current SPI settings
#ifndef SPI_HAS_TRANSACTION
_SREG = SREG;
noInterrupts();
#endif
_SPCR = SPCR;
_SPSR = SPSR;
//set FLASH chip SPI settings
#ifdef SPI_HAS_TRANSACTION
SPI.beginTransaction(_settings);
#else
// set FLASH 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();
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
#endif
digitalWrite(_slaveSelectPin, LOW);
}
@@ -48,9 +58,13 @@ void SPIFlash::select() {
void SPIFlash::unselect() {
digitalWrite(_slaveSelectPin, HIGH);
//restore SPI settings to what they were before talking to the FLASH chip
#ifdef SPI_HAS_TRANSACTION
SPI.endTransaction();
#else
SREG = _SREG; // restore interrupts IFF they were enabled
#endif
SPCR = _SPCR;
SPSR = _SPSR;
interrupts();
}
/// setup SPI, read device ID etc...
@@ -58,7 +72,10 @@ boolean SPIFlash::initialize()
{
_SPCR = SPCR;
_SPSR = SPSR;
digitalWrite(_slaveSelectPin, HIGH);
pinMode(_slaveSelectPin, OUTPUT);
SPI.begin();
_settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
unselect();
wakeup();
@@ -185,22 +202,33 @@ void SPIFlash::writeByte(long addr, uint8_t byt) {
unselect();
}
/// write 1-256 bytes to flash memory
/// write multiple bytes to flash memory (up to 64K)
/// 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
/// This version handles both page alignment and data blocks larger than 256 bytes.
///
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();
uint16_t n;
uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
uint16_t offset = 0;
while (len>0)
{
n = (len<=maxBytes) ? len : maxBytes;
command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
SPI.transfer(addr >> 16);
SPI.transfer(addr >> 8);
SPI.transfer(addr);
for (uint16_t i = 0; i < n; i++)
SPI.transfer(((byte*) buf)[offset + i]);
unselect();
addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
offset +=n;
len -= n;
maxBytes = 256; // now we can do up to 256 bytes per loop
}
}
/// 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
+23 -15
View File
@@ -1,11 +1,13 @@
/*
* Copyright (c) 2013 by Felix Rusu <felix@lowpowerlab.com>
* 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)
* This works with 256uint8_t/page SPI flash memory
* For instance a 4MBit (512Kuint8_t) flash chip will have 2048 pages: 256*2048 = 524288 uint8_ts (512Kuint8_ts)
* Minimal modifications should allow chips that have different page size but modifications
* DEPENDS ON: Arduino SPI library
*
* Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
*
* 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
@@ -56,34 +58,34 @@
// 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_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy uint8_t after 3 address uint8_ts)
#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)
#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256uint8_ts)
#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 uint8_ts, specific uint8_ts 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);
static uint8_t UNIQUEID[8];
SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0);
boolean initialize();
void command(byte cmd, boolean isWrite=false);
byte readStatus();
byte readByte(long addr);
void command(uint8_t cmd, boolean isWrite=false);
uint8_t readStatus();
uint8_t readByte(long addr);
void readBytes(long addr, void* buf, word len);
void writeByte(long addr, byte byt);
void writeByte(long addr, uint8_t 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();
uint8_t* readUniqueId();
void sleep();
void wakeup();
@@ -91,10 +93,16 @@ public:
protected:
void select();
void unselect();
byte _slaveSelectPin;
uint8_t _slaveSelectPin;
uint16_t _jedecID;
byte _SPCR;
byte _SPSR;
uint8_t _SPCR;
uint8_t _SPSR;
uint8_t _SREG;
#ifdef SPI_HAS_TRANSACTION
SPISettings _settings;
#endif
};
#endif