Arduino

Google polls Spark Core

appsIn a previous blog post I was describing an example of how a Spark Core can be used to read weather sensors. The setup was really no different from any simple Arduino Uno setup. It only demonstrated how easy it is to port Arduino Sketches to a Spark Core.
With the integrated WLAN I was interested to connect the Spark Core to the internet cloud. One of the simplest ways I found, was using Google’s Spreadsheet service. I stumbled over this idea in this Spark forum post.
Here is how it works: a Google Script is periodically reading data from the Spark Core via the RESTful Spark API and then appends the data to a Spreadsheet. The code below is a minimalistic Spark code to test the such a setup:

int variable = 1634;
void setup() {
  Spark.variable("variable", &variable, INT);
}
void loop() {
  variable++;
  delay(5000);
}

It publishes a variable for cloud access and then increments it in regular intervals. Together with the following Google script I was able to quickly pull data from my core.

function collectData() {
  var  sheet = SpreadsheetApp.getActiveSheet();
  var sensor = UrlFetchApp.fetch("https://api.spark.io/v1/devices/<id>7/variable?access_token=<token>");
  // parse the JSON the Core API created
  var sensor = JSON.parse(sensor.getContentText());
  // you'll need to unescape before your parse as JSON
  var sensor_result = unescape(sensor.result);
  // create a time stamp
  var d = new Date();
  // append data to spreadsheet
  sheet.appendRow([d, sensor_result]);
}

However when I setup a time trigger to run the script in regular intervals I found the setup to be very unreliable. This is discussed and documented by several Spark Users and as of this writing I have not seen a fix for this problem.
One thing to note is, that this approach is pulling data from the Spark Core rather than the core pushing them to the cloud. This has a significant flaw as we cannot put the core into standby between the measurement intervals. Therefore this solution is anyway not a good choice for low power applications.
So stay tuned, I am experimenting with a better solution that I will blog about in my next post.

Spark Core Weather Station

In my previous blog post I described my first encounter with the Spark Core. Today I want to demonstrate a first simple code example. For this I connected the Spark Core to a Weather Shield from Sparkfun. The shield offers sensors for light, humidity, temperature and pressure. It can even be extended with rain and wind sensors as well as GPS.
.Spark Core Weather
The shield comes with a nice set of libraries and examples that I used as a starting point. To keep things really simple, I combine the entire Weather Shield source with the sensor library functions and the setup() and loop() into a single file. This did not take long and compiled quickly. I also removed the wind and rain related functionality as I did not plan to use those. The source code below takes measurements every second and writes the them to the USB serial port.

/*
MPL3115A2 Barometric Pressure Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 22nd, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This library allows an Arduino to read from the MPL3115A2 low-cost high-precision pressure sensor.
If you have feature suggestions or need support please use the github support page: https://github.com/sparkfun/MPL3115A2_Breakout
Hardware Setup: The MPL3115A2 lives on the I2C bus. Attach the SDA pin to A4, SCL to A5. Use inline 10k resistors
if you have a 5V board. If you are using the SparkFun breakout board you *do not* need 4.7k pull-up resistors
on the bus (they are built-in).
Link to the breakout board product:
Software:
.begin() Gets sensor on the I2C bus.
.readAltitude() Returns float with meters above sealevel. Ex: 1638.94
.readAltitudeFt() Returns float with feet above sealevel. Ex: 5376.68
.readPressure() Returns float with barometric pressure in Pa. Ex: 83351.25
.readTemp() Returns float with current temperature in Celsius. Ex: 23.37
.readTempF() Returns float with current temperature in Fahrenheit. Ex: 73.96
.setModeBarometer() Puts the sensor into Pascal measurement mode.
.setModeAltimeter() Puts the sensor into altimetery mode.
.setModeStandy() Puts the sensor into Standby mode. Required when changing CTRL1 register.
.setModeActive() Start taking measurements!
.setOversampleRate(byte) Sets the # of samples from 1 to 128. See datasheet.
.enableEventFlags() Sets the fundamental event flags. Required during setup.
*/
/*******************************************************************************************/
//#include "MPL3115A2.h"
/*******************************************************************************************/
#define MPL3115A2_ADDRESS 0x60 // Unshifted 7-bit I2C address for sensor
#define STATUS 0x00
#define OUT_P_MSB 0x01
#define OUT_P_CSB 0x02
#define OUT_P_LSB 0x03
#define OUT_T_MSB 0x04
#define OUT_T_LSB 0x05
#define DR_STATUS 0x06
#define OUT_P_DELTA_MSB 0x07
#define OUT_P_DELTA_CSB 0x08
#define OUT_P_DELTA_LSB 0x09
#define OUT_T_DELTA_MSB 0x0A
#define OUT_T_DELTA_LSB 0x0B
#define WHO_AM_I 0x0C
#define F_STATUS 0x0D
#define F_DATA 0x0E
#define F_SETUP 0x0F
#define TIME_DLY 0x10
#define SYSMOD 0x11
#define INT_SOURCE 0x12
#define PT_DATA_CFG 0x13
#define BAR_IN_MSB 0x14
#define BAR_IN_LSB 0x15
#define P_TGT_MSB 0x16
#define P_TGT_LSB 0x17
#define T_TGT 0x18
#define P_WND_MSB 0x19
#define P_WND_LSB 0x1A
#define T_WND 0x1B
#define P_MIN_MSB 0x1C
#define P_MIN_CSB 0x1D
#define P_MIN_LSB 0x1E
#define T_MIN_MSB 0x1F
#define T_MIN_LSB 0x20
#define P_MAX_MSB 0x21
#define P_MAX_CSB 0x22
#define P_MAX_LSB 0x23
#define T_MAX_MSB 0x24
#define T_MAX_LSB 0x25
#define CTRL_REG1 0x26
#define CTRL_REG2 0x27
#define CTRL_REG3 0x28
#define CTRL_REG4 0x29
#define CTRL_REG5 0x2A
#define OFF_P 0x2B
#define OFF_T 0x2C
#define OFF_H 0x2D
class MPL3115A2 {
public:
MPL3115A2();
//Public Functions
bool begin(); // Gets sensor on the I2C bus.
float readAltitude(); // Returns float with meters above sealevel. Ex: 1638.94
float readAltitudeFt(); // Returns float with feet above sealevel. Ex: 5376.68
float readPressure(); // Returns float with barometric pressure in Pa. Ex: 83351.25
float readTemperature(); // Returns float with current temperature in Celsius. Ex: 23.37
float readTemperatureF(); // Returns float with current temperature in Fahrenheit. Ex: 73.96
void setModeBarometer(); // Puts the sensor into Pascal measurement mode.
void setModeAltimeter(); // Puts the sensor into altimetery mode.
void setModeStandby(); // Puts the sensor into Standby mode. Required when changing CTRL1 register.
void setModeActive(); // Start taking measurements!
void setOversampleRate(byte); // Sets the # of samples from 1 to 128. See datasheet.
void enableEventFlags(); // Sets the fundamental event flags. Required during setup.
//Public Variables
private:
//Private Functions
void toggleOneShot();
byte IIC_Read(byte regAddr);
void IIC_Write(byte regAddr, byte value);
//Private Variables
};
/*******************************************************************************************/
MPL3115A2::MPL3115A2()
{
//Set initial values for private vars
}
//Begin
/*******************************************************************************************/
//Start I2C communication
bool MPL3115A2::begin(void)
{
Wire.begin();
}
//Returns the number of meters above sea level
//Returns -1 if no new data is available
float MPL3115A2::readAltitude()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float tempcsb = (lsb>>4)/16.0;
float altitude = (float)( (msb << 8) | csb) + tempcsb;
return(altitude);
}
//Returns the number of feet above sea level
float MPL3115A2::readAltitudeFt()
{
return(readAltitude() * 3.28084);
}
//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
//Returns -1 if no new data is available
float MPL3115A2::readPressure()
{
//Check PDR bit, if it's not set then toggle OST
if(IIC_Read(STATUS) & (1<<2) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while(IIC_Read(STATUS) & (1<<2) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
// Pressure comes back as a left shifted 20 bit number
long pressure_whole = (long)msb<<16 | (long)csb<<8 | (long)lsb;
pressure_whole >>= 6; //Pressure is an 18 bit number with 2 bits of decimal. Get rid of decimal portion.
lsb &= 0b00110000; //Bits 5/4 represent the fractional component
lsb >>= 4; //Get it right aligned
float pressure_decimal = (float)lsb/4.0; //Turn it into fraction
float pressure = (float)pressure_whole + pressure_decimal;
return(pressure);
}
float MPL3115A2::readTemperature()
{
if(IIC_Read(STATUS) & (1<<1) == 0) toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for TDR bit, indicates we have new temp data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 600) return(-999); //Error out after max of 512ms for a read
delay(1);
}
// Read temperature registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_T_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 2); // Request two bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 2)
{
if(counter++ > 100) return(-999); //Error out
delay(1);
}
byte msb, lsb;
msb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Negative temperature fix by D.D.G.
short foo = 0;
bool negSign = false;
//Check for 2s compliment
if(msb > 0x7F)
{
foo = ~((msb << 8) + lsb) + 1; //2’s complement
msb = foo >> 8;
lsb = foo & 0x00F0;
negSign = true;
}
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float templsb = (lsb>>4)/16.0; //temp, fraction of a degree
float temperature = (float)(msb + templsb);
if (negSign) temperature = 0 - temperature;
return(temperature);
}
//Give me temperature in fahrenheit!
float MPL3115A2::readTemperatureF()
{
return((readTemperature() * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
}
//Sets the mode to Barometer
//CTRL_REG1, ALT bit
void MPL3115A2::setModeBarometer()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<7); //Clear ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Sets the mode to Altimeter
//CTRL_REG1, ALT bit
void MPL3115A2::setModeAltimeter()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<7); //Set ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
void MPL3115A2::setModeStandby()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<0); //Clear SBYB bit for Standby mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
void MPL3115A2::setModeActive()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<0); //Set SBYB bit for Active mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
void MPL3115A2::setOversampleRate(byte sampleRate)
{
if(sampleRate > 7) sampleRate = 7; //OS cannot be larger than 0b.0111
sampleRate <<= 3; //Align it for the CTRL_REG1 register
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= 0b11000111; //Clear out old OS bits
tempSetting |= sampleRate; //Mask in new OS bits
IIC_Write(CTRL_REG1, tempSetting);
}
//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
void MPL3115A2::enableEventFlags()
{
IIC_Write(PT_DATA_CFG, 0x07); // Enable all three pressure and temp event flags
}
//Clears then sets the OST bit which causes the sensor to immediately take another reading
//Needed to sample faster than 1Hz
void MPL3115A2::toggleOneShot(void)
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<1); //Clear OST bit
IIC_Write(CTRL_REG1, tempSetting);
tempSetting = IIC_Read(CTRL_REG1); //Read current settings to be safe
tempSetting |= (1<<1); //Set OST bit
IIC_Write(CTRL_REG1, tempSetting);
}
// These are the two I2C functions in this sketch.
byte MPL3115A2::IIC_Read(byte regAddr)
{
// This function reads one byte over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr); // Address of CTRL_REG1
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 1); // Request the data...
return Wire.read();
}
void MPL3115A2::IIC_Write(byte regAddr, byte value)
{
// This function writes one byto over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr);
Wire.write(value);
Wire.endTransmission(true);
}
/*
HTU21D Humidity Sensor Library
By: Nathan Seidle
SparkFun Electronics
Date: September 22nd, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This library allows an Arduino to read from the HTU21D low-cost high-precision humidity sensor.
If you have feature suggestions or need support please use the github support page: https://github.com/sparkfun/HTU21D
Hardware Setup: The HTU21D lives on the I2C bus. Attach the SDA pin to A4, SCL to A5. If you are using the SparkFun
breakout board you *do not* need 4.7k pull-up resistors on the bus (they are built-in).
Link to the breakout board product:
Software:
Call HTU21D.Begin() in setup.
HTU21D.ReadHumidity() will return a float containing the humidity. Ex: 54.7
HTU21D.ReadTemperature() will return a float containing the temperature in Celsius. Ex: 24.1
HTU21D.SetResolution(byte: 0b.76543210) sets the resolution of the readings.
HTU21D.check_crc(message, check_value) verifies the 8-bit CRC generated by the sensor
HTU21D.read_user_register() returns the user register. Used to set resolution.
*/
//#include <Wire.h>
/*******************************************************************************************/
//#include "HTU21D.h"
/*******************************************************************************************/
#define HTDU21D_ADDRESS 0x40 //Unshifted 7-bit I2C address for the sensor
#define TRIGGER_TEMP_MEASURE_HOLD 0xE3
#define TRIGGER_HUMD_MEASURE_HOLD 0xE5
#define TRIGGER_TEMP_MEASURE_NOHOLD 0xF3
#define TRIGGER_HUMD_MEASURE_NOHOLD 0xF5
#define WRITE_USER_REG 0xE6
#define READ_USER_REG 0xE7
#define SOFT_RESET 0xFE
class HTU21D {
public:
HTU21D();
//Public Functions
bool begin();
float readHumidity(void);
float readTemperature(void);
void setResolution(byte resBits);
//Public Variables
private:
//Private Functions
byte read_user_register(void);
byte check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor);
//Private Variables
};
/*******************************************************************************************/
HTU21D::HTU21D()
{
//Set initial values for private vars
}
//Begin
/*******************************************************************************************/
//Start I2C communication
bool HTU21D::begin(void)
{
Wire.begin();
}
//Read the humidity
/*******************************************************************************************/
//Calc humidity and return it to the user
//Returns 998 if I2C timed out
//Returns 999 if CRC is wrong
float HTU21D::readHumidity(void)
{
//Request a humidity reading
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(TRIGGER_HUMD_MEASURE_NOHOLD); //Measure humidity with no bus holding
Wire.endTransmission();
//Hang out while measurement is taken. 50mS max, page 4 of datasheet.
delay(55);
//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
Wire.requestFrom(HTDU21D_ADDRESS, 3);
//Wait for data to become available
int counter = 0;
while(Wire.available() < 3)
{
counter++;
delay(1);
if(counter > 100) return 998; //Error out
}
byte msb, lsb, checksum;
msb = Wire.read();
lsb = Wire.read();
checksum = Wire.read();
/* //Used for testing
byte msb, lsb, checksum;
msb = 0x4E;
lsb = 0x85;
checksum = 0x6B;*/
unsigned int rawHumidity = ((unsigned int) msb << 8) | (unsigned int) lsb;
if(check_crc(rawHumidity, checksum) != 0) return(999); //Error out
//sensorStatus = rawHumidity & 0x0003; //Grab only the right two bits
rawHumidity &= 0xFFFC; //Zero out the status bits but keep them in place
//Given the raw humidity data, calculate the actual relative humidity
float tempRH = rawHumidity / (float)65536; //2^16 = 65536
float rh = -6 + (125 * tempRH); //From page 14
return(rh);
}
//Read the temperature
/*******************************************************************************************/
//Calc temperature and return it to the user
//Returns 998 if I2C timed out
//Returns 999 if CRC is wrong
float HTU21D::readTemperature(void)
{
//Request the temperature
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(TRIGGER_TEMP_MEASURE_NOHOLD);
Wire.endTransmission();
//Hang out while measurement is taken. 50mS max, page 4 of datasheet.
delay(55);
//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
Wire.requestFrom(HTDU21D_ADDRESS, 3);
//Wait for data to become available
int counter = 0;
while(Wire.available() < 3)
{
counter++;
delay(1);
if(counter > 100) return 998; //Error out
}
unsigned char msb, lsb, checksum;
msb = Wire.read();
lsb = Wire.read();
checksum = Wire.read();
/* //Used for testing
byte msb, lsb, checksum;
msb = 0x68;
lsb = 0x3A;
checksum = 0x7C; */
unsigned int rawTemperature = ((unsigned int) msb << 8) | (unsigned int) lsb;
if(check_crc(rawTemperature, checksum) != 0) return(999); //Error out
//sensorStatus = rawTemperature & 0x0003; //Grab only the right two bits
rawTemperature &= 0xFFFC; //Zero out the status bits but keep them in place
//Given the raw temperature data, calculate the actual temperature
float tempTemperature = rawTemperature / (float)65536; //2^16 = 65536
float realTemperature = -46.85 + (175.72 * tempTemperature); //From page 14
return(realTemperature);
}
//Set sensor resolution
/*******************************************************************************************/
//Sets the sensor resolution to one of four levels
//Page 12:
// 0/0 = 12bit RH, 14bit Temp
// 0/1 = 8bit RH, 12bit Temp
// 1/0 = 10bit RH, 13bit Temp
// 1/1 = 11bit RH, 11bit Temp
//Power on default is 0/0
void HTU21D::setResolution(byte resolution)
{
byte userRegister = read_user_register(); //Go get the current register state
userRegister &= 0b01111110; //Turn off the resolution bits
resolution &= 0b10000001; //Turn off all other bits but resolution bits
userRegister |= resolution; //Mask in the requested resolution bits
//Request a write to user register
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(WRITE_USER_REG); //Write to the user register
Wire.write(userRegister); //Write the new resolution bits
Wire.endTransmission();
}
//Read the user register
byte HTU21D::read_user_register(void)
{
byte userRegister;
//Request the user register
Wire.beginTransmission(HTDU21D_ADDRESS);
Wire.write(READ_USER_REG); //Read the user register
Wire.endTransmission();
//Read result
Wire.requestFrom(HTDU21D_ADDRESS, 1);
userRegister = Wire.read();
return(userRegister);
}
//Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D
//If it returns 0, then the transmission was good
//If it returns something other than 0, then the communication was corrupted
//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html
//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks
#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes
byte HTU21D::check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor)
{
//Test cases from datasheet:
//message = 0xDC, checkvalue is 0x79
//message = 0x683A, checkvalue is 0x7C
//message = 0x4E85, checkvalue is 0x6B
uint32_t remainder = (uint32_t)message_from_sensor << 8; //Pad with 8 bits because we have to add in the check value
remainder |= check_value_from_sensor; //Add on the check value
uint32_t divsor = (uint32_t)SHIFTED_DIVISOR;
for (int i = 0 ; i < 16 ; i++) //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done.
{
//Serial.print("remainder: ");
//Serial.println(remainder, BIN);
//Serial.print("divsor: ");
//Serial.println(divsor, BIN);
//Serial.println();
if( remainder & (uint32_t)1<<(23 - i) ) //Check if there is a one in the left position
remainder ^= divsor;
divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder
}
return (byte)remainder;
}
/*
Weather Shield Example
By: Nathan Seidle
SparkFun Electronics
Date: November 16th, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586
This code reads all the various sensors (wind speed, direction, rain gauge, humidty, pressure, light, batt_lvl)
and reports it over the serial comm port. This can be easily routed to an datalogger (such as OpenLog) or
a wireless transmitter (such as Electric Imp).
Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are
calcualted at each report.
This example code assumes the GPS module is not used.
*/
//#include <Wire.h> //I2C needed for sensors
//#include "MPL3115A2.h" //Pressure sensor
//#include "HTU21D.h" //Humidity sensor
MPL3115A2 myPressure; //Create an instance of the pressure sensor
HTU21D myHumidity; //Create an instance of the humidity sensor
//Hardware pin definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// digital I/O pins
const byte STAT1 = 6; // Blue User LED
const byte STAT2 = 7;
// analog I/O pins
const byte REFERENCE_3V3 = A3;
const byte LIGHT = A1;
const byte BATT = A2;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Global Variables
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastSecond; //The millis counter to see when a second rolls by
byte seconds; //When it hits 60, increase the current minute
byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data
byte minutes; //Keeps track of where we are in various arrays of data
byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data
//These are all the weather values that wunderground expects:
float humidity = 0; // [%]
float temp_p = 0; // [pressure sensor temperature C]
float temp_h = 0; // [humidity sensor temperature C]
//float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent
float pressure = 0;
//float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent
float battery = 11.8; //[analog value from 0 to 1023]
float light = 455; //[analog value from 0 to 1023]
//Returns the voltage of the light sensor based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
float get_light_level()
{
float operatingVoltage = analogRead(REFERENCE_3V3);
float lightSensor = analogRead(LIGHT);
operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V
lightSensor = operatingVoltage * lightSensor;
return(lightSensor);
}
//Returns the voltage of the raw pin based on the 3.3V rail
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V)
//Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors:
//3.9K on the high side (R1), and 1K on the low side (R2)
float get_battery_level()
{
float operatingVoltage = analogRead(REFERENCE_3V3);
float rawVoltage = analogRead(BATT);
operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V
rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin
rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage
return(rawVoltage);
}
//Calculates each of the variables that wunderground is expecting
void calcWeather()
{
//Calc humidity
humidity = myHumidity.readHumidity();
//Calc temperature from pressure sensor
temp_p = myPressure.readTemperature();
temp_h = myHumidity.readTemperature();
//tempf = ((tempc * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
//Calc pressure
pressure = myPressure.readPressure();
//Calc light level
light = get_light_level();
//Calc battery level
battery = get_battery_level();
Serial.println();
Serial.print(",humidity=");
Serial.print(humidity, 1);
Serial.print(",temp_h=");
Serial.print(temp_h, 1);
Serial.print(",temp_p=");
Serial.print(temp_p, 1);
Serial.print(",pressure=");
Serial.print(pressure, 2);
Serial.print(",battery=");
Serial.print(battery, 2);
Serial.print(",light=");
Serial.print(light, 2);
Serial.print(",");
Serial.println("#");
}
/*******************************************************************************************/
// MAIN
/*******************************************************************************************/
void setup()
{
Serial.begin(9600);
while(!Serial.available()); // Wait here until the user presses ENTER in the Serial Terminal
Serial.println("Weather Shield Example");
pinMode(STAT1, OUTPUT); //Status LED Blue
pinMode(STAT2, OUTPUT); //Status LED Green
pinMode(REFERENCE_3V3, INPUT);
pinMode(LIGHT, INPUT);
//Configure the pressure sensor
myPressure.begin(); // Get sensor online
myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
myPressure.setOversampleRate(7); // Set Oversample to the recommended 128
myPressure.enableEventFlags(); // Enable all three pressure and temp event flags
//Configure the humidity sensor
myHumidity.begin();
seconds = 0;
lastSecond = millis();
Spark.variable("pressure", &pressure, INT);
Spark.variable("humidity", &humidity, INT);
Spark.variable("light", &light, INT);
Spark.variable("battery", &battery, INT);
Spark.variable("temp_p", &temp_p, INT);
Spark.variable("temp_h", &temp_h, INT);
// Serial.println("Weather Shield online!");
}
void loop()
{
//Keep track of which minute it is
if(millis() - lastSecond >= 1000)
{
digitalWrite(STAT1, HIGH); //Blink stat LED
lastSecond += 1000;
//Report all readings every second
//printWeather();
calcWeather(); //Go calc all the various sensors
digitalWrite(STAT1, LOW); //Turn off stat LED
}
delay(1000);
}

For debugging I used the Serial Communication link over USB. Windows users have to install a COM driver. However, MAC and Linux support the Spark Core USB functionality out of the box.
I was really pleased to see how well the Spark Core supports Arduino libraries and well written legacy code. With only a few code modifications I had the sensors up and running.
The setup is now streaming values over a USB cable to a PC. There I captured the values with Tera Term and created a Weather Graph from the comma separated values (CVS). The example below shows the pressure curve of a Bay Area Storm passing by at end of February 2014.
CA Storm
This setup is a somewhat trivial example that a basic Arduino can also do. The project really does not take advantage of the Spak Core’s connectivity to the internet. So stay tuned for my next blog post where I will add internet connectivity to the setup.

Encounter with a Spark

I have tested several IoT platforms over the last couple of weeks. So I was not too keen to checkout yet another one. However, when I got the annoucement that the Spark Core is shipping I could not resist and ordered one. It arrive in the mail today so I thought I will take it for a spin.
The Spark Core comes in a very stylish little box.
Spark Box
Figure1: Spark Box
To my surprise the box did even includes a breadboard:
spark2spark3
Figure 2: Open Spark Core Box
Overall, the box contains the Spark Core board, a breadboard, a micro-USB cable and Spark sticker.
spark4
Figure 3: Box Content
It is amazingly simple to get the board up and running. By following these few simple steps:

  1. Download the Spark App for iPhone or Android
  2. Setup an account by register at spark.io
  3. Power up the Spark Core over the USB cable
  4. Start Spark App and log into your wireless network

If everything works well you will get rewarded with the RGB-LED on the Spark board flashing in rainbow colors. Once the Spark Core is connected to you WiFi and paired with the Spark cloud, it took me only a few minutes to get an on-board blue LED blinking.
It very quickly becomes obvious that the Spark team has done a great job setting up an entire end-to-end IoT solution consisting of:

  1. Spark Hardware
  2. Cloud based IDE
  3. Arduino compatible API
  4. Free for life cloud back-end service with a RESTful API

All the Spark Core software is open source. The board uses a CC3000 WiFi Module from TI combined with a 32-bit ARM Cortex-M3 powered STM32F103 from ST Microelectronics. The Spark team has come up with a nice integration of this hardware and the cloud server back end. It is based on the CoAP protocol specification and allows for an easy and energy efficient integrated IoT solution.
The cloud API offers over-the-air (OTA) firmware updating where the input can either be c/c++ source code or binaries. For those that don’t want to use Spark Builder, their cloud based IDE the web site also promises support for desktop IDEs like Eclipse.
So much for today, I will cover more details in future blogs.

Do you need WiFi Connectivity in your project?

There are a lot of WiFi solutions for Makers out there. However many are either expensive, big or outdated. So it is refreshing to look at the technical data of the little known WiFi module available by the name of RTX4100  from RTX Telecom. You may never have heard of RTX Telecom but this Danish design service company specialized in wireless has been around for many years.  The module is hardly bigger than a Bluetooth module.
RTX_BT1
Figure1: on the left a simple Bluetooth HC-5 module and on the right the RTX4100 WiFi Module.
The RTX41xx uses latest WiFi System in a Package (SiP) technology. It features a Nordic Semiconductors 32-bit ARM Cortex-M3  based low power microcontroller.  The WiFi is based on a AR41xx SiP from one of the leading WiFi chip manufacturer  Qualcomm – Atheros.
The 32-bit application processor is responsible for all the WiFi driver related duties. But an API allows to program custom application into the module. RTX calls the custom programs Co-Located Application or CoLA.  Besides the RTX4100 that offers 24 kBytes flash memory and 3 kBytes RAM for custom applications. RTX also offers a pin compatible RTX4140 that provides much more programmable memory for CoLA applications, 512 kBytes flash and 64 kBytes RAM.
CoLa
The SDK can be downloaded from RTX’s web site together with a comprehensive set of documents and CoLA examples.
On the Hardware side the module offers 30 solder pins that support a variety of  I/O functionality:

  • ADC ports, DAC ports
  • GPIO ports
  • UART, SPI, I2C
  • Timers

RTX has also teamed up with some cloud services. The currently supported cloud partners are: 2lemetryExositeNabto and Sensinode.
For simple applications like WiFi sensors or actors that require a limited set of IOs and CPU/Memory resources RTX41xx modules can be used stand alone. They are also a great choice for embedded projects based on Arduino that need WiFi.  Similar to some of the popular Bluetooth modules you only need a spare UART or SPI interface to talk to the RTX4100.
Unlike Electric Imp that offers you a fully integrated platform form the module all the way up to the cloud, RTX is a much more open and flexible platform where you retain control. However this control also comes at the price that you have to do more software work. The good news is that you don’t have to start from scratch, RTX supports you with quite a bit of Software.

Galileo goes Wireless

The Galileo is a great single board computer. However one thing that makes the board even more attractive is the simple support for WiFi. This blog outlines the steps necessary to get Galileo with WiFi working.
According to post in the Intel forum Galileo will work with the Intel Centrino N135 and N6205. However after reading the great post from Sergy I could not resist the temptation and got a Intel® Centrino® Advanced-N 6235 card from a local computer store. I then also had to get a pair of antennas and the half mPCI card extender.
Here are a few things you need before you start:

  1. A computer with the Arduino IDE for Galileo installed
  2. A network router with a DHCP server running
  3. An Ethernet cable to connect the Galileo board to your network
  4. An empty SD card or USB thumb drive

As my WiFi card is not supported out of the box I had to add the driver and firmware support. Here are the steps to do this:
(Note: instead of booting from a microSD card, you can also use a USB thumb drive and a USB-to-microUSB OTG-adapter cable). This is  not advertised widely, but see Galileo forum post for details

    1. Head over to Wireless Linux site and download the Linux diver for the Intel Centrino Advanced-N 6235. The file name is iwlwifi-6000g2b-ucode-18.168.6.1.tgz
    2. Attach your Galileo to your network router with a standard Ethernet cable
    3. Download the sketch source code below. Modify the MAC address in the sketch to match you Galileo board’s MAC address printed on the label on the Ethernet plug.
      #include SPI.h
      #include Ethernet.h
      // the media access control (ethernet hardware) address for the Galileo:
      byte mac[] = { 0x98, 0x4F, 0xEE, 0x00, 0x08, 0x2D};
      //the IP address for the Galileo:
      byte ip[] = { 192, 168, 0, 2 };
      void setup()
      {
          Serial.begin(9600);
          Serial.println("Attempting to start Ethernet");
          if (Ethernet.begin(mac) == 0) {
              Serial.println("Failed to configure Ethernet using DHCP");
              Serial.println("Attempting to configure Ethernet using Static IP");
              Ethernet.begin(mac, ip);
          }
          Serial.print("Your IP address: ");
          Serial.println(Ethernet.localIP());
      }
      void loop () {}
    4. Compile and upload the sketch.
    5. Open the Serial Console in the Arduino IDE. You should see a Message that reports the IP address assigned by your DHCP server “Attempting to start Ethernet” “Your IP address: 192.168. 1. 49”
    6. Do a full format  of a microSD Card (no Quickformat)
    7. Copy all the files from Prepare the microSD Card
    8. Plug the micro SD card into the SD card slot on the Galileo Board
    9. Boot your Gallileo board by pushing the REBOOT switch and wait until you see the board dectected by your computers USB port.
    10. Use SSH (mindterm or scp) to copy the file iwlwifi-6000g2b-6.ucode WiFI firmware  to the /lib/firmware/ folder of you Galileo
    11. Generate the WPA credentials:
      %wpa_passphrase NETWORK_NAME << EOF > /etc/wpa_supplicant.conf
      > YOUR_PASSWORD
      > EOF
    12. Start the network with:
      %/etc/init.d/networking restart
    13. Shut down the WiFi with:
      %ifdown wlan0
    14. Start up the WiFi
      %ifup wlan0

Using the IP address that the Galileo reported in the Serial Terminal you should be able to telnet into the board. This will give you a Galileo Linux terminal prompt.

Cortino – Another STM32 based Arduino

While searching for some STM32 related data I cam across the Cortino board by Bugblat.
Cortino
Like my Olimex featured in an earlier blog post this board uses a STM32F103 based 32-bit ARM Cortex-M3 CPU. The Cortino board looks like a nicely done Arduino variant. It even includes a FTDI chip. Although Bugblat does not provide support for the Arduino IDE software their product page offers a good overview of available 3rd Party IDEs.
Like for the Olimex, it should not be too difficult to adopt the Maple IDE from Leaflabs. However the Mable IDE is now getting a bit dated.  A more current Arduino 1.5.5 IDE can be created by using the instructions on Makerlab.me’s web page . Note unless you are fluent in Chinese you have to use Goggle Translate. However the code is documented in English and available from Github. For those that want to learn more about the details of supporting a new board there is a good document available on Arduino.cc  Arduino IDE 1.5 3rd party Hardware specification. Another alternative for Mac users is the OS X native Xcode IDE as offered by embedXcode.

How does Galileo Stack up against Raspberry PI

I am interested is to compare Galileo and other DIY single board computers. In this post I want to analyze the Galileo board against the popular Rasberry PI. The first thing to note is that the Rasberry PI is not an Arduino compatible platform. However, there are now extension boards available that allow to use Arduino shields with Raspberry PI. Here are to examples: The first is the AlaMode for Raspberry Pi  the second is the GertDuino: Add-On Board for Raspberry PI . Both boards are priced in the range of a Rasberry PI. So the combination of a Raspberry PI with an Arduino shield extension puts this solution right where the Galileo board is.
Have a look at the table below. It compares the two single board computer’s hardware. The technical data for the Raspberry PI are taken from WikiPedia.

Rasberry PI Model A Rasberry PI Model B Intel Galileo
Target price: US$ 25 US$ 35 US$69
SoC: Broadcom BCM2835 (CPU, GPU, DSP, SDRAM, and single USB port) Intel Quark X1000
CPU: 700 MHz ARM1176JZF-S CPU 400MHz 32-bit x86 Pentium Class CPU
GPU: Broadcom VideoCore IV @ 250 MHz none
Memory (DRAM): 256 MBytes (shared with GPU) 512 MBytes (shared with GPU) as of 15 October 2012 256 Mbyte
PCIe ports: none PCIe 2.0
USB 2.0 ports: 1 Host 2 Host (from LAN9512) 1 Host,
2 Device
Video input: A CSI input connector allows for the connection of a RPF designed camera module none
Video outputs: Composite RCA (PAL and NTSC), HDMI (rev 1.3 & 1.4), raw LCD Panels via DSI none
Audio outputs: 3.5 mm jack, HDMI, and, as of revision 2 boards, I²S audionull none
Onboard storage: SD/MMC/SDIO 3.3V card slot SD/MMC/SDIO 3.3V card slot
Onboard network: None 10/100 Ethernet (from LAN9512) 10/100 Ethernet
Low-level peripherals: 8 × GPIO, UART, I²C bus, SPI bus with two chip selects, I²S audio +3.3 V, +5 V, ground 16 × GPIO,
UART, I²C bus, SPI
Power ratings: 300 mA (1.5 W) 700 mA (3.5 W) 550 mA (1.9-2.2W)
Power source: 5 volt via MicroUSB or GPIO header 5 Volt
Size: 85.60 mm × 53.98 mm (3.370 in × 2.125 in) 106.68 mm x 71.12 mm (4.2 in x 2.8 in)

