SBC

RedBear BLE Module

Bluetooth Low Energy (BLE) transceiver board. BLE is a new protocol introduced in the 4.0 revision of the Bluetooth standard. It is a wireless personal area network (PAN) technology aimed at novel applications in the healthcare, fitness, security, and home entertainment industries.  BLE is not backward-compatible with the previous Bluetooth protocol. However it uses the same 2.4 GHz frequency bands but a simpler modulation scheme. The picture below shows the RedBearLab BLE Mini Board.MKRBL2-2T
The module is a combo of a RBT01 BLE module featuring the Ti CC2540 Single chip Bluetooth (SoC) and a breakout board that offers a micro USB connector and a 3.3Volt UART connectors. The main reason this board caught my attention is the fact that it also has solder points for additional GPIOs on the back of the board. These GPIOs can be custom programed. So it should be possible to hook up  I2C or SPI sensors to the board and with a bit of software be able to monitor them.
Using such a BLE board  is not exactly an IoT solution as the connectivity to the cloud would have to be implemented with for example a Wireless enhanced Gallileo. Also the BLE’s range is rather limited. However when it comes to power consumption BLE has a leg up as it was specifically designed for very low power.

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.

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.

Is Edison competing with Galileo

Last summer at the Maker Fair in Rome Intel announced the Galileo single board computer . This week at CES 2014 in Las Vegas Intel followed up with another initiative that carries an inventors name. This time it is Edison. The Edison board is more advanced take on the Quark System on a Chip (SoC) based single board. The board is only the size of an industry standard SD card. So don’t expect to solder it yourself.
edison
However the card is a full featured single board computer that will offer support for multiple operating systems (OS).  The integrated WiFi will turn any device equipped with an Edison into an IoT solution.
Intel also promised to release design files that will make it easy to  integrate Edison into your own project.  Among the tool vendors that will support Edison is Autodesk. The company just announced the  acquisition of circuit.io. This online PCB design tool is now a part of Autodesk’s 123D design suite.
For those that cannot wait and want something today the Electric Imp Wireless SD-CARD is an interesting alternative. This card is clearly not as powerful as an Edison. However given the creativity that innovators have displayed around the meager Arduino 8-bit AVR CPU  it may still be plenty.
El_Imp