This is my .ino file :
// This #include statement was automatically added by the Spark IDE.
#include "BOSCH.h"
// This #include statement was automatically added by the Spark IDE.
#include "HDC100x.h"
// This #include statement was automatically added by the Spark IDE.
#include "OPT3001.h"
// D0 = SDA
// D1 = SCL
//#define DEBUG_PIN
#define VENDOR_LUX 1
#define DEVICE_LUX 2
#define VENDOR_HDC 3
#define DEVICE_HDC 4
#define VENDOR_BOSCH 5
// Define the pins we're going to call pinMode on
int led = D7; // This one is the built-in tiny one to the right of the USB jack
// Declaration of variables
int iRSSI = 0;
double d_Temperature = 0.0;
unsigned int ui_RH = 0;
double d_Pressure = 0.0;
double d_Lux = 0.0;
// Declartion of function
int func_iVerifyID(String ID);
void setup_test();
void test_pin();
void setup_test() {
pinMode(D0, OUTPUT);
pinMode(D1, OUTPUT);
}
void test_pin() {
digitalWrite(D0, LOW);
digitalWrite(D1, HIGH);
delay(1000); // Wait for 1 second in off mode
digitalWrite(D0, HIGH);
digitalWrite(D1, LOW);
delay(1000); // Wait for 1 second in off mode
}
// This function return 1 if the command to verify ID or Vendor of a component is correct
// It return -1 if is wrong and -2 if the command doesn't correspond to anything
int func_iVerifyID(String ID){
int iTemp;
unsigned int uiTemp;
switch(ID.toInt())
{
case VENDOR_LUX :
{
uiTemp = funcOPT_ui_get_VendorID();
if(uiTemp == VENDOR_ID_LUX)
{
iTemp = 1;
}
else
{
iTemp = -1;
}
break;
}
case DEVICE_LUX :
{
uiTemp = funcOPT_ui_get_DeviceID();
if(uiTemp == DEVICE_ID_LUX)
{
iTemp = 1;
}
else
{
iTemp = -1;
}
break;
}
case VENDOR_HDC :
{
uiTemp = funcHDC_ui_get_DeviceID();
if(uiTemp == DEVICE_ID_HDC)
{
iTemp = 1;
}
else
{
iTemp = -1;
}
break;
}
case DEVICE_HDC :
{
uiTemp = funcHDC_ui_get_VendorID();
if(uiTemp == VENDOR_ID_HDC)
{
iTemp = 1;
}
else
{
iTemp = -1;
}
break;
}
case VENDOR_BOSCH :
{
uiTemp = funcBOSCH_ui_get_DeviceID();
if(uiTemp == CHIP_ID_BOSCH)
{
iTemp = 1;
}
else
{
iTemp = uiTemp;
}
break;
}
default:
iTemp = -2;
}
return iTemp;
}
// This routine runs only once upon reset
void setup() {
// Register a Spark variables here
Spark.variable("temperature", &d_Temperature, DOUBLE);
Spark.variable("RH", &ui_RH, INT);
Spark.variable("Pressure", &d_Pressure, DOUBLE);
Spark.variable("Lux", &d_Lux, DOUBLE);
Spark.variable("RSSI", &iRSSI, INT);
// Register a Spark Function here
Spark.function("ID_OK",func_iVerifyID);
// Initialize D7 pin as output
// It's important you do this here, inside the setup() function rather than outside it or in the loop function.
pinMode(led, OUTPUT);
// Configure and initialize I2C Bus
Wire.setSpeed(CLOCK_SPEED_100KHZ);
Wire.begin();
// Configure Lux sensor
funcOPT_f_setup();
}
// This routine gets called repeatedly, like once every 5-15 milliseconds.
// Spark firmware interleaves background CPU activity associated with WiFi + Cloud activity with your code.
// Make sure none of your code delays or blocks for too long (like more than 5 seconds), or weird things can happen.
void loop() {
unsigned int uiBoucleFor;
digitalWrite(led, HIGH); // Turn ON the LED pins
//Return the signal strengh of the wifi network
//iRSSI = WiFi.RSSI();
d_Lux = funcOPT_d_get_Lux();
// Test if there is an communication error with sensor
if(d_Lux == ERROR_CONV | d_Lux == ERROR_BUS)
{
if(!RGB.controlled())
{
RGB.control(true);
}
RGB.brightness(255);
RGB.color(255,0,0);
// Try to restart the I2C peripheral
Wire.endTransmission();
Wire.setSpeed(CLOCK_SPEED_100KHZ);
Wire.begin();
}
else
{
if(RGB.controlled())
{
RGB.control(false);
}
}
digitalWrite(led, LOW); // Turn OFF the LED pins
delay(1000); // Wait for 1000mS = 1 second
}
This is my code for communicate with the sensor opt3001.c:
#include <spark_wiring_i2c.h>
#include "math.h"
#include "OPT3001.h"
void funcOPT_f_setup(void)
{
unsigned int uiTemp = DEFAULT_CONFIG;
unsigned char ucMSBConf;
unsigned char ucLSBConf;
// Split config var in two byte
ucMSBConf = (unsigned char) (uiTemp >> 8);
ucLSBConf = (unsigned char) (uiTemp);
// Start a write sequence to OPT3001 in configuration register with last value
Wire.beginTransmission(I2C_ADDRESS_OPT3001);
Wire.write(ADDR_REG_CONFIG);
Wire.write(ucMSBConf);
Wire.write(ucLSBConf);
Wire.endTransmission();
}
double funcOPT_d_get_Lux(void)
{
unsigned char ucTimeout;
unsigned char ucMSBConf;
unsigned char ucLSBConf;
unsigned int ui_mantissa;
unsigned int ui_exponent;
unsigned int ui_result;
unsigned int uiTemp = DEFAULT_CONFIG;
double dTemp;
// Initialize a var with single conversion configuration
uiTemp |= SINGLE_SHOT;
// Split config var in two byte
ucMSBConf = (unsigned char) (uiTemp >> 8);
ucLSBConf = (unsigned char) (uiTemp);
// Start a write sequence to OPT3001 in configuration register to start a measurement
Wire.beginTransmission(I2C_ADDRESS_OPT3001);
Wire.write(ADDR_REG_CONFIG);
Wire.write(ucMSBConf);
Wire.write(ucLSBConf);
Wire.endTransmission();
ucTimeout = 0;
// Waits until the measurement is performed and there was no timeout
do
{
Wire.requestFrom(I2C_ADDRESS_OPT3001,2);
if(Wire.available() != 0)
{
uiTemp = Wire.read();
uiTemp = uiTemp << 8;
uiTemp |= Wire.read();
uiTemp = uiTemp && 0x0080;
if(uiTemp == 0x0080)
{
uiTemp = BUSY;
}
else
{
uiTemp = READY;
}
}
else
{
uiTemp = ERROR_BUS;
ucTimeout = 200;
}
delay(2);
ucTimeout = ucTimeout + 1;
}while(uiTemp == BUSY && ucTimeout < 50);
// Test, if the measurement is sucessful
if(uiTemp == READY)
{
Wire.beginTransmission(I2C_ADDRESS_OPT3001);
Wire.write(ADDR_REG_RESULT);
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS_OPT3001,2);
if(Wire.available() != 0)
{
ui_result = Wire.read();
ui_result = ui_result << 8;
ui_result |= Wire.read();
ui_mantissa = (ui_result & 0xF000) >> 12;
ui_exponent = (ui_result & 0x0FFF);
// Use the equation 3 i(See datasheet page 20) to get Lux
dTemp = 0.01 * pow(2,ui_mantissa) * ui_exponent;
return dTemp;
}
else
{
// Retunr an error bus
return (double)ERROR_BUS;
}
}
else
{
// Return an error in case the conversion failed
return (double)ERROR_CONV;
}
}
unsigned int funcOPT_ui_get_VendorID(void)
{
unsigned int uiTemp;
// Start a write sequence to write the vendor ID address in access register
Wire.beginTransmission(I2C_ADDRESS_OPT3001);
Wire.write(ADDR_REG_VENDOR_ID);
Wire.endTransmission();
// Start a read sequence to get the Vendor ID
Wire.requestFrom(I2C_ADDRESS_OPT3001,2);
if(Wire.available() != 0)
{
uiTemp = Wire.read();
uiTemp = uiTemp << 8;
uiTemp |= Wire.read();
}
else
{
// Return an bus error
uiTemp = ERROR_BUS;
}
// Return the Vendor ID
return uiTemp;
}
unsigned int funcOPT_ui_get_DeviceID(void)
{
unsigned int uiTemp;
// Start a write sequence to write the Device ID address in access register
Wire.beginTransmission(I2C_ADDRESS_OPT3001);
Wire.write(ADDR_REG_DEVICE_ID);
Wire.endTransmission();
// Start a read sequence to get the Device ID
Wire.requestFrom(I2C_ADDRESS_OPT3001,2);
if(Wire.available() != 0)
{
uiTemp = Wire.read();
uiTemp = uiTemp << 8;
uiTemp |= Wire.read();
}
else
{
// Return an bus error
uiTemp = ERROR_BUS;
}
// Return the Device ID
return uiTemp;
}
The last one is the opt3001.h :
#ifndef _OPT3001_H_
#define _OPT3001_H_
#define ADDR_REG_RESULT 0X00
#define ADDR_REG_CONFIG 0X01
#define ADDR_REG_LOW_LIM 0X02
#define ADDR_REG_HIGH_LIM 0X03
#define ADDR_REG_VENDOR_ID 0X7E
#define ADDR_REG_DEVICE_ID 0X7F
#define DEFAULT_CONFIG 0xC810
#define SINGLE_SHOT (0x01 << 9)
#define I2C_ADDRESS_OPT3001 0x44
#define ERROR_CONV 0xFFFFFC
#define BUSY 0xFD
#define READY 0xFE
#define ERROR_BUS 0xFF
#define VENDOR_ID_LUX 0x5449
#define DEVICE_ID_LUX 0x3001
void funcOPT_f_setup(void);
double funcOPT_d_get_Lux(void);
unsigned int funcOPT_ui_get_VendorID(void);
unsigned int funcOPT_ui_get_DeviceID(void);
#endif
I planned to change the setup function of the sensor to accept parameters and really configure the sensor, not use an static config like right now. But its not the source of the problem i think.
I found an errata on the STM32 processor ERRATA. There are bugs with I2C1. Did you know if the workarounds are implemented in low level or wire library ?
I agree with @AndyW for the value of pull-up. My sensors are 3.3V powered so it is even a little high but not really a problem.
Thanks to all of you.