The Raspberry PI uses a SoC chip that was originally designed for the set-top box market. Therefore it shows a nice lineup of features on the video side. The integrated HDMI port and on-chip graphics accelerator are testimony to this. However for IoT applications the Quark X1000 SoC used by Galileo offers a really nice selection of interfaces.

What shields are working with Galileo

In my last post I touched on Galileo’s shield interface implementation. 010511_0750_0082_nsmsHaving experimented with a few shields sitting in my drawer, I realized that the implementation of the Arduino shield interface creates a bit of a challenge.  So before you assume that a shield is plug-and-play do your homework. Like with a vintage car they may need some tender loving care.
Here are a few key criteria that you want to check:

  • Hardware
    1. Does my shield draw a lot of current: the Cypress CY8C9540A 40-Bit I/O Expander is only capable of driving 15/25mA instead of 40/50mA
    2. Are you accessing some of the shield pins at a high rate? Without special tricks, the Galileo can only toggle an IO pin at 477 kHz (see also Galileo FAQ and Forum post on this subject).
  • Software
    1. Does the driver directly access Atmel’s  registers? This can be either the IO-port registers, Interrupt, Pulse Width Modulator (PWM) or Timer registers.
    2. Does it use any  AVR libraries? These libraries are exposing the Atmel AVR hardware to the programmer and are therefore a sure sign that you are in for some work to port the Arduino software libraries to the Galileo platform. Search for “#include <avr/” to see how many AVR hardware specific libraries are used.

Well written software libraries only use the official Arduino application programmers Interface (API). However, many of the existing shield libraries directly manipulating AVR hardware registers. This is either done out of ignorance for software portability or out of necessity as to push the hardware to its limits. I expect that with the transition away from the 8-bit AVR (ATmega328) micro controller to the more powerfule 32-bit CPUs ( Arduino Due, Arduino TreGalileo and Olimex-STM32) this problem will gradually subside.
Also note that as of this writing the following Arduino Libraries are supported:

  • SPI
  • EEPROM
  • UART
  • GPIO
  • WiFi

Check the Release Notes on Intel’s site for the latest status.

Galileo is different, is it?

There a quite a number of Arduino boards available. The original Arduinos all used 8-bit AVR micro-controllers from Atmel. Recently Arduino adopted 32-bit ARM cores. In this post I want to look at the features of the Galileo board. The Board is about double the size of an original Arduino board and built around the Intel Quark X1000 controller.Galileo-circuitry_610x534 The Quark family of Intel chips are the new low cost line of x86 controllers that are positioned below the Atom cores.  Quarks are elementary particles that make up the atomic nucleus. Intel positions the Quark family for Internet of Things (IoT) applications. The X1000 controller is the first member of this line. The X1000 offers:

  • 400 MHz 32-bit x86 CPU
  • 512 Kbyte ECC protected embedded SRAM
  • Up to 2Gbyte external ECC protected DDR3 memory
  • 10 /100 Mbps Ethernet port with RMI interface
  • 2 x PCI Express Rev 2.0 ports offering up to 2.5 GT/s data transfer rates
  • 2 x USB 2.0 Host ports
  • 1 x USB 2.0 Device port
  • SDIO card interface
  • 2 x I2C Master interfaces up to 400 Kbit/s
  • 16 x GPIO
  • 2 x SPI Master controllers
  • 2 x 16550 compliant UART supporting baud rates from 300 to 2764800
  • Real Time Clock (RTC)

The controller is packed into a Flip-Chip Ball Grid Array (FCBGA) package with 393 solder balls that come with a 0.593 mm ball pitch. The package dimensions are 15mm x 15mm. With this kind of a package hand soldering is out of the picture.
Noteworthy is the implementation of the Arduino shield interface. The interface is pretty much designed with external components. For the GPIO/PWM digital shield pins a Cypress CY8C9540A 40-Bit I/O Expander with EEPROM  is used. The analog shield pins use an Analog Device AD7298 8-Channel, 1 MSPS, 12-Bit SAR Analog to Digital Converter (ADC) with Temperature Sensor . The Quark controller uses I2C serial interface to control the PGIO/PWM CY8C9540A device and the SPI for the ADC AD7298.