From ebf49f374367726d16c2c1b572f1ecbf9fa60973 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Thu, 4 Jul 2024 13:07:39 +0200 Subject: [PATCH] refactor #78, redo #76 (#79) - Fix #78, prevent infinite loop. (Thanks to devmirek). - Fix #76 (again), update readme.md Comparator Polarity. - add ADS1X15_ERROR_I2C, communication error. - add minimal section in readme.md about error codes. - minor edits. --- ADS1X15.cpp | 58 +++++++++++++++++++++------------ ADS1X15.h | 11 +++---- CHANGELOG.md | 7 ++++ README.md | 80 +++++++++++++++++++++++++++++++++------------- library.json | 2 +- library.properties | 2 +- 6 files changed, 109 insertions(+), 51 deletions(-) diff --git a/ADS1X15.cpp b/ADS1X15.cpp index fdc2b71..c65d710 100644 --- a/ADS1X15.cpp +++ b/ADS1X15.cpp @@ -1,7 +1,7 @@ // // FILE: ADS1X15.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.4.4 +// VERSION: 0.4.5 // DATE: 2013-03-24 // PURPOSE: Arduino library for ADS1015 and ADS1115 // URL: https://github.com/RobTillaart/ADS1X15 @@ -183,8 +183,8 @@ uint8_t ADS1X15::getGain() case ADS1X15_PGA_0_512V: return 8; case ADS1X15_PGA_0_256V: return 16; } - _err = ADS1X15_INVALID_GAIN; - return _err; + _error = ADS1X15_INVALID_GAIN; + return _error; } @@ -219,8 +219,8 @@ float ADS1X15::getMaxVoltage() case ADS1X15_PGA_0_512V: return 0.512; case ADS1X15_PGA_0_256V: return 0.256; } - _err = ADS1X15_INVALID_VOLTAGE; - return _err; + _error = ADS1X15_INVALID_VOLTAGE; + return _error; } @@ -242,8 +242,8 @@ uint8_t ADS1X15::getMode(void) case ADS1X15_MODE_CONTINUE: return 0; case ADS1X15_MODE_SINGLE: return 1; } - _err = ADS1X15_INVALID_MODE; - return _err; + _error = ADS1X15_INVALID_MODE; + return _error; } @@ -402,8 +402,8 @@ int16_t ADS1X15::getComparatorThresholdHigh() int8_t ADS1X15::getError() { - int8_t rv = _err; - _err = ADS1X15_OK; + int8_t rv = _error; + _error = ADS1X15_OK; return rv; } @@ -451,11 +451,17 @@ int16_t ADS1X15::_readADC(uint16_t readmode) _requestADC(readmode); if (_mode == ADS1X15_MODE_SINGLE) { - unsigned long start = millis(); - while (isBusy()) { + uint32_t start = millis(); + // timeout == { 129, 65, 33, 17, 9, 5, 3, 2 } + // a few ms more than max conversion time. + uint8_t timeOut = (128 >> (_datarate >> 5)) + 1; + while (isBusy()) + { yield(); // wait for conversion; yield for ESP. - if ((start + ADS1X15_READ_TIMEOUT_MS) < millis()) + if ( (millis() - start) > timeOut) + { return ADS1X15_ERROR_TIMEOUT; + } } } else @@ -485,7 +491,7 @@ void ADS1X15::_requestADC(uint16_t readmode) _writeRegister(_address, ADS1X15_REG_CONFIG, config); // remember last request type. - _lastRequest = readmode; + _lastRequest = readmode; } @@ -495,7 +501,13 @@ bool ADS1X15::_writeRegister(uint8_t address, uint8_t reg, uint16_t value) _wire->write((uint8_t)reg); _wire->write((uint8_t)(value >> 8)); _wire->write((uint8_t)(value & 0xFF)); - return (_wire->endTransmission() == 0); + int rv = _wire->endTransmission(); + if (rv != 0) + { + _error = ADS1X15_ERROR_I2C; + return false; + } + return true; } @@ -503,15 +515,18 @@ uint16_t ADS1X15::_readRegister(uint8_t address, uint8_t reg) { _wire->beginTransmission(address); _wire->write(reg); - _wire->endTransmission(); - - int rv = _wire->requestFrom((int) address, (int) 2); - if (rv == 2) + int rv = _wire->endTransmission(); + if (rv == 0) { - uint16_t value = _wire->read() << 8; - value += _wire->read(); - return value; + rv = _wire->requestFrom((int) address, (int) 2); + if (rv == 2) + { + uint16_t value = _wire->read() << 8; + value += _wire->read(); + return value; + } } + _error = ADS1X15_ERROR_I2C; return 0x0000; } @@ -742,3 +757,4 @@ void ADS1115::requestADC_Differential_2_3() // -- END OF FILE -- + diff --git a/ADS1X15.h b/ADS1X15.h index a17f606..601dacb 100644 --- a/ADS1X15.h +++ b/ADS1X15.h @@ -2,7 +2,7 @@ // // FILE: ADS1X15.h // AUTHOR: Rob Tillaart -// VERSION: 0.4.4 +// VERSION: 0.4.5 // DATE: 2013-03-24 // PURPOSE: Arduino library for ADS1015 and ADS1115 // URL: https://github.com/RobTillaart/ADS1X15 @@ -12,7 +12,7 @@ #include "Arduino.h" #include "Wire.h" -#define ADS1X15_LIB_VERSION (F("0.4.4")) +#define ADS1X15_LIB_VERSION (F("0.4.5")) // allow compile time default address // address in { 0x48, 0x49, 0x4A, 0x4B }, no test... @@ -24,13 +24,11 @@ #define ADS1115_ADDRESS 0x48 #endif -#ifndef ADS1X15_READ_TIMEOUT_MS -#define ADS1X15_READ_TIMEOUT_MS 200 //Longest acquisition time is 125ms (8SPS) -#endif #define ADS1X15_OK 0 #define ADS1X15_INVALID_VOLTAGE -100 #define ADS1X15_ERROR_TIMEOUT -101 +#define ADS1X15_ERROR_I2C -102 #define ADS1X15_INVALID_GAIN 0xFF #define ADS1X15_INVALID_MODE 0xFE @@ -198,7 +196,7 @@ class ADS1X15 void _requestADC(uint16_t readmode); bool _writeRegister(uint8_t address, uint8_t reg, uint16_t value); uint16_t _readRegister(uint8_t address, uint8_t reg); - int8_t _err = ADS1X15_OK; + int8_t _error = ADS1X15_OK; TwoWire* _wire; uint32_t _clockSpeed = 0; @@ -272,3 +270,4 @@ class ADS1115 : public ADS1X15 // -- END OF FILE -- + diff --git a/CHANGELOG.md b/CHANGELOG.md index b983992..98afd75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.4.5] - 2024-07-03 +- Fix #78, prevent infinite loop. (Thanks to devmirek). +- Fix #76 (again), update readme.md Comparator Polarity. +- add ADS1X15_ERROR_I2C, communication error. +- add minimal section in readme.md about error codes. +- minor edits. + ## [0.4.4] - 2024-06-28 - Fix #76, update readme.md Comparator Polarity - added defines to replace magic numbers (not used in code yet) diff --git a/README.md b/README.md index af9272f..9f4f020 100644 --- a/README.md +++ b/README.md @@ -474,26 +474,33 @@ Flag is only explicitly set after a **readADC()** or a **requestADC()** - **uint8_t getComparatorPolarity()** returns value set. -From tests (#76) it became clear that the behaviour of the **ALERT/RDY** pin is a bit ambiguous. -The meaning of HIGH LOW is different for **continuous** and **single** mode, see -the table below. Also different is the timing of the pulse at the **ALERT/RDY** pin. -See **ADS_COMP_POL.ino**. +From tests (see #76) it became clear that the behaviour of the **ALERT/RDY** pin +looks ambiguous. Further investigation eventually showed that the behaviour is +logical but one should not think in "pulses", more in levels and edges. -Timing of pulse from a synchronous ```ADS.readADC(0)``` call. +In the continuous mode it looks like an 8us pulse, however this "pulse" is +actual a short time (8 us) of IDLE followed by a long time pulse of converting. + +In the single shot mode it looks like the converting time is the pulse +as that is the only single change visible. This is IMHO the correct view. + + +#### ALERT RDY table + +| MODE | COMP_POL | IDLE | START | CONVERT | READY | +|:---------------|:-----------|:-------|:----------|:----------|:----------| +| 0 = continuous | 0 = LOW | HIGH | FALLING | LOW | RISING | +| 0 = continuous | 1 = HIGH | LOW | RISING | HIGH | FALLING | +| 1 = single | 0 = LOW | HIGH | FALLING | LOW | RISING | +| 1 = single | 1 = HIGH | LOW | RISING | HIGH | FALLING | -| TEST | MODE | COMP_POL | ALERT/RDY PIN | Notes | -|:----:|:-----------------|:-----------|:------------------------------|:--------| -| 1 | 0 = continuous | 0 = LOW | LOW with 8 us HIGH pulse | as specified in datasheet -| 2 | 0 = continuous | 1 = HIGH | HIGH with 8 us LOW pulse | as specified in datasheet -| 3 | 1 = single | 0 = LOW | HIGH with an 8 ms LOW pulse | depends on data rate -| 4 | 1 = single | 1 = HIGH | LOW with an 8 ms HIGH pulse | depends on data rate See issue #76 for some screenshots. -#### Effect Data Rate +#### Converting time by Data Rate -| data rate | pulse length | Notes | +| data rate | convert time | Notes | |:-----------:|:--------------:|:-------:| | 0 | 125 ms | | 1 | 62 ms | @@ -509,14 +516,25 @@ Times are estimates from scope. #### Conclusions -- Conversion always generates a pulse. -- The length of the pulse in continuous mode and in single mode differs. - - In single shot mode the length of the pulse indicates the conversion time. - - In continuous mode the pulse indicates the end of conversion. -- The polarity in single mode seems to have an inverted pulse, however it is - not about the pulse, it is about the edge. -- If COMP_POL = 0, a FALLING edge indicates conversion ready. -- If COMP_POL = 1, a RISING edge indicates conversion ready. +- Conversion generates a conversion pulse with length depending on the data rate. +- In continuous mode it looks like there is a short pulse, but actual the long + period is the conversion pulse. + +In short: + +- if COMP_POL = 0, + - a FALLING edge indicates conversion start. + - a LOW level indicates converting. + - a RISING edge indicates conversion ready. + - a HIGH level indicates idle. + +- if COMP_POL = 1, + - a RISING edge indicates conversion start. + - a HIGH level indicates converting. + - a FALLING edge indicates conversion ready. + - a LOW level indicates idle. + +This interpretation is in line with all tests done in #76. ### Latch @@ -568,6 +586,23 @@ mean something different see - Comparator Mode above or datasheet. - **int16_t getComparatorThresholdHigh()** reads value from device. +## Error codes + +This section has to be elaborated. + +Some functions return or set an error value. +This is read and reset by **getError()** + +| Value | Define | Description | +|:-------:|:-------------------------:|:-------------:| +| 0 | ADS1X15_OK | idem. +| -100 | ADS1X15_INVALID_VOLTAGE | getMaxVoltage() +| -101 | ADS1X15_ERROR_TIMEOUT | readADC() device did not respond in time. +| -102 | ADS1X15_ERROR_I2C | I2C communication failure. +| 0xFF | ADS1X15_INVALID_GAIN | getGain() +| 0xFE | ADS1X15_INVALID_MODE | getMode() + + ## Future ideas & improvements #### Must @@ -580,10 +615,11 @@ mean something different see - Comparator Mode above or datasheet. - Remove the experimental **getWireClock()** as this is not really a library function but a responsibility of the I2C library. - Investigate ADS1118 library which should be a similar SPI based ADC. +- improve error handling + - refactor values to be more logic. #### Could -- More examples - SMB alert command (00011001) on I2C bus? - Sync code order .h / .cpp diff --git a/library.json b/library.json index 0c7bbe2..01406b8 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/ADS1X15" }, - "version": "0.4.4", + "version": "0.4.5", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/library.properties b/library.properties index 36328cd..a0290d0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ADS1X15 -version=0.4.4 +version=0.4.5 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for ADS1015 - I2C 12 bit ADC and ADS1115 I2C 16 bit ADC