From 08eaa8ddb799fcfcc9970cecdb7b51a849c1ad7f Mon Sep 17 00:00:00 2001 From: Asbelos Date: Tue, 14 Jun 2022 17:21:11 +0100 Subject: [PATCH] I2C overlap checks (working but messy) Needs disgnostic clean and promotion of i2c address to IODevice. --- IODevice.cpp | 38 +++++++++++++++++++++++++++++++------- IODevice.h | 11 ++++++++--- IO_AnalogueInputs.h | 2 +- IO_GPIOBase.h | 6 +++++- IO_MCP23008.h | 2 +- IO_MCP23017.h | 2 +- IO_PCA9685.cpp | 2 +- IO_PCF8574.h | 2 +- IO_VL53L0X.h | 2 +- 9 files changed, 50 insertions(+), 17 deletions(-) diff --git a/IODevice.cpp b/IODevice.cpp index d320c09..c6af137 100644 --- a/IODevice.cpp +++ b/IODevice.cpp @@ -61,10 +61,14 @@ void IODevice::begin() { // Allocates 32 pins 100-131 PCA9685::create(100, 16, 0x40); PCA9685::create(116, 16, 0x41); + PCA9685::create(132, 16, 0x41); // should fail + PCA9685::create(118, 4, 0x42); // should fail + // Predefine two MCP23017 module 0x20/0x21 // Allocates 32 pins 164-195 MCP23017::create(164, 16, 0x20); MCP23017::create(180, 16, 0x21); +MCP23017::create(196, 16, 0x40); // should fail // Call the begin() methods of each configured device in turn for (IODevice *dev=_firstDevice; dev!=NULL; dev = dev->_nextDevice) { @@ -275,16 +279,36 @@ IODevice *IODevice::findDevice(VPIN vpin) { // Private helper function to check for vpin overlap. Run during setup only. // returns true if pins DONT overlap with existing device -bool IODevice::checkNoOverlap(VPIN firstPin, uint8_t nPins) { - for (VPIN testPin=firstPin; testPin< (firstPin+nPins); testPin++) - if (findDevice(testPin)) { - DIAG(F("WARNING HAL Pin %d overlap, re-definition of pins %d to %d ignored."), - testPin, firstPin, firstPin+nPins); - return false; +bool IODevice::checkNoOverlap(VPIN firstPin, uint8_t nPins, uint8_t i2cAddress) { + DIAG(F("Check no overlap %d %d 0x%x"), firstPin,nPins,i2cAddress); + VPIN lastPin=firstPin+nPins-1; + for (IODevice *dev = _firstDevice; dev != 0; dev = dev->_nextDevice) { + + // check for pin range overlaps (verbose but compiler will fix that) + VPIN firstDevPin=dev->_firstVpin; + VPIN lastDevPin=firstDevPin+dev->_nPins-1; + bool noOverlap= firstPin>lastDevPin || lastPin_matchI2CAddress(i2cAddress)) { + DIAG(F("WARNING HAL Overlap. i2c Addr 0x%x ignored."),i2cAddress); + return false; + } } - return true; + return true; // no overlaps... OK to go on with constructor } + bool IODevice::_matchI2CAddress(uint8_t i2cAddress) { + // Overridden for I2c devices. + (void) i2cAddress; + return false; + } + //================================================================================================================== // Static data //------------------------------------------------------------------------------------------------------------------ diff --git a/IODevice.h b/IODevice.h index a688ba3..77325c2 100644 --- a/IODevice.h +++ b/IODevice.h @@ -228,8 +228,11 @@ protected: // pin low if an input changes state. int16_t _gpioInterruptPin = -1; + // non-i2c hal drivers return false, i2c drivers override this in IO_GPIOBase + virtual bool _matchI2CAddress(uint8_t i2cAddress); + // Method to check if pins will overlap before creating new device. - static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1); + static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, uint8_t i2cAddress=0); // Static support function for subclass creation static void addDevice(IODevice *newDevice); @@ -242,7 +245,7 @@ private: bool owns(VPIN vpin); // Method to find device handling Vpin static IODevice *findDevice(VPIN vpin); - + uint8_t _I2CAddress; IODevice *_nextDevice = 0; unsigned long _nextEntryTime; static IODevice *_firstDevice; @@ -284,7 +287,9 @@ private: void updatePosition(uint8_t pin); void writeDevice(uint8_t pin, int value); void _display() override; - + virtual bool _matchI2CAddress(uint8_t i2caddress) override { + return i2caddress && i2caddress==_I2CAddress; + } uint8_t _I2CAddress; // 0x40-0x43 possible struct ServoData { diff --git a/IO_AnalogueInputs.h b/IO_AnalogueInputs.h index 5849501..1af351d 100644 --- a/IO_AnalogueInputs.h +++ b/IO_AnalogueInputs.h @@ -60,7 +60,7 @@ class ADS111x: public IODevice { public: static void create(VPIN firstVpin, int nPins, uint8_t i2cAddress) { - if (checkNoOverlap(firstVpin,nPins)) new ADS111x(firstVpin, nPins, i2cAddress); + if (checkNoOverlap(firstVpin,nPins,i2cAddress)) new ADS111x(firstVpin, nPins, i2cAddress); } private: ADS111x(VPIN firstVpin, int nPins, uint8_t i2cAddress) { diff --git a/IO_GPIOBase.h b/IO_GPIOBase.h index 3bc75af..d2a1339 100644 --- a/IO_GPIOBase.h +++ b/IO_GPIOBase.h @@ -45,9 +45,13 @@ protected: int _read(VPIN vpin) override; void _display() override; void _loop(unsigned long currentMicros) override; + virtual bool _matchI2CAddress(uint8_t i2cAddress) override { + DIAG(F("MatchI2c %x %x"), i2cAddress, _I2CAddress); + return (i2cAddress && i2cAddress==_I2CAddress); + } // Data fields - uint8_t _I2CAddress; + uint8_t _I2CAddress; // Allocate enough space for all input pins T _portInputState; T _portOutputState; diff --git a/IO_MCP23008.h b/IO_MCP23008.h index 916ebbe..aa4679b 100644 --- a/IO_MCP23008.h +++ b/IO_MCP23008.h @@ -25,7 +25,7 @@ class MCP23008 : public GPIOBase { public: static void create(VPIN firstVpin, uint8_t nPins, uint8_t I2CAddress, int interruptPin=-1) { - if (checkNoOverlap(firstVpin, nPins)) new MCP23008(firstVpin, nPins, I2CAddress, interruptPin); + if (checkNoOverlap(firstVpin, nPins,I2CAddress)) new MCP23008(firstVpin, nPins, I2CAddress, interruptPin); } private: diff --git a/IO_MCP23017.h b/IO_MCP23017.h index e6ff5be..65769f6 100644 --- a/IO_MCP23017.h +++ b/IO_MCP23017.h @@ -31,7 +31,7 @@ class MCP23017 : public GPIOBase { public: static void create(VPIN vpin, int nPins, uint8_t I2CAddress, int interruptPin=-1) { - if (checkNoOverlap(vpin, nPins)) new MCP23017(vpin, min(nPins,16), I2CAddress, interruptPin); + if (checkNoOverlap(vpin, nPins, I2CAddress)) new MCP23017(vpin, min(nPins,16), I2CAddress, interruptPin); } private: diff --git a/IO_PCA9685.cpp b/IO_PCA9685.cpp index ae6d3dd..3d7c347 100644 --- a/IO_PCA9685.cpp +++ b/IO_PCA9685.cpp @@ -39,7 +39,7 @@ static void writeRegister(byte address, byte reg, byte value); // Create device driver instance. void PCA9685::create(VPIN firstVpin, int nPins, uint8_t I2CAddress) { - if (checkNoOverlap(firstVpin, nPins)) new PCA9685(firstVpin, nPins, I2CAddress); + if (checkNoOverlap(firstVpin, nPins,I2CAddress)) new PCA9685(firstVpin, nPins, I2CAddress); } // Configure a port on the PCA9685. diff --git a/IO_PCF8574.h b/IO_PCF8574.h index d3f98c8..44eccad 100644 --- a/IO_PCF8574.h +++ b/IO_PCF8574.h @@ -43,7 +43,7 @@ class PCF8574 : public GPIOBase { public: static void create(VPIN firstVpin, uint8_t nPins, uint8_t I2CAddress, int interruptPin=-1) { - if (checkNoOverlap(firstVpin, nPins)) new PCF8574(firstVpin, nPins, I2CAddress, interruptPin); + if (checkNoOverlap(firstVpin, nPins,I2CAddress)) new PCF8574(firstVpin, nPins, I2CAddress, interruptPin); } private: diff --git a/IO_VL53L0X.h b/IO_VL53L0X.h index 47204d5..9d51345 100644 --- a/IO_VL53L0X.h +++ b/IO_VL53L0X.h @@ -130,7 +130,7 @@ private: public: static void create(VPIN firstVpin, int nPins, uint8_t i2cAddress, uint16_t onThreshold, uint16_t offThreshold, VPIN xshutPin = VPIN_NONE) { - if (checkNoOverlap(firstVpin, nPins)) new VL53L0X(firstVpin, nPins, i2cAddress, onThreshold, offThreshold, xshutPin); + if (checkNoOverlap(firstVpin, nPins,i2cAddress)) new VL53L0X(firstVpin, nPins, i2cAddress, onThreshold, offThreshold, xshutPin); } protected: