Browse Source

Improved I2C auto-discover avoiding collissions

fastled
Xose Pérez 6 years ago
parent
commit
4e454331d4
8 changed files with 95 additions and 43 deletions
  1. +3
    -1
      code/espurna/config/prototypes.h
  2. +2
    -2
      code/espurna/config/sensors.h
  3. +43
    -3
      code/espurna/i2c.ino
  4. +5
    -11
      code/espurna/sensors/BMX280Sensor.h
  5. +32
    -0
      code/espurna/sensors/BaseSensor.h
  6. +3
    -8
      code/espurna/sensors/EmonADC121Sensor.h
  7. +3
    -8
      code/espurna/sensors/EmonADS1X15Sensor.h
  8. +4
    -10
      code/espurna/sensors/SI7021Sensor.h

+ 3
- 1
code/espurna/config/prototypes.h View File

@ -51,7 +51,9 @@ template<typename T> String getSetting(const String& key, unsigned int index, T
// -----------------------------------------------------------------------------
// I2C
// -----------------------------------------------------------------------------
unsigned char i2cFindFirst(size_t size, unsigned char * addresses);
unsigned char i2cFindAndLock(size_t size, unsigned char * addresses);
bool i2cGetLock(unsigned char address);
bool i2cReleaseLock(unsigned char address);
// -----------------------------------------------------------------------------
// Debug


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

@ -93,7 +93,7 @@
//--------------------------------------------------------------------------------
#ifndef BMX280_SUPPORT
#define BMX280_SUPPORT 0
#define BMX280_SUPPORT 1
#endif
#ifndef BMX280_ADDRESS
@ -283,7 +283,7 @@
//--------------------------------------------------------------------------------
#ifndef SI7021_SUPPORT
#define SI7021_SUPPORT 0
#define SI7021_SUPPORT 1
#endif
#ifndef SI7021_ADDRESS


+ 43
- 3
code/espurna/i2c.ino View File

@ -8,6 +8,9 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
#if I2C_SUPPORT
#include <vector>
std::vector<unsigned char> _i2c_locked;
#if I2C_USE_BRZO
#include "brzo_i2c.h"
unsigned long _i2c_scl_frequency = 0;
@ -123,13 +126,50 @@ bool i2cCheck(unsigned char address) {
#endif
}
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];
bool i2cGetLock(unsigned char address) {
for (unsigned char i=0; i<_i2c_locked.size(); i++) {
if (_i2c_locked[i] == address) return false;
}
_i2c_locked.push_back(address);
DEBUG_MSG_P(PSTR("[I2C] Address 0x%02X locked\n"), address);
return true;
}
bool i2cReleaseLock(unsigned char address) {
for (unsigned char i=0; i<_i2c_locked.size(); i++) {
if (_i2c_locked[i] == address) {
_i2c_locked.erase(_i2c_locked.begin() + i);
return true;
}
}
return false;
}
unsigned char i2cFind(size_t size, unsigned char * addresses, unsigned char &start) {
for (unsigned char i=start; i<size; i++) {
if (i2cCheck(addresses[i]) == 0) {
start = i;
return addresses[i];
}
}
return 0;
}
unsigned char i2cFind(size_t size, unsigned char * addresses) {
unsigned char start = 0;
return i2cFind(size, addresses, start);
}
unsigned char i2cFindAndLock(size_t size, unsigned char * addresses) {
unsigned char start = 0;
unsigned char address = 0;
while (address = i2cFind(size, addresses, start)) {
if (i2cGetLock(address)) break;
start++;
}
return address;
}
void i2cScan() {
unsigned char nDevices = 0;
for (unsigned char address = 1; address < 127; address++) {


+ 5
- 11
code/espurna/sensors/BMX280Sensor.h View File

@ -35,17 +35,12 @@ class BMX280Sensor : public BaseSensor {
if (!_dirty) return;
_dirty = false;
_chip = 0;
// Discover
if (_address == 0) {
unsigned char addresses[] = {0x76, 0x77};
_address = i2cFindFirst(2, addresses);
}
if (_address == 0) {
_error = SENSOR_ERROR_UNKNOWN_ID;
_chip = 0;
return;
}
// I2C auto-discover
unsigned char addresses[] = {0x76, 0x77};
_address = lock_i2c(_address, sizeof(addresses), addresses);
if (_address == 0) return;
// Init
init();
@ -207,7 +202,6 @@ class BMX280Sensor : public BaseSensor {
BME280 * bme;
unsigned char _chip;
unsigned char _address = 0;
unsigned long _measurement_delay;
};

+ 32
- 0
code/espurna/sensors/BaseSensor.h View File

@ -46,6 +46,7 @@ typedef enum magnitude_t {
#define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
#define SENSOR_ERROR_UNKNOWN_ID 4 // Sensor did not report a known ID
#define SENSOR_ERROR_CRC 5 // Sensor data corrupted
#define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
class BaseSensor {
@ -81,6 +82,34 @@ class BaseSensor {
// Current value for slot # index
virtual double value(unsigned char index) {}
// Specific for I2C sensors
unsigned char lock_i2c(unsigned char address, size_t size, unsigned char * addresses) {
// Check if we should release a previously locked address
if (_previous_address != address) {
i2cReleaseLock(_previous_address);
}
// If we have already an address, check it is not locked
if (address && !i2cGetLock(address)) {
_error = SENSOR_ERROR_I2C;
// If we don't have an address...
} else {
// Trigger auto-discover
address = i2cFindAndLock(size, addresses);
// If still nothing exit with error
if (address == 0) _error = SENSOR_ERROR_I2C;
}
_previous_address = address;
return address;
}
// Return sensor status (true for ready)
bool status() { return _error == 0; }
@ -119,6 +148,9 @@ class BaseSensor {
bool _dirty = true;
unsigned char _count = 0;
// I2C
unsigned char _previous_address = 0;
unsigned char _address = 0;
};


+ 3
- 8
code/espurna/sensors/EmonADC121Sensor.h View File

@ -58,14 +58,9 @@ class EmonADC121Sensor : public EmonAnalogSensor {
_dirty = false;
// Discover
if (_address == 0) {
unsigned char addresses[] = {0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x58, 0x59, 0x5A};
_address = i2cFindFirst(9, addresses);
}
if (_address == 0) {
_error = SENSOR_ERROR_UNKNOWN_ID;
return;
}
unsigned char addresses[] = {0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x58, 0x59, 0x5A};
_address = lock_i2c(_address, sizeof(addresses), addresses);
if (_address == 0) return;
// Init sensor
#if I2C_USE_BRZO


+ 3
- 8
code/espurna/sensors/EmonADS1X15Sensor.h View File

@ -141,14 +141,9 @@ class EmonADS1X15Sensor : public EmonSensor {
_dirty = false;
// Discover
if (_address == 0) {
unsigned char addresses[] = {0x48, 0x49, 0x4A, 0x4B};
_address = i2cFindFirst(4, addresses);
}
if (_address == 0) {
_error = SENSOR_ERROR_UNKNOWN_ID;
return;
}
unsigned char addresses[] = {0x48, 0x49, 0x4A, 0x4B};
_address = lock_i2c(_address, sizeof(addresses), addresses);
if (_address == 0) return;
// Calculate ports
_ports = 0;


+ 4
- 10
code/espurna/sensors/SI7021Sensor.h View File

@ -46,15 +46,10 @@ class SI7021Sensor : public BaseSensor {
if (!_dirty) return;
_dirty = false;
// Discover
if (_address == 0) {
unsigned char addresses[] = {0x40};
_address = i2cFindFirst(1, addresses);
}
if (_address == 0) {
_error = SENSOR_ERROR_UNKNOWN_ID;
return;
}
// I2C auto-discover
unsigned char addresses[] = {0x40};
_address = lock_i2c(_address, sizeof(addresses), addresses);
if (_address == 0) return;
// Check device
#if I2C_USE_BRZO
@ -182,7 +177,6 @@ class SI7021Sensor : public BaseSensor {
return String("Unknown");
}
unsigned char _address;
unsigned char _chip;
};

Loading…
Cancel
Save