Browse Source

Support for SI7021 sensor, I2C enabled by default using Wire library

fastled
Xose Pérez 6 years ago
parent
commit
f8e7a564f1
9 changed files with 282 additions and 32 deletions
  1. +14
    -5
      code/espurna/config/general.h
  2. +4
    -0
      code/espurna/config/hardware.h
  3. +15
    -2
      code/espurna/config/sensors.h
  4. +5
    -0
      code/espurna/espurna.ino
  5. +42
    -9
      code/espurna/i2c.ino
  6. +36
    -14
      code/espurna/power_emon.ino
  7. +6
    -1
      code/espurna/sensor.ino
  8. +1
    -1
      code/espurna/sensors/DallasSensor.h
  9. +159
    -0
      code/espurna/sensors/SI7021Sensor.h

+ 14
- 5
code/espurna/config/general.h View File

@ -664,13 +664,22 @@ PROGMEM const char* const custom_reset_string[] = {
// -----------------------------------------------------------------------------
#ifndef I2C_SUPPORT
#define I2C_SUPPORT 0 // I2C enabled (1.98Kb)
#define I2C_SUPPORT 1 // I2C enabled (1.98Kb)
#endif
#define I2C_SDA_PIN 4 // SDA GPIO
#define I2C_SCL_PIN 14 // SCL GPIO
#define I2C_CLOCK_STRETCH_TIME 200 // BRZO clock stretch time
#define I2C_SCL_FREQUENCY 1000 // BRZO SCL frequency
#define I2C_USE_BRZO 0 // Use brzo_i2c library or standard Wire
#ifndef I2C_SDA_PIN
#define I2C_SDA_PIN SDA // SDA GPIO (Sonoff => 4)
#endif
#ifndef I2C_SCL_PIN
#define I2C_SCL_PIN SCL // SCL GPIO (Sonoff => 14)
#endif
#define I2C_CLOCK_STRETCH_TIME 50000 // BRZO clock stretch time
#define I2C_SCL_FREQUENCY 200 // BRZO SCL frequency
#define I2C_CLEAR_BUS 0 // Clear I2C bus at boot
// -----------------------------------------------------------------------------
// DOMOTICZ


+ 4
- 0
code/espurna/config/hardware.h View File

@ -222,6 +222,10 @@
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
// Jack is connected to GPIO14 (and with a small hack to GPIO4)
//#define I2C_SDA_PIN 4
//#define I2C_SCL_PIN 14
#elif defined(ITEAD_SONOFF_SV)
// Info


+ 15
- 2
code/espurna/config/sensors.h View File

@ -39,7 +39,7 @@
#endif
#ifndef DHT_PIN
#define DHT_PIN 12
#define DHT_PIN 14
#endif
#ifndef DHT_TYPE
@ -115,6 +115,19 @@
#define COUNTER_DEBOUNCE 10 // Do not register events within less than 10 millis
#define COUNTER_TOPIC "counter" // Default topic for MQTT, API and InfluxDB
//--------------------------------------------------------------------------------
// SI7021 temperature & humidity sensor
// Enable support by passing SI7021_SUPPORT=1 build flag
//--------------------------------------------------------------------------------
#ifndef SI7021_SUPPORT
#define SI7021_SUPPORT 0
#endif
#ifndef SI7021_ADDRESS
#define SI7021_ADDRESS 0x40
#endif
//--------------------------------------------------------------------------------
// DS18B20 temperature sensor
// Enable support by passing DS18B20_SUPPORT=1 build flag
@ -125,7 +138,7 @@
#endif
#ifndef DS18B20_PIN
#define DS18B20_PIN 13
#define DS18B20_PIN 14
#endif
#ifndef DS18B20_PULLUP


+ 5
- 0
code/espurna/espurna.ino View File

@ -298,7 +298,12 @@ void setup() {
#endif
#if I2C_SUPPORT
i2cSetup();
#if I2C_CLEAR_BUS
i2cClearBus();
#endif
i2cScan();
#endif
#ifdef ITEAD_SONOFF_RFBRIDGE
rfbSetup();
#endif


+ 42
- 9
code/espurna/i2c.ino View File

@ -8,7 +8,16 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
#if I2C_SUPPORT
#if I2C_USE_BRZO
#include "brzo_i2c.h"
unsigned long _i2c_scl_frequency = 0;
#else
#include "Wire.h"
#endif
// -----------------------------------------------------------------------------
// Private
// -----------------------------------------------------------------------------
int _i2cClearbus(int sda, int scl) {
@ -93,13 +102,28 @@ int _i2cClearbus(int sda, int scl) {
}
// -----------------------------------------------------------------------------
// Utils
// -----------------------------------------------------------------------------
void i2cClearBus() {
unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
DEBUG_MSG_P(PSTR("[I2C] Clear bus (response: %d)\n"), _i2cClearbus(sda, scl));
}
bool i2cCheck(unsigned char address) {
brzo_i2c_start_transaction(address, I2C_SCL_FREQUENCY);
brzo_i2c_ACK_polling(1000);
return brzo_i2c_end_transaction();
#if I2C_USE_BRZO
brzo_i2c_start_transaction(address, _i2c_scl_frequency);
brzo_i2c_ACK_polling(1000);
return brzo_i2c_end_transaction();
#else
Wire.beginTransmission(address);
return Wire.endTransmission();
#endif
}
unsigned char i2cFind(size_t size, unsigned char * addresses) {
unsigned char i2cFindFirst(size_t size, unsigned char * addresses) {
for (unsigned char i=0; i<size; i++) {
if (i2cCheck(addresses[i]) == 0) return addresses[i];
}
@ -113,17 +137,26 @@ void i2cScan() {
if (error == 0) {
DEBUG_MSG_P(PSTR("[I2C] Device found at address 0x%02X\n"), address);
nDevices++;
} else if (error != 32) {
//DEBUG_MSG_P(PSTR("[I2C] Unknown error at address 0x%02X\n"), address);
}
}
if (nDevices == 0) DEBUG_MSG_P(PSTR("[I2C] No devices found\n"));
}
void i2cSetup() {
DEBUG_MSG_P(PSTR("[I2C] Using GPIO%d for SDA and GPIO%d for SCL\n"), I2C_SDA_PIN, I2C_SCL_PIN);
//DEBUG_MSG_P(PSTR("[I2C] Clear bus (response: %d)\n"), _i2cClearbus(I2C_SDA_PIN, I2C_SCL_PIN));
brzo_i2c_setup(I2C_SDA_PIN, I2C_SCL_PIN, I2C_CLOCK_STRETCH_TIME);
unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
#if I2C_USE_BRZO
unsigned long cst = getSetting("i2cCST", I2C_CLOCK_STRETCH_TIME).toInt();
_i2c_scl_frequency = getSetting("i2cFreq", I2C_SCL_FREQUENCY).toInt();
brzo_i2c_setup(sda, scl, cst);
#else
Wire.begin(sda, scl);
#endif
DEBUG_MSG_P(PSTR("[I2C] Using GPIO%d for SDA and GPIO%d for SCL\n"), sda, scl);
}
#endif

+ 36
- 14
code/espurna/power_emon.ino View File

@ -17,7 +17,11 @@ EmonLiteESP _emon;
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
#if I2C_USE_BRZO
#include "brzo_i2c.h"
#else
#include "Wire.h"
#endif
// ADC121 Registers
#define ADC121_REG_RESULT 0x00
@ -45,15 +49,26 @@ unsigned int currentCallback() {
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
uint8_t buffer[2];
brzo_i2c_start_transaction(ADC121_I2C_ADDRESS, I2C_SCL_FREQUENCY);
buffer[0] = ADC121_REG_RESULT;
brzo_i2c_write(buffer, 1, false);
brzo_i2c_read(buffer, 2, false);
brzo_i2c_end_transaction();
unsigned int value;
value = (buffer[0] & 0x0F) << 8;
value |= buffer[1];
#if I2C_USE_BRZO
uint8_t buffer[2];
i2cStart(ADC121_I2C_ADDRESS);
buffer[0] = ADC121_REG_RESULT;
brzo_i2c_write(buffer, 1, false);
brzo_i2c_read(buffer, 2, false);
brzo_i2c_end_transaction();
value = (buffer[0] & 0x0F) << 8;
value |= buffer[1];
#else
Wire.beginTransmission(ADC121_I2C_ADDRESS);
Wire.write(ADC121_REG_RESULT);
Wire.endTransmission();
Wire.requestFrom(ADC121_I2C_ADDRESS, 2);
value = (Wire.read() & 0x0F) << 8;
value = value + Wire.read();
#endif
return value;
#endif // POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
@ -133,12 +148,19 @@ void _powerSetupProvider() {
_emon.initCurrent(currentCallback, EMON_ADC_BITS, EMON_REFERENCE_VOLTAGE, EMON_CURRENT_RATIO);
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
uint8_t buffer[2];
buffer[0] = ADC121_REG_CONFIG;
buffer[1] = 0x00;
brzo_i2c_start_transaction(ADC121_I2C_ADDRESS, I2C_SCL_FREQUENCY);
brzo_i2c_write(buffer, 2, false);
brzo_i2c_end_transaction();
#if I2C_USE_BRZO
uint8_t buffer[2];
buffer[0] = ADC121_REG_CONFIG;
buffer[1] = 0x00;
brzo_i2c_start_transaction(ADC121_I2C_ADDRESS, I2C_SCL_FREQUENCY);
brzo_i2c_write(buffer, 2, false);
brzo_i2c_end_transaction();
#else
Wire.beginTransmission(ADC121_I2C_ADDRESS);
Wire.write(ADC121_REG_CONFIG);
Wire.write(0x00);
Wire.endTransmission();
#endif
#endif
_emon.warmup();


+ 6
- 1
code/espurna/sensor.ino View File

@ -219,6 +219,11 @@ void sensorInit() {
sensorRegister(new DallasSensor(DS18B20_PIN, SENSOR_READ_INTERVAL, DS18B20_PULLUP));
#endif
#if SI7021_SUPPORT
#include "sensors/SI7021Sensor.h"
sensorRegister(new SI7021Sensor(SI7021_ADDRESS));
#endif
#if ANALOG_SUPPORT
#include "sensors/AnalogSensor.h"
sensorRegister(new AnalogSensor(ANALOG_PIN));
@ -295,7 +300,7 @@ void sensorLoop() {
_sensorTick();
// Check if we should read new data
if ((millis() - last_update > SENSOR_READ_INTERVAL) || (last_update == 0)) {
if (millis() - last_update > SENSOR_READ_INTERVAL) {
last_update = millis();
report_count = (report_count + 1) % SENSOR_REPORT_EVERY;


+ 1
- 1
code/espurna/sensors/DallasSensor.h View File

@ -114,7 +114,7 @@ class DallasSensor : public BaseSensor {
// Descriptive name of the sensor
String name() {
char buffer[20];
snprintf(buffer, sizeof(buffer), "OneWire @ GPIO%d", _gpio);
snprintf(buffer, sizeof(buffer), "Dallas @ GPIO%d", _gpio);
return String(buffer);
}


+ 159
- 0
code/espurna/sensors/SI7021Sensor.h View File

@ -0,0 +1,159 @@
// -----------------------------------------------------------------------------
// DHT Sensor
// -----------------------------------------------------------------------------
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#if I2C_USE_BRZO
#include <brzo_i2c.h>
#else
#include <Wire.h>
#endif
#define SI7021_SCL_FREQUENCY 200
#define SI7021_CHIP_SI7021 0x15
#define SI7021_CHIP_HTU21D 0x32
#define SI7021_CMD_TMP_HOLD 0xE3
#define SI7021_CMD_HUM_HOLD 0xE5
#define SI7021_CMD_TMP_NOHOLD 0xF3
#define SI7021_CMD_HUM_NOHOLD 0xF5
#define SI7021_ERROR_UNKNOW_CHIP -1
#define SI7021_ERROR_TIMEOUT -2
#define SI7021_ERROR_CRC -3
class SI7021Sensor : public BaseSensor {
public:
SI7021Sensor(unsigned char address = 0x40): BaseSensor() {
// Asume I2C already started
_address = address;
// Check device
#if I2C_USE_BRZO
uint8_t buffer[2] = {0xFC, 0xC9};
brzo_i2c_start_transaction(_address, SI7021_SCL_FREQUENCY);
brzo_i2c_write(buffer, 2, false);
brzo_i2c_read(buffer, 1, false);
brzo_i2c_end_transaction();
_chip = buffer[0];
#else
Wire.beginTransmission(_address);
Wire.write(0xFC);
Wire.write(0xC9);
Wire.endTransmission();
Wire.requestFrom(_address, (unsigned char) 1);
_chip = Wire.read();
#endif
if ((_chip != SI7021_CHIP_SI7021) & (_chip != SI7021_CHIP_HTU21D)) {
_error = SI7021_ERROR_UNKNOW_CHIP;
} else {
_count = 2;
}
}
// Descriptive name of the sensor
String name() {
char buffer[20];
snprintf(buffer, sizeof(buffer), "%s @ I2C (0x%02X)", chipAsString().c_str(), _address);
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return name();
}
// Type for slot # index
magnitude_t type(unsigned char index) {
if (index < _count) {
_error = SENSOR_ERROR_OK;
if (index == 0) return MAGNITUDE_TEMPERATURE;
if (index == 1) return MAGNITUDE_HUMIDITY;
}
_error = SENSOR_ERROR_OUT_OF_RANGE;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
if (index < _count) {
_error = SENSOR_ERROR_OK;
double value;
if (index == 0) {
value = read(SI7021_CMD_TMP_NOHOLD);
value = (175.72 * value / 65536) - 46.85;
}
if (index == 1) {
value = read(SI7021_CMD_HUM_NOHOLD);
value = (125.0 * value / 65536) - 6;
value = constrain(value, 0, 100);
}
return value;
}
_error = SENSOR_ERROR_OUT_OF_RANGE;
return 0;
}
protected:
unsigned int read(uint8_t command) {
unsigned char bytes = (command == 0xE0) ? 2 : 3;
#if I2C_USE_BRZO
#else
Wire.beginTransmission(_address);
Wire.write(command);
Wire.endTransmission();
#endif
// When not using clock stretching (*_NOHOLD commands) delay here
// is needed to wait for the measurement.
// According to datasheet the max. conversion time is ~22ms
unsigned long start = millis();
while (millis() - start < 50) delay(1);
#if I2C_USE_BRZO
unsigned int msb = 0;
unsigned int lsb = 0;
#else
Wire.requestFrom(_address, bytes);
if (Wire.available() != bytes) return 100;
unsigned int msb = Wire.read();
unsigned int lsb = Wire.read();
#endif
// Clear the last to bits of LSB to 00.
// According to datasheet LSB of RH is always xxxxxx10
lsb &= 0xFC;
unsigned int value = (msb << 8) | lsb;
return value;
}
unsigned char chip() {
return _chip;
}
String chipAsString() {
if (_chip == SI7021_CHIP_SI7021) return String("SI7021");
if (_chip == SI7021_CHIP_HTU21D) return String("HTU21D");
return String("Unknown");
}
unsigned char _address;
unsigned char _chip;
bool _found = false;
};

Loading…
Cancel
Save