0.1.1 MCP3424

This commit is contained in:
Rob Tillaart 2024-09-19 16:38:26 +02:00
parent 188019a4fb
commit 3336a0dced
9 changed files with 264 additions and 82 deletions

View File

@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.1] - 2024-09-18
- add derived classes for MCP3421/2/3/6/7/8
- extend unit tests.
- fixed **getMode()** to return 1 (continuous) or 0 (single shot).
- fixed math of **floats readVolts()** et al.
- update readme.md
- minor edits
## [0.1.0] - 2024-09-15 ## [0.1.0] - 2024-09-15
- initial version - initial version

View File

@ -1,7 +1,7 @@
// //
// FILE: MCP3424.cpp // FILE: MCP3424.cpp
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// VERSION: 0.1.0 // VERSION: 0.1.1
// PURPOSE: Arduino library for 18 bit ADC I2C MCP3424 and compatibles. // PURPOSE: Arduino library for 18 bit ADC I2C MCP3424 and compatibles.
// URL: https://github.com/RobTillaart/MCP3424 // URL: https://github.com/RobTillaart/MCP3424
@ -23,8 +23,7 @@ MCP3424::MCP3424(uint8_t address, TwoWire *wire)
_gain = 1; _gain = 1;
_bits = 12; _bits = 12;
_mode = 0; // CONTINUOUS _config = 0x10; // default
_config = 0x10;
} }
@ -60,47 +59,52 @@ int32_t MCP3424::read()
} }
// shift is to calculate the LSB factor.
// 18 bits => 1, LSB == 15.625 uV
// 16 bits => 4, LSB == 62.5 uV
// 14 bits => 16, LSB == 250 uV
// 12 bits => 64 LSB == 1000 uV = 1 mV
// must be multiplied to float first to prevent
// losing bits due to integer division
float MCP3424::readVolts() float MCP3424::readVolts()
{ {
// TODO return read() * (15.625e-6 * (1L << (18 - _bits))) / _gain;
// pre calculate float _factor = 15.625e-6 * pow(2, (_bits - 12))/ _gain;
return read() * 15.625e-6 * pow(2, (_bits - 12))/ _gain;
} }
float MCP3424::readMilliVolts() float MCP3424::readMilliVolts()
{ {
return read() * 15.625e-3 * pow(2, (_bits - 12))/ _gain; return read() * (15.625e-3 * (1L << (18 - _bits))) / _gain;
} }
float MCP3424::readMicroVolts() float MCP3424::readMicroVolts()
{ {
return read() * 15.625e0 * pow(2, (_bits - 12))/ _gain; return read() * (15.625e0 * (1L << (18 - _bits))) / _gain;
} }
// TODO move to derived class with more than one channel?
bool MCP3424::setChannel(uint8_t channel) bool MCP3424::setChannel(uint8_t channel)
{ {
if (channel >= _maxChannels) if (channel >= _maxChannels)
{ {
return false; return false;
} }
// only update if changed
if (_channel != channel) if (_channel != channel)
{ {
_channel = channel; _channel = channel;
_config &= 0x1F; // channel = 0 _config &= 0x1F; // channel = 0
// if (channel > 0) => _config |= (channel << 4)
if (channel == 1) _config |= 0x20; if (channel == 1) _config |= 0x20;
if (channel == 2) _config |= 0x40; else if (channel == 2) _config |= 0x40;
if (channel == 3) _config |= 0x60; else if (channel == 3) _config |= 0x60;
} }
writeConfig(); writeConfig();
return true; return true;
} }
// TODO move to derived class with more than one channel?
uint8_t MCP3424::getChannel() uint8_t MCP3424::getChannel()
{ {
return _channel; return _channel;
@ -113,13 +117,14 @@ bool MCP3424::setGain(uint8_t gain)
{ {
return false; return false;
} }
// only update if changed.
if (_gain != gain) if (_gain != gain)
{ {
_gain = gain; _gain = gain;
_config &= 0xFC; // gain == 1 _config &= 0xFC; // gain == 1
if (_gain == 2) _config |= 0x01; if (_gain == 2) _config |= 0x01;
if (_gain == 4) _config |= 0x02; else if (_gain == 4) _config |= 0x02;
if (_gain == 8) _config |= 0x03; else if (_gain == 8) _config |= 0x03;
writeConfig(); writeConfig();
} }
return true; return true;
@ -138,13 +143,14 @@ bool MCP3424::setResolution(uint8_t bits)
{ {
return false; return false;
} }
// only update if changed.
if (_bits != bits) if (_bits != bits)
{ {
_bits = bits; _bits = bits;
_config &= 0xF3; // bits == 12 _config &= 0xF3; // bits == 12
if (_bits == 14) _config |= 0x04; if (_bits == 14) _config |= 0x04;
if (_bits == 16) _config |= 0x08; else if (_bits == 16) _config |= 0x08;
if (_bits == 18) _config |= 0x0C; else if (_bits == 18) _config |= 0x0C;
writeConfig(); writeConfig();
} }
return true; return true;
@ -153,27 +159,34 @@ bool MCP3424::setResolution(uint8_t bits)
uint8_t MCP3424::getResolution() uint8_t MCP3424::getResolution()
{ {
// return 12 + 2 * ((_config >> 2) & 0x03);
return _bits; return _bits;
} }
void MCP3424::setContinuousMode() void MCP3424::setContinuousMode()
{ {
_config &= ~0x10; if (getMode() != 1)
{
_config |= 0x10;
writeConfig(); writeConfig();
}
} }
void MCP3424::setSingleShotMode() void MCP3424::setSingleShotMode()
{ {
_config |= 0x10; if (getMode() != 0)
{
_config &= ~0x10;
writeConfig(); writeConfig();
}
} }
uint8_t MCP3424::getMode() uint8_t MCP3424::getMode()
{ {
return (_config & 0x10); return (_config & 0x10) ? 1 : 0;
} }
@ -226,5 +239,42 @@ int32_t MCP3424::readRaw()
} }
/////////////////////////////////////////////////////////////////////////////
//
// DERIVED CLASSES
//
MCP3421::MCP3421(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 1;
}
MCP3422::MCP3422(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 2;
}
MCP3423::MCP3423(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 2;
}
MCP3426::MCP3426(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 2;
}
MCP3427::MCP3427(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 2;
}
MCP3428::MCP3428(uint8_t address, TwoWire *wire) : MCP3424(address, wire)
{
_maxChannels = 4;
}
// -- END OF FILE -- // -- END OF FILE --

View File

@ -2,7 +2,7 @@
// //
// FILE: MCP3424.h // FILE: MCP3424.h
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// VERSION: 0.1.0 // VERSION: 0.1.1
// PURPOSE: Arduino library for 18 bit ADC I2C MCP3424 and compatibles. // PURPOSE: Arduino library for 18 bit ADC I2C MCP3424 and compatibles.
// URL: https://github.com/RobTillaart/MCP3424 // URL: https://github.com/RobTillaart/MCP3424
@ -10,15 +10,9 @@
#include "Arduino.h" #include "Arduino.h"
#include "Wire.h" #include "Wire.h"
#define MCP3424_LIB_VERSION (F("0.1.0")) #define MCP3424_LIB_VERSION (F("0.1.1"))
// TODO
// - ERROR HANDLING
// - READ STATUS
// - CACHE LAST READ
//
class MCP3424 class MCP3424
{ {
public: public:
@ -50,12 +44,11 @@ public:
uint8_t getMode(); uint8_t getMode();
private: protected:
uint8_t _maxChannels; uint8_t _maxChannels;
uint8_t _channel; uint8_t _channel;
uint8_t _gain; uint8_t _gain;
uint8_t _bits; uint8_t _bits;
uint8_t _mode;
uint8_t _config; uint8_t _config;
uint8_t _address; uint8_t _address;
@ -66,5 +59,49 @@ private:
}; };
/////////////////////////////////////////////////////////////////////////////
//
// DERIVED CLASSES
//
class MCP3421 : public MCP3424
{
public:
MCP3421(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
class MCP3422 : public MCP3424
{
public:
MCP3422(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
class MCP3423 : public MCP3424
{
public:
MCP3423(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
//
// max 16 bit
//
class MCP3426 : public MCP3424
{
public:
MCP3426(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
class MCP3427 : public MCP3424
{
public:
MCP3427(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
class MCP3428 : public MCP3424
{
public:
MCP3428(uint8_t address = 0x68, TwoWire *wire = &Wire);
};
// -- END OF FILE -- // -- END OF FILE --

View File

@ -25,10 +25,13 @@ This library is to be used to configure and read the 18 bit MCP4324 4 channel AD
The MCP3424 is not a fast ADC, however with 18 bit it has at least a very high The MCP3424 is not a fast ADC, however with 18 bit it has at least a very high
resolution. What the effects of the long sampling time means is to be investigated. resolution. What the effects of the long sampling time means is to be investigated.
The high resolution combined with an optional gain of 8x means one could The high resolution combined with an optional gain of 8x means one could
measure voltage in steps of about 2 µV measure voltage in steps of about 2 µV.
The library has three functions that return a reading in volts, millivolts or The library cannot check yet if a conversion is ready.
microvolts to match the need of the user. Need hardware to check how this works in detail.
The library has three functions that return a reading in Volts, milliVolts or
microVolts to match the need of the user.
The user has to configure the ADC device (bits, gain) and can call The user has to configure the ADC device (bits, gain) and can call
**read()** (et al) without parameters to keep usage straightforward. **read()** (et al) without parameters to keep usage straightforward.
@ -37,7 +40,7 @@ Current implementation will probably change slightly in the future
when related devices will be supported. (See future section). when related devices will be supported. (See future section).
Alt-230 = µ Alt-230 = µ
### Resolution ### Resolution
@ -45,23 +48,33 @@ Alt-230 =
| Bits | LSB (gain=1) | SPS | Raw range | Notes | | Bits | LSB (gain=1) | SPS | Raw range | Notes |
|:------:|---------------:|:------:|:-------------------:|:-------:| |:------:|---------------:|:------:|:-------------------:|:-------:|
| 12 | 1 mV | 240 | -2048 .. 2047 | | 12 | 1 mV | 240 | -2048 .. 2047 |
| 14 | 250 µV | 60 | -8192 .. 8191 | | 14 | 250 µV | 60 | -8192 .. 8191 |
| 16 | 62.5 µV | 15 | -32768 .. 32767 | | 16 | 62.5 µV | 15 | -32768 .. 32767 |
| 18 | 15.625 µV | 3.75 | -131072 .. 131071 | not for 3426/27/28. | 18 | 15.625 µV | 3.75 | -131072 .. 131071 | not for 3426/27/28.
The effective resolution also depends on the gain set. The effective resolution also depends on the gain set.
In theory with a gain of 8 the LSB of the 18 bit resolution represents In theory with a gain of 8 the LSB of the 18 bit resolution represents
1/8 of 15.625 µV == 1.95 µV. 1/8 of 15.625 µV == 1.95 µV.
If this is feasible in practice is to be seen. If this is feasible in practice is to be seen.
### I2C Address ### I2C Address
The MCP3421 has a fixed address 0x68, one can order different addresses at factory (how?). The MCP3421 and MCP3426 have a fixed address 0x68, one can order different
addresses at the factory (how?).
TODO Table of addresses? The other devices have two address pins to set 8 addresses. The trick is
to leave address pins floating. See datasheet table 5.3 for details.
Max speed ? 400 KHz.
### I2C Speed
The MCP342x devices support 100 KHz, 400 KHz and 3.4 MHz.
The latter is not (yet) supported by the library.
The sketch **MCP3424_performance.ino** can be used to get some insight
in the performance. It will check up to 800 kHz.
TODO verify with hardware.
### I2C multiplexing ### I2C multiplexing
@ -99,14 +112,14 @@ too if they are behind the multiplexer.
### Constructor ### Constructor
TODO other constructors.
- **MCP3424(uint8_t address = 0x68, TwoWire \*wire = &Wire)** - **MCP3424(uint8_t address = 0x68, TwoWire \*wire = &Wire)**
- **bool begin()** initializes the device. POR? - **bool begin()** initializes the device. POR?
- **bool isConnected()** checks if the device address can be seen on I2C bus. - **bool isConnected()** checks if the device address can be seen on I2C bus.
- **uint8_t getAddress()** idem, convenience function. - **uint8_t getAddress()** idem, convenience function.
- **uint8_t getMaxChannels()** idem, convenience function. - **uint8_t getMaxChannels()** idem, convenience function.
The MCP3421/2/3/6/7/8 constructors have the same parameters.
### Read ### Read
@ -130,51 +143,65 @@ that it will take some time before the conversion with new settings is done.
- **bool setChannel(uint8_t channel = 0)** not to be used for the MCP3421 as - **bool setChannel(uint8_t channel = 0)** not to be used for the MCP3421 as
it has only one channel. Default is channel 0, parameter should be less than the it has only one channel. Default is channel 0, parameter should be less than the
value of **getMaxChannels()**. value of **getMaxChannels()**.
- **uint8_t getChannel()** returns chosen channel, 0 based. e - **uint8_t getChannel()** returns chosen channel (default 0).
- **bool setGain(uint8_t gain = 1)** set gain to 1,2,4, or 8. - **bool setGain(uint8_t gain = 1)** set gain to 1,2,4, or 8.
Other values will return false and not change the setting. Other values will return false and not change the setting.
- **uint8_t getGain()** returns the set gain (default 1). - **uint8_t getGain()** returns the set gain (default 1).
- **bool setResolution(uint8_t bits = 12)** set the bit resolution 12,14,16 or 18. - **bool setResolution(uint8_t bits = 12)** set the bit resolution 12,14,16 or 18.
Other values will return false and not change the setting. Other values will return false and not change the setting.
- **uint8_t getResolution()** returns the set resolution. - **uint8_t getResolution()** returns the set resolution (default 12).
- **void setContinuousMode()** idem. - **void setContinuousMode()** idem.
- **void setSingleShotMode()** idem. - **void setSingleShotMode()** idem.
- **uint8_t getMode()** idem. - **uint8_t getMode()** returns 0 for singleShot and 1 for continuous.
The set function write their changes directly to the device. It might be better The set function write their changes directly to the device. It might be better
to have one function to set all parameters in one call. To be investigated. to have one function to set all parameters in one call. To be investigated.
The library caches the last configuration, it is not read back from the device. The library caches the last configuration, it is not read back from the device.
This might be added in the future.
## Future ## Future
#### Must #### Must
- investigate reading of ready flag
- get hardware to test. - get hardware to test.
- redo interface for MCP3424 if needed. - redo interface for MCP3424 if needed.
- investigate ready flag - investigate continuous vs single shot mode.
- investigate continuous vs single shot.
- improve documentation - improve documentation
- Table of addresses.
#### Should #### Should
- implement support for (separate classes ?)
- 18 bit, MCP3421/MCP3422/MCP3423
- 16 bit: MCP3426/MCP3427/MCP3428 (no 18 bit so not 100% compatible)
- test on different boards. - test on different boards.
- optimize performance (a lot of same math in conversion to voltage) - optimize performance if possible
- check performance I2C with HW
- optimize setting all configuration in one function call. - optimize setting all configuration in one function call.
- PowerOnReset function for configuration - **setConfig(channel, resolution, gain, mode)** ?
- getter needed?
- implement PowerOnReset function for configuration
#### Could #### Could
- implement maxResolution (combine with maxChannels? in one "maxValue" byte)
- check range in **setResolution()**.
- extract gain and resolution from the config byte to reduce storage.
- like **getMode()**.
- extend examples
- array of ADC's
- mcp3424_plotter
- add error handling
- add error variable
- check return value **writeConfig()**.
- check read() process.
#### Wont #### Wont
- cache last read value. (difficult for wrappers)
## Support ## Support

View File

@ -1,7 +1,7 @@
// //
// FILE: MCP3424_test.ino // FILE: MCP3424_performance.ino
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// PURPOSE: basic test API calls. // PURPOSE: basic performance test API calls.
// URL: https://github.com/RobTillaart/MCP3424 // URL: https://github.com/RobTillaart/MCP3424
// //
// needs a device connected to be able to test. // needs a device connected to be able to test.
@ -38,6 +38,8 @@ void setup()
Serial.println(mcp.getGain()); Serial.println(mcp.getGain());
Serial.print("Bits:\t"); Serial.print("Bits:\t");
Serial.println(mcp.getResolution()); Serial.println(mcp.getResolution());
Serial.print("Mode:\t");
Serial.println(mcp.getMode());
Serial.println(); Serial.println();
delay(100); delay(100);

View File

@ -7,11 +7,9 @@
#include "MCP3424.h" #include "MCP3424.h"
MCP3424 mcp; MCP3424 mcp;
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
@ -36,6 +34,8 @@ void setup()
Serial.println(mcp.getGain()); Serial.println(mcp.getGain());
Serial.print("Bits:\t"); Serial.print("Bits:\t");
Serial.println(mcp.getResolution()); Serial.println(mcp.getResolution());
Serial.print("Mode:\t");
Serial.println(mcp.getMode());
Serial.println(); Serial.println();
Serial.println("GAIN 1"); Serial.println("GAIN 1");

View File

@ -1,6 +1,6 @@
{ {
"name": "MCP3424", "name": "MCP3424",
"keywords": "", "keywords": "MCP3421,MCP3422,MCP3423,MCP3426,MCP3427,MCP3428",
"description": "Arduino library for 18 bit ADC I2C MCP3424 et al.", "description": "Arduino library for 18 bit ADC I2C MCP3424 et al.",
"authors": "authors":
[ [
@ -15,7 +15,7 @@
"type": "git", "type": "git",
"url": "https://github.com/RobTillaart/MCP3424.git" "url": "https://github.com/RobTillaart/MCP3424.git"
}, },
"version": "0.1.0", "version": "0.1.1",
"license": "MIT", "license": "MIT",
"frameworks": "*", "frameworks": "*",
"platforms": "*", "platforms": "*",

View File

@ -1,9 +1,9 @@
name=MCP3424 name=MCP3424
version=0.1.0 version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com> author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com> maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for 18 bit ADC I2C MCP3424 et al. sentence=Arduino library for 18 bit ADC I2C MCP3424 et al.
paragraph= paragraph=MCP3421,MCP3422,MCP3423,MCP3426,MCP3427,MCP3428
category=Sensors category=Sensors
url=https://github.com/RobTillaart/MCP3424 url=https://github.com/RobTillaart/MCP3424
architectures=* architectures=*

View File

@ -45,15 +45,55 @@ unittest(test_constants)
} }
unittest(test_constructor) unittest(test_constructors)
{
MCP3421 mcp1;
MCP3422 mcp2;
MCP3423 mcp3;
MCP3424 mcp4;
MCP3426 mcp6;
MCP3427 mcp7;
MCP3428 mcp8;
// base class
assertEqual(0, mcp4.getChannel());
assertEqual(4, mcp4.getMaxChannels());
assertEqual(1, mcp4.getGain());
assertEqual(12, mcp4.getResolution());
assertEqual(1, mcp4.getMode());
// check MAX channels derived classes
assertEqual(1, mcp1.getMaxChannels());
assertEqual(2, mcp2.getMaxChannels());
assertEqual(2, mcp3.getMaxChannels());
assertEqual(4, mcp4.getMaxChannels());
assertEqual(2, mcp6.getMaxChannels());
assertEqual(2, mcp7.getMaxChannels());
assertEqual(4, mcp8.getMaxChannels());
}
unittest(test_channel)
{ {
MCP3424 mcp; MCP3424 mcp;
assertEqual(0, mcp.getChannel()); assertEqual(0, mcp.getChannel());
assertEqual(4, mcp.getMaxChannels());
assertEqual(1, mcp.getGain()); assertTrue(mcp.setChannel(1));
assertEqual(12, mcp.getResolution()); assertEqual(1, mcp.getChannel());
// mode
assertTrue(mcp.setChannel(2));
assertEqual(2, mcp.getChannel());
assertTrue(mcp.setChannel(3));
assertEqual(3, mcp.getChannel());
// default
assertTrue(mcp.setChannel());
assertEqual(0, mcp.getChannel());
// out of range
assertFalse(mcp.setChannel(5));
} }
@ -72,9 +112,11 @@ unittest(test_gain)
assertTrue(mcp.setGain(8)); assertTrue(mcp.setGain(8));
assertEqual(8, mcp.getGain()); assertEqual(8, mcp.getGain());
// default
assertTrue(mcp.setGain()); assertTrue(mcp.setGain());
assertEqual(1, mcp.getGain()); assertEqual(1, mcp.getGain());
// out of range
assertFalse(mcp.setGain(0)); assertFalse(mcp.setGain(0));
} }
@ -94,13 +136,29 @@ unittest(test_resolution)
assertTrue(mcp.setResolution(18)); assertTrue(mcp.setResolution(18));
assertEqual(18, mcp.getResolution()); assertEqual(18, mcp.getResolution());
// default
assertTrue(mcp.setResolution()); assertTrue(mcp.setResolution());
assertEqual(12, mcp.getResolution()); assertEqual(12, mcp.getResolution());
// out of range
assertFalse(mcp.setResolution(13)); assertFalse(mcp.setResolution(13));
} }
unittest(test_mode)
{
MCP3424 mcp;
assertEqual(1, mcp.getMode());
mcp.setSingleShotMode();
assertEqual(0, mcp.getMode());
mcp.setContinuousMode();
assertEqual(1, mcp.getMode());
}
unittest_main() unittest_main()