diff --git a/libraries/MCP_ADC/CHANGELOG.md b/libraries/MCP_ADC/CHANGELOG.md index a82c2efb..295db52e 100644 --- a/libraries/MCP_ADC/CHANGELOG.md +++ b/libraries/MCP_ADC/CHANGELOG.md @@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.2.0] - 2023-08-15 +- add analogReadMultiple(channels\[], numChannels, readings\[]) + - Kudo's to Alex Uta. +- add performance example + - add performance output files. +- add support MCP3201 (experimental) +- fix differentialRead() +- update examples (print lib version). +- update readme.md +- update library.properties +- minor edits + +---- + ## [0.1.9] - 2022-11-16 - add RP2040 in build-CI - add changelog.md diff --git a/libraries/MCP_ADC/MCP_ADC.cpp b/libraries/MCP_ADC/MCP_ADC.cpp index 40069d47..506dc0d6 100644 --- a/libraries/MCP_ADC/MCP_ADC.cpp +++ b/libraries/MCP_ADC/MCP_ADC.cpp @@ -91,6 +91,12 @@ int16_t MCP_ADC::analogRead(uint8_t channel) } +void MCP_ADC::analogReadMultiple(uint8_t channels[], uint8_t numChannels, int16_t readings[]) +{ + readADCMultiple(channels, numChannels, readings); +} + + int16_t MCP_ADC::differentialRead(uint8_t channel) { if (channel >= _channels) return 0; @@ -138,7 +144,7 @@ int16_t MCP_ADC::readADC(uint8_t channel, bool single) } mySPI->endTransaction(); } - else // Software SPI + else // Software SPI { for (uint8_t b = 0; b < bytes; b++) { @@ -153,6 +159,46 @@ int16_t MCP_ADC::readADC(uint8_t channel, bool single) } +void MCP_ADC::readADCMultiple(uint8_t channels[], uint8_t numChannels, int16_t readings[]) +{ + _count += numChannels; + + if (_hwSPI) { + mySPI->beginTransaction(_spi_settings); + } + + for (uint8_t i = 0; i < numChannels; i++) { + + digitalWrite(_select, LOW); + + uint8_t data[3] = {0, 0, 0}; + uint8_t bytes = buildRequest(channels[i], true, data); + + if (_hwSPI) { + for (uint8_t b = 0; b < bytes; b++) { + data[b] = mySPI->transfer(data[b]); + } + } else { + for (uint8_t b = 0; b < bytes; b++) { + data[b] = swSPI_transfer(data[b]); + } + } + + if (bytes == 2) { + readings[i] = ((256 * data[0] + data[1]) & _maxValue); + } else { + readings[i] = ((256 * data[1] + data[2]) & _maxValue); + } + + digitalWrite(_select, HIGH); + } + + if (_hwSPI) { + mySPI->endTransaction(); + } +} + + // MSBFIRST uint8_t MCP_ADC::swSPI_transfer(uint8_t val) { @@ -236,6 +282,27 @@ uint8_t MCP3008::buildRequest(uint8_t channel, bool single, uint8_t * data) } +///////////////////////////////////////////////////////////////////////////// +// +// MCP3201 +// +MCP3201::MCP3201(uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP_ADC(dataIn, dataOut, clock) +{ + _channels = 1; + _maxValue = 4095; +} + +uint8_t MCP3201::buildRequest(uint8_t channel, bool single, uint8_t * data) +{ + // P21 fig 6.1 MCP3201 + // no specific data needed + // keep build CI compiler (ESP32) happy next statement + if ((channel == 0) || (single == false)) return 2; + return 2; +} + + ///////////////////////////////////////////////////////////////////////////// // // MCP3202 diff --git a/libraries/MCP_ADC/MCP_ADC.h b/libraries/MCP_ADC/MCP_ADC.h index 49596c1b..17cb385c 100644 --- a/libraries/MCP_ADC/MCP_ADC.h +++ b/libraries/MCP_ADC/MCP_ADC.h @@ -2,7 +2,7 @@ // // FILE: MCP_ADC.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.9 +// VERSION: 0.2.0 // DATE: 2019-10-24 // PURPOSE: Arduino library for MCP_ADC // URL: https://github.com/RobTillaart/MCP_ADC @@ -13,7 +13,7 @@ #include "SPI.h" -#define MCP_ADC_LIB_VERSION (F("0.1.9")) +#define MCP_ADC_LIB_VERSION (F("0.2.0")) class MCP_ADC @@ -24,7 +24,9 @@ public: uint8_t channels() { return _channels; }; int16_t maxValue() { return _maxValue; }; + int16_t analogRead(uint8_t channel); + void analogReadMultiple(uint8_t channels[], uint8_t numChannels, int16_t readings[]); int16_t differentialRead(uint8_t channel); int16_t deltaRead(uint8_t channel); @@ -34,6 +36,7 @@ public: // debugging bool usesHWSPI() { return _hwSPI; }; + uint32_t count(); // number of channels read. // ESP32 specific #if defined(ESP32) @@ -46,8 +49,6 @@ public: void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select); #endif - uint32_t count(); - protected: uint8_t _dataIn; @@ -57,12 +58,15 @@ protected: bool _hwSPI; uint8_t _channels; int16_t _maxValue; - uint32_t _SPIspeed = 1000000; // 1 MHz is a safe value (datasheet); in a test 4 MHz worked. + // 1 MHz is a safe value (datasheet); in a test 4 MHz worked. + uint32_t _SPIspeed = 1000000; // derived classes must implement buildRequest() function. virtual uint8_t buildRequest(uint8_t channel, bool single, uint8_t * data) = 0; int16_t readADC(uint8_t channel, bool single); + void readADCMultiple(uint8_t channels[], uint8_t numChannels, int16_t readings[]); + uint8_t swSPI_transfer(uint8_t d); SPIClass * mySPI; @@ -104,6 +108,14 @@ public: }; +class MCP3201 : public MCP_ADC +{ +public: + MCP3201(uint8_t dataIn = 255, uint8_t dataOut = 255, uint8_t clock = 255); + uint8_t buildRequest(uint8_t channel, bool single, uint8_t * data); +}; + + class MCP3202 : public MCP_ADC { public: diff --git a/libraries/MCP_ADC/README.md b/libraries/MCP_ADC/README.md index cac86803..14408da6 100644 --- a/libraries/MCP_ADC/README.md +++ b/libraries/MCP_ADC/README.md @@ -8,7 +8,7 @@ # MCP_ADC -Arduino library for MCP3002 MCP3004 MCP3008 MCP3202 MCP3204 MCP3208 and compatibles. +Arduino library for MCP3002 MCP3004 MCP3008 MCP3201 MCP3202 MCP3204 MCP3208 and compatibles. ## Description @@ -17,14 +17,15 @@ This library reads the ADC ports of the MCP ADC convertors. The chips are communicates with SPI and support both hardware SPI or optional software SPI. -| type | bits | channels | notes | -|:--------|:----:|:--------:|:------| -| MCP3002 | 10 | 2 | | -| MCP3004 | 10 | 4 | | -| MCP3008 | 10 | 8 | | -| MCP3202 | 12 | 2 | | -| MCP3204 | 12 | 4 | | -| MCP3208 | 12 | 8 | | +| type | bits | chan | notes | +|:----------|:------:|:------:|:--------| +| MCP3002 | 10 | 2 | +| MCP3004 | 10 | 4 | +| MCP3008 | 10 | 8 | +| MCP3201 | 12 | 1 | not tested yet. +| MCP3202 | 12 | 2 | +| MCP3204 | 12 | 4 | +| MCP3208 | 12 | 8 | Current version allows manual override of the hardware SPI clock as the speed is not @@ -40,12 +41,19 @@ This delta mode can return negative values too. ## Interface +```cpp +#include "MCP_ADC.h" +``` + +#### Base + If the pins are not set in the constructor, the class will automatically -use the hardware SPI, otherwise it will use a software SPI. +use the hardware SPI, otherwise it will use software SPI. - **MCP3002(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 10 bit ADC 2 channel. - **MCP3004(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 10 bit ADC 4 channel. - **MCP3008(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 10 bit ADC 8 channel. +- **MCP3201(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 12 bit ADC 1 channel. - **MCP3202(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 12 bit ADC 2 channel. - **MCP3204(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 12 bit ADC 4 channel. - **MCP3208(uint8_t dataIn, uint8_t dataOut, uint8_t clock)** constructor 12 bit ADC 8 channel. @@ -54,6 +62,8 @@ use the hardware SPI, otherwise it will use a software SPI. - **int16_t maxValue()** returns maxReading of adc, e.g. 1023. This makes it easy to calculate relative measurements. - **int16_t analogRead(uint8_t channel)** reads the value of a single channel. +- **void analogReadMultiple(uint8_t channels[], uint8_t numChannels, int16_t readings[])** +reads multiple channels in one call. See section below. - **int16_t differentialRead(uint8_t channel)** reads differential between two channels. Check datasheet for details. Note if the **IN+** is equal or below **IN-** this function will return 0. @@ -64,7 +74,7 @@ of the ADC first to get optimal speed. - **uint32_t getSPIspeed()** gets current speed in **Hz**. -Differential channel table: +### Differential channel table: | Channel | diff IN+ | diff IN- | MCP | |:-------:|:--------:|:--------:|---------------:| @@ -78,9 +88,10 @@ Differential channel table: | 7 | 7 | 6 | 3x08 | -### debug +### Debug - **bool usesHWSPI()** returns true if HW SPI is used. +- **uint32_t count()** returns number of channels read since start. ### ESP32 specific @@ -94,7 +105,7 @@ The **selectVSPI()** or the **selectHSPI()** needs to be called BEFORE the **begin()** function. -#### experimental +#### setGPIOpins() experimental - **void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)** overrule GPIO pins of ESP32 for hardware SPI. needs to be called AFTER the **begin()** function. @@ -121,42 +132,73 @@ This is the value recommended in the datasheet for 2.7V. In a test with an ESP32 (3.3V) the library showed stable results at 4 MHz and at 6 MHz it was almost good. - -The max value read at 6 MHz was 1020 instead of 1023 (MCP3008) -which indicates that the last 2 bits got lost due to signal deformation. -| Board | Voltage | safe | max | -|:-----:|:-------:|:------:|:-----:| -| ESP32 | 2.7V | 1 MHz | 4 MHz | -| UNO | 5.0V | 2 MHz | 4 MHz | +The maximum value read at 6 MHz was 1020 instead of 1023 (MCP3008) +which indicates that the last 2 bits got lost probably due to signal +deformation. + +| Board | Voltage | safe | max | +|:-------:|:---------:|:-------:|:-------:| +| ESP32 | 2.7V | 1 MHz | 4 MHz | +| UNO | 5.0V | 2 MHz | 4 MHz | For hardware SPI the ESP32 uses the VSPI pins. (see ESP examples). -## Operations +## analogReadMultiple() -See examples. +Since version 0.2.0 the **analogReadMultiple(channels[], numChannels, readings[])** +is added to the interface. +(See https://github.com/RobTillaart/MCP_ADC/pull/11 - Thanks to Alex Uta). + +This function allows to read multiple channels in one call, which improves +the performance of fetching new readings from the MCP_ADC device. +The amount of gain differs per platform, so run your own performance test. + +Besides fetching all ADC's in one call this function also allows to fetch +the data from a specific channel multiple times, e.g. to be averaged. +Other patterns are possible. +These scenarios need still to be tested in practice. + +Finally **analogReadMultiple()** can be used to read only one channel too +by using numChannels = 1. + + +## MCP3201 experimental + +Since 0.2.0 code for the MCP3201 has been added however this 12 bit single +channel device has not been tested yet. + +As the SPI transfer looked quite a bit like the MCP3202 it is expected to work +but the proof is in the hardware test. + +Note that not all function calls make sense for the MCP3201 as this device only +has one channel. So use the library carefully. + +Feedback is as always welcome. ## Future -#### must -- documentation -- testing, a lot ... +#### Must + +- improve documentation +- test analogReadMultiple() scenario's +- MCP3201 buy hardware and test + +#### Should + +- improve SWSPI for AVR + (code is under test for MCP23S17) -#### should +#### Could -#### could -- analogRead (mask, int array\[8\] ) read ports (set in mask) in an array in one call. - would this save time? - - -#### wont +#### Wont - get / setF(float A, float B) => float readF(channel) output = A\*value + B; it actually does float mapping. As it implies the same mapping for all it might - not be that useful => multimap + not be that useful => check multiMap library. diff --git a/libraries/MCP_ADC/examples/MCP3002_analogRead/MCP3002_analogRead.ino b/libraries/MCP_ADC/examples/MCP3002_analogRead/MCP3002_analogRead.ino index cc6a45a9..f7deaf56 100644 --- a/libraries/MCP_ADC/examples/MCP3002_analogRead/MCP3002_analogRead.ino +++ b/libraries/MCP_ADC/examples/MCP3002_analogRead/MCP3002_analogRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3002 mcp1; // use HWSPI -MCP3002 mcp2(6, 7); // use SWSPI +MCP3002 mcp1; // use HWSPI +MCP3002 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -29,6 +31,7 @@ void setup() Serial.print(mcp2.channels()); Serial.print("\t"); Serial.println(mcp2.maxValue()); + Serial.println(); } @@ -55,5 +58,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3002_deltaRead/MCP3002_deltaRead.ino b/libraries/MCP_ADC/examples/MCP3002_deltaRead/MCP3002_deltaRead.ino index 9b66cda9..4faed283 100644 --- a/libraries/MCP_ADC/examples/MCP3002_deltaRead/MCP3002_deltaRead.ino +++ b/libraries/MCP_ADC/examples/MCP3002_deltaRead/MCP3002_deltaRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3002 mcp1; // use HWSPI -MCP3002 mcp2(6, 7); // use SWSPI +MCP3002 mcp1; // use HWSPI +MCP3002 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -55,5 +57,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3002_differentialRead/MCP3002_differentialRead.ino b/libraries/MCP_ADC/examples/MCP3002_differentialRead/MCP3002_differentialRead.ino index 58381e00..91262e66 100644 --- a/libraries/MCP_ADC/examples/MCP3002_differentialRead/MCP3002_differentialRead.ino +++ b/libraries/MCP_ADC/examples/MCP3002_differentialRead/MCP3002_differentialRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3002 mcp1; // use HWSPI -MCP3002 mcp2(6, 7); // use SWSPI +MCP3002 mcp1; // use HWSPI +MCP3002 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -55,5 +57,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3008_analogRead/MCP3008_analogRead.ino b/libraries/MCP_ADC/examples/MCP3008_analogRead/MCP3008_analogRead.ino index 323fdb24..264dad5c 100644 --- a/libraries/MCP_ADC/examples/MCP3008_analogRead/MCP3008_analogRead.ino +++ b/libraries/MCP_ADC/examples/MCP3008_analogRead/MCP3008_analogRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3008 mcp1; // use HWSPI -MCP3004 mcp2(6, 7); // use SWSPI +MCP3008 mcp1; // use HWSPI +MCP3004 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -55,5 +57,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_HWSPI/MCP3008_analogRead_ESP32_HWSPI.ino b/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_HWSPI/MCP3008_analogRead_ESP32_HWSPI.ino index 7251a02d..c491fe65 100644 --- a/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_HWSPI/MCP3008_analogRead_ESP32_HWSPI.ino +++ b/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_HWSPI/MCP3008_analogRead_ESP32_HWSPI.ino @@ -20,17 +20,19 @@ // MISO: 19, -MCP3008 mcp1; // use HWSPI on ESP32 (apparently VSPI) -// MCP3008 mcp1(23, 19, 21); // ESP32 use SWSPI dataIn, dataOut, Clock -// MCP3008 mcp1(6, 7, 8); // UNO use SWSPI dataIn, dataOut, Clock +MCP3008 mcp1; // use HWSPI on ESP32 (apparently VSPI) +// MCP3008 mcp1(23, 19, 21); // ESP32 use SWSPI dataIn, dataOut, Clock +// MCP3008 mcp1(6, 7, 8); // UNO use SWSPI dataIn, dataOut, Clock void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); - mcp1.begin(5); // chip select pin. + mcp1.begin(5); // chip select pin. Serial.println(); Serial.println("ADC\tCHAN\tMAXVALUE"); @@ -39,7 +41,7 @@ void setup() Serial.print("\t"); Serial.println(mcp1.maxValue()); - mcp1.setSPIspeed(4000000); // seems to be the max speed. use 1MHz (default) to be safe + mcp1.setSPIspeed(4000000); // seems to be the max speed. use 1MHz (default) to be safe } @@ -52,7 +54,7 @@ void loop() uint16_t val = mcp1.analogRead(channel); Serial.print(val); Serial.print("\t"); - delay(1); // added so single reads are better visible on a scope + delay(1); // added so single reads are better visible on a scope } Serial.println(); @@ -60,5 +62,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_SWSPI/MCP3008_analogRead_ESP32_SWSPI.ino b/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_SWSPI/MCP3008_analogRead_ESP32_SWSPI.ino index edd83f36..e675b5c2 100644 --- a/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_SWSPI/MCP3008_analogRead_ESP32_SWSPI.ino +++ b/libraries/MCP_ADC/examples/MCP3008_analogRead_ESP32_SWSPI/MCP3008_analogRead_ESP32_SWSPI.ino @@ -8,27 +8,29 @@ #include "MCP_ADC.h" -// ESP32 PINS -// For HSPI -// CLK: 14 -// MOSI: 13 -// MISO: 12 +// ESP32 PINS +// For HSPI +// CLK: 14 +// MOSI: 13 +// MISO: 12 // -// For VSPI (id = 2): -// CLK: 18, -// MOSI: 23, -// MISO: 19, +// For VSPI (id = 2): +// CLK: 18, +// MOSI: 23, +// MISO: 19, -MCP3008 mcp1(23, 19, 21); // ESP32 use SWSPI dataIn, dataOut, Clock -// MCP3008 mcp1; // use HWSPI on ESP32 (apparently VSPI) -// MCP3008 mcp1(6, 7, 8); // UNO use SWSPI dataIn, dataOut, Clock +MCP3008 mcp1(23, 19, 21); // ESP32 use SWSPI dataIn, dataOut, Clock +// MCP3008 mcp1; // use HWSPI on ESP32 (apparently VSPI) +// MCP3008 mcp1(6, 7, 8); // UNO use SWSPI dataIn, dataOut, Clock void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(5); @@ -50,7 +52,7 @@ void loop() uint16_t val = mcp1.analogRead(channel); Serial.print(val); Serial.print("\t"); - delay(1); // added so single reads are better visible on a scope + delay(1); // added so single reads are better visible on a scope } Serial.println(); @@ -58,5 +60,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3008_deltaRead/MCP3008_deltaRead.ino b/libraries/MCP_ADC/examples/MCP3008_deltaRead/MCP3008_deltaRead.ino index 8e052338..452ca1e0 100644 --- a/libraries/MCP_ADC/examples/MCP3008_deltaRead/MCP3008_deltaRead.ino +++ b/libraries/MCP_ADC/examples/MCP3008_deltaRead/MCP3008_deltaRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3008 mcp1; // use HWSPI -MCP3004 mcp2(6, 7); // use SWSPI +MCP3008 mcp1; // use HWSPI +MCP3004 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -55,5 +57,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3008_differentialRead/MCP3008_differentialRead.ino b/libraries/MCP_ADC/examples/MCP3008_differentialRead/MCP3008_differentialRead.ino index e7d06e66..e3cb649a 100644 --- a/libraries/MCP_ADC/examples/MCP3008_differentialRead/MCP3008_differentialRead.ino +++ b/libraries/MCP_ADC/examples/MCP3008_differentialRead/MCP3008_differentialRead.ino @@ -7,14 +7,16 @@ #include "MCP_ADC.h" -MCP3008 mcp1; // use HWSPI -MCP3004 mcp2(6, 7); // use SWSPI +MCP3008 mcp1; // use HWSPI +MCP3004 mcp2(6, 7); // use SWSPI void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp1.begin(10); mcp2.begin(5); @@ -55,5 +57,5 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3201_analogRead/MCP3201_analogRead.ino b/libraries/MCP_ADC/examples/MCP3201_analogRead/MCP3201_analogRead.ino new file mode 100644 index 00000000..1582f3d4 --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP3201_analogRead/MCP3201_analogRead.ino @@ -0,0 +1,80 @@ +// +// FILE: MCP3201_analogRead.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo +// DATE: 2023-08-15 + + +#include "MCP_ADC.h" + +MCP3201 mcp1; // use HWSPI +MCP3201 mcp2(6, 7); // use SWSPI + +uint32_t start, stop; + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); + + mcp1.begin(10); + mcp2.begin(5); + + Serial.println(); + Serial.println("ADC\tCHAN\tMAXVALUE"); + Serial.print("mcp1\t"); + Serial.print(mcp1.channels()); + Serial.print("\t"); + Serial.println(mcp1.maxValue()); + delay(10); + start = micros(); + uint16_t val = mcp1.analogRead(0); + stop = micros(); + Serial.print("hwspi:\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println(val); + + Serial.print("mcp2\t"); + Serial.print(mcp2.channels()); + Serial.print("\t"); + Serial.println(mcp2.maxValue()); + delay(10); + start = micros(); + val = mcp2.analogRead(0); + stop = micros(); + Serial.print("swspi:\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println(val); + + Serial.println(); +} + + +void loop() +{ + Serial.print("mcp1:\t"); + for (int channel = 0 ; channel < mcp1.channels(); channel++) + { + uint16_t val = mcp1.analogRead(channel); + Serial.print(val); + Serial.print("\t"); + } + Serial.println(); + Serial.print("mcp2:\t"); + for (int channel = 0 ; channel < mcp2.channels(); channel++) + { + uint16_t val = mcp2.analogRead(channel); + Serial.print(val); + Serial.print("\t"); + } + Serial.println(); + + delay(5000); +} + + +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3208_performance/MCP3208_performance.ino b/libraries/MCP_ADC/examples/MCP3208_performance/MCP3208_performance.ino new file mode 100644 index 00000000..a81caf25 --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP3208_performance/MCP3208_performance.ino @@ -0,0 +1,170 @@ +// +// FILE: MCP3208_performance.ino +// AUTHOR: Rob Tillaart, Alex Uta +// PURPOSE: simple performance measurement for MCP3208 +// DATE: 2023-08-13 +// + + +#include "MCP_ADC.h" + +MCP3208 mcp28; +#define MCP3208_CS_PIN 25 + +uint32_t start, stop, + analog_read_time, + analog_read_multiple_time; + +const uint8_t num_channels = 8; +uint8_t channels_list[num_channels] = { + 0,1,2,3,4,5,6,7 +}; + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); + + Serial.println(); + Serial.println("ADC\tCHAN\tMAXVALUE"); + Serial.print("mcp28\t"); + Serial.print(mcp28.channels()); + Serial.print("\t"); + Serial.println(mcp28.maxValue()); + + Serial.println("\nTiming in micros().\n"); + delay(10); + + Serial.println("***************************************\n"); + for (int s = 1; s <= 16; s++) + { + Serial.println(s * 1000000UL); + mcp28.setSPIspeed(s * 1000000UL); + mcp28.begin(MCP3208_CS_PIN); + test(); + } + + testChannelsRead(); + Serial.println("done..."); +} + + +void loop() +{ +} + + +void test() +{ + uint32_t val = 0; + + start = micros(); + for (int channel = 0; channel < mcp28.channels(); channel++) + { + val += mcp28.analogRead(channel); + } + stop = micros(); + analog_read_time = stop - start; + + Serial.print("mcp28.analogRead()\t8x: \t"); + Serial.println(analog_read_time); + delay(10); + + + start = micros(); + int16_t readings[num_channels]; + + mcp28.analogReadMultiple(channels_list, num_channels, readings); + stop = micros(); + analog_read_multiple_time = stop - start; + + Serial.print("mcp28.analogReadMultiple()\t8x: \t"); + Serial.println(stop - start); + + Serial.print("analogRead() time / analogReadMultiple() time \t"); + Serial.println((1.0 * analog_read_time) / analog_read_multiple_time); + delay(10); + + + start = micros(); + for (int channel = 0; channel < mcp28.channels(); channel++) + { + val += mcp28.differentialRead(channel); + } + stop = micros(); + Serial.print("mcp28.differentialRead() 8x: \t"); + Serial.println(stop - start); + delay(10); + + start = micros(); + for (int channel = 0; channel < mcp28.channels(); channel++) + { + val += mcp28.deltaRead(channel); + } + stop = micros(); + Serial.print("mcp28.deltaRead()\t8x: \t"); + Serial.println(stop - start); + Serial.println(); + delay(10); + +} + + +void testChannelsRead() { + Serial.println("***************************************\n"); + + mcp28.setSPIspeed(8000000); // 8 MHz + mcp28.begin(MCP3208_CS_PIN); + Serial.println("8000000"); + + for (uint8_t numChannelsToRead = 1; numChannelsToRead <= num_channels; numChannelsToRead++) { + + delay(10); + + // analogRead() + start = micros(); + for (uint8_t i = 0; i < numChannelsToRead; i++) { + mcp28.analogRead(i); + } + stop = micros(); + analog_read_time = stop - start; + + Serial.print("mcp28.analogRead()\t"); + Serial.print(numChannelsToRead); + Serial.print(": \t"); + Serial.print(analog_read_time); + Serial.println(""); + + // analogReadMultiple() + uint8_t channels_list[numChannelsToRead]; + for (uint8_t i = 0; i < numChannelsToRead; i++) { + channels_list[i] = i; + } + + delay(10); + + int16_t readings[numChannelsToRead]; + start = micros(); + mcp28.analogReadMultiple(channels_list, numChannelsToRead, readings); + stop = micros(); + analog_read_multiple_time = stop - start; + + Serial.print("mcp28.analogReadMultiple()\t"); + Serial.print(numChannelsToRead); + Serial.print(": \t"); + Serial.println(analog_read_multiple_time); + + Serial.print("analogRead() time / analogReadMultiple() time \t"); + Serial.println((1.0 * analog_read_time) / analog_read_multiple_time, 2); // print as float + + Serial.println("\n"); + delay(10); + } + +} + + +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9.md b/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9.md new file mode 100644 index 00000000..5f3fcc54 --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9.md @@ -0,0 +1,25 @@ + + +# Performance test + +Test sketch MCP3208_performance.ino + +Max clock frequency tested 16 MHz, ESP32 WROVER Module + +### Library version: 0.1.9 + +| Action | HW 1 MHz | HW 2 MHz | HW 4 MHz | HW 8 MHz | HW 10 MHz | HW 12 MHz | HW 14 MHz | HW 16 MHz | notes | +|:------------------------------|---------:|---------:|---------:|---------:|:---------:|:---------:|:---------:|:---------:| +| mcp28.analogRead() | 397.0 | 243.0 | 188.0 | 158.00 | 153.0 | 209.0 | 208.0 | 147.0 | +| mcp28.analogReadMultiple() | 271.0 | 154.0 | 99.00 | 70.00 | 64.00 | 61.00 | 59.0 | 55.00 | +| single / multiple ratio | 1.0 | 1.0 | 1.0 | 2.0 | 2.0 | 3.0 | 3.0 | 2.0 | +| | | | | | | | | | +| mcp28.differentialRead() | 359.0 | 241.0 | 186.0 | 157.0 | 151.0 | 148.0 | 146.0 | 142.0 | +| mcp28.deltaRead() | 363.0 | 304.0 | 234.0 | 198.0 | 191.0 | 187.0 | 185.0 | 145.0 | + +### Notes + +For this test I used the ESP32 WROVER Module (ESP32-WROVER-IE-N16R8) with MCP3208-CI/SL (IC ADC 12BIT SAR 16SOIC) + +A good compromise was the 12 MHz. +By running multiple tests I was able to see a difference in the reading value of 13-16 and it was easily fixed from the software side. diff --git a/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9_raw_AVR.txt b/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9_raw_AVR.txt new file mode 100644 index 00000000..29e6c62f --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP3208_performance/performance_0.1.9_raw_AVR.txt @@ -0,0 +1,167 @@ + +IDE: 1.8.19 +Board: UNO + +MCP3208_performance.ino +MCP_ADC_LIB_VERSION: 0.1.9 + +ADC CHAN MAXVALUE +mcp28 8 4095 + +Timing in micros(). + +*************************************** + +1000000 +mcp28.ancnogRead() 8x: 512 +mcp28.analogReadMultiple() 8x: 368 +analogRead() time / analogReadMultiple() time 1.39 +mcp28.differentialRead() 8x: 472 +mcp28.deltaRead() 8x: 932 + +2000000 +mcp28.ancnogRead() 8x: 408 +mcp28.analogReadMultiple() 8x: 272 +analogRead() time / analogReadMultiple() time 1.50 +mcp28.differentialRead() 8x: 372 +mcp28.deltaRead() 8x: 736 + +3000000 +mcp28.ancnogRead() 8x: 388 +mcp28.analogReadMultiple() 8x: 276 +analogRead() time / analogReadMultiple() time 1.41 +mcp28.differentialRead() 8x: 372 +mcp28.deltaRead() 8x: 740 + +4000000 +mcp28.ancnogRead() 8x: 356 +mcp28.analogReadMultiple() 8x: 224 +analogRead() time / analogReadMultiple() time 1.59 +mcp28.differentialRead() 8x: 324 +mcp28.deltaRead() 8x: 648 + +5000000 +mcp28.ancnogRead() 8x: 348 +mcp28.analogReadMultiple() 8x: 224 +analogRead() time / analogReadMultiple() time 1.55 +mcp28.differentialRead() 8x: 320 +mcp28.deltaRead() 8x: 636 + +6000000 +mcp28.ancnogRead() 8x: 344 +mcp28.analogReadMultiple() 8x: 224 +analogRead() time / analogReadMultiple() time 1.54 +mcp28.differentialRead() 8x: 328 +mcp28.deltaRead() 8x: 640 + +7000000 +mcp28.ancnogRead() 8x: 344 +mcp28.analogReadMultiple() 8x: 228 +analogRead() time / analogReadMultiple() time 1.51 +mcp28.differentialRead() 8x: 324 +mcp28.deltaRead() 8x: 648 + +8000000 +mcp28.ancnogRead() 8x: 328 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.64 +mcp28.differentialRead() 8x: 300 +mcp28.deltaRead() 8x: 596 + +9000000 +mcp28.ancnogRead() 8x: 332 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.66 +mcp28.differentialRead() 8x: 300 +mcp28.deltaRead() 8x: 596 + +10000000 +mcp28.ancnogRead() 8x: 332 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.66 +mcp28.differentialRead() 8x: 300 +mcp28.deltaRead() 8x: 596 + +11000000 +mcp28.ancnogRead() 8x: 328 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.64 +mcp28.differentialRead() 8x: 296 +mcp28.deltaRead() 8x: 588 + +12000000 +mcp28.ancnogRead() 8x: 328 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.64 +mcp28.differentialRead() 8x: 304 +mcp28.deltaRead() 8x: 592 + +13000000 +mcp28.ancnogRead() 8x: 324 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.62 +mcp28.differentialRead() 8x: 304 +mcp28.deltaRead() 8x: 592 + +14000000 +mcp28.ancnogRead() 8x: 328 +mcp28.analogReadMultiple() 8x: 208 +analogRead() time / analogReadMultiple() time 1.58 +mcp28.differentialRead() 8x: 300 +mcp28.deltaRead() 8x: 596 + +15000000 +mcp28.ancnogRead() 8x: 328 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.64 +mcp28.differentialRead() 8x: 300 +mcp28.deltaRead() 8x: 596 + +16000000 +mcp28.ancnogRead() 8x: 332 +mcp28.analogReadMultiple() 8x: 200 +analogRead() time / analogReadMultiple() time 1.66 +mcp28.differentialRead() 8x: 296 +mcp28.deltaRead() 8x: 600 + +*************************************** + +8000000 +mcp28.analogRead() 1: 40 +mcp28.analogReadMultiple() 1: 36 +analogRead() time / analogReadMultiple() time 1.11 + + +mcp28.analogRead() 2: 76 +mcp28.analogReadMultiple() 2: 56 +analogRead() time / analogReadMultiple() time 1.36 + + +mcp28.analogRead() 3: 112 +mcp28.analogReadMultiple() 3: 88 +analogRead() time / analogReadMultiple() time 1.27 + + +mcp28.analogRead() 4: 148 +mcp28.analogReadMultiple() 4: 104 +analogRead() time / analogReadMultiple() time 1.42 + + +mcp28.analogRead() 5: 184 +mcp28.analogReadMultiple() 5: 132 +analogRead() time / analogReadMultiple() time 1.39 + + +mcp28.analogRead() 6: 224 +mcp28.analogReadMultiple() 6: 156 +analogRead() time / analogReadMultiple() time 1.44 + + +mcp28.analogRead() 7: 256 +mcp28.analogReadMultiple() 7: 176 +analogRead() time / analogReadMultiple() time 1.45 + + +mcp28.analogRead() 8: 296 +mcp28.analogReadMultiple() 8: 200 +analogRead() time / analogReadMultiple() time 1.48 diff --git a/libraries/MCP_ADC/examples/MCP3208_performance/readADC_vs_readADCMultiple.md b/libraries/MCP_ADC/examples/MCP3208_performance/readADC_vs_readADCMultiple.md new file mode 100644 index 00000000..8749d63b --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP3208_performance/readADC_vs_readADCMultiple.md @@ -0,0 +1,16 @@ + +### Comparing multiple **readADC()** calls with one **readADCMultiple()** call + +- ESP32 +- source https://github.com/RobTillaart/MCP_ADC/pull/11#issuecomment-1676461195 +- figures are indicative and platform dependent. + +| function | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <- channels +|:--------------------:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:| +| analogRead | | 42 | 59 | 78 | 98 | 118 | 137 | 157 | (us) +| analogReadMultiple | | 27 | 34 | 41 | 49 | 55 | 62 | 70 | (us) +| ratio | | 1.56 | 1.73 | 1.90 | 2.00 | 2.15 | 2.21 | 2.24 | + + +TODO AVR UNO + diff --git a/libraries/MCP_ADC/examples/MCP_ADC_performance/MCP_ADC_performance.ino b/libraries/MCP_ADC/examples/MCP_ADC_performance/MCP_ADC_performance.ino index 402c46c1..cdacd3ad 100644 --- a/libraries/MCP_ADC/examples/MCP_ADC_performance/MCP_ADC_performance.ino +++ b/libraries/MCP_ADC/examples/MCP_ADC_performance/MCP_ADC_performance.ino @@ -13,8 +13,8 @@ MCP3002 mcp2; MCP3004 mcp4; -MCP3008 mcp8(11, 12, 13); // software spi -// MCP3008 mcp8; // hardware spi +MCP3008 mcp8(11, 12, 13); // software SPI +// MCP3008 mcp8; // hardware SPI MCP3202 mcp22; MCP3204 mcp24; MCP3208 mcp28; @@ -26,6 +26,8 @@ void setup() { Serial.begin(115200); Serial.println(__FILE__); + Serial.print("MCP_ADC_LIB_VERSION: "); + Serial.println(MCP_ADC_LIB_VERSION); mcp2.begin(8); mcp4.begin(9); @@ -72,7 +74,7 @@ void setup() test_2(); test_3(); - // on UNO there is no difference above 8MHz (half CPU clock) + // on UNO there is no difference above 8MHz (half CPU clock) Serial.println("***************************************\n"); for (int s = 1; s <= 16; s *= 2) { @@ -81,7 +83,7 @@ void setup() test_3(); } - // on UNO there is no difference above 8MHz (half CPU clock) + // on UNO there is no difference above 8MHz (half CPU clock) Serial.println("***************************************\n"); for (int s = 1; s <= 16; s *= 2) { @@ -90,7 +92,7 @@ void setup() test_4(); } - // on UNO there is no difference above 8MHz (half CPU clock) + // on UNO there is no difference above 8MHz (half CPU clock) Serial.println("***************************************\n"); for (int s = 1; s <= 16; s *= 2) { @@ -99,7 +101,7 @@ void setup() test_5(); } - // on UNO there is no difference above 8MHz (half CPU clock) + // on UNO there is no difference above 8MHz (half CPU clock) Serial.println("***************************************\n"); for (int s = 1; s <= 16; s *= 2) { @@ -339,5 +341,5 @@ void test_6() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/MCP_ADC/examples/MCP_ADC_performance/performance_0.1.9.txt b/libraries/MCP_ADC/examples/MCP_ADC_performance/performance_0.1.9.txt new file mode 100644 index 00000000..8ce81e54 --- /dev/null +++ b/libraries/MCP_ADC/examples/MCP_ADC_performance/performance_0.1.9.txt @@ -0,0 +1,138 @@ + +IDE: 1.8.19 +Board: UNO + +MCP_ADC_performance.ino +MCP_ADC_LIB_VERSION: 0.1.9 + +ADC CHAN MAXVALUE +mcp2 2 1023 +mcp4 4 1023 +mcp8 8 1023 +mcp22 2 4095 +mcp24 4 4095 +mcp28 8 4095 + +Timing in micros(). + +mcp2.analogRead() 2x: 96 +mcp2.differentialRead() 2x: 96 +mcp2.deltaRead() 2x: 200 + +mcp4.analogRead() 4x: 232 +mcp4.differentialRead() 4x: 236 +mcp4.deltaRead() 4x: 480 + +mcp8.analogRead() 8x: 3780 +mcp8.differentialRead() 8x: 3776 +mcp8.deltaRead() 8x: 3796 + +*************************************** + +1000000 +mcp8.analogRead() 8x: 4100 +mcp8.differentialRead() 8x: 3772 +mcp8.deltaRead() 8x: 3800 + +2000000 +mcp8.analogRead() 8x: 3828 +mcp8.differentialRead() 8x: 3776 +mcp8.deltaRead() 8x: 3796 + +4000000 +mcp8.analogRead() 8x: 3824 +mcp8.differentialRead() 8x: 3772 +mcp8.deltaRead() 8x: 3796 + +8000000 +mcp8.analogRead() 8x: 3832 +mcp8.differentialRead() 8x: 3772 +mcp8.deltaRead() 8x: 3796 + +16000000 +mcp8.analogRead() 8x: 3840 +mcp8.differentialRead() 8x: 3776 +mcp8.deltaRead() 8x: 3796 + +*************************************** + +1000000 +mcp22.analogRead() 2x: 124 +mcp22.differentialRead() 2x: 116 +mcp22.deltaRead() 2x: 232 + +2000000 +mcp22.analogRead() 2x: 108 +mcp22.differentialRead() 2x: 92 +mcp22.deltaRead() 2x: 180 + +4000000 +mcp22.analogRead() 2x: 88 +mcp22.differentialRead() 2x: 76 +mcp22.deltaRead() 2x: 156 + +8000000 +mcp22.analogRead() 2x: 80 +mcp22.differentialRead() 2x: 76 +mcp22.deltaRead() 2x: 148 + +16000000 +mcp22.analogRead() 2x: 80 +mcp22.differentialRead() 2x: 72 +mcp22.deltaRead() 2x: 148 + +*************************************** + +1000000 +mcp24.analogRead() 4x: 248 +mcp24.differentialRead() 4x: 228 +mcp24.deltaRead() 4x: 464 + +2000000 +mcp24.analogRead() 4x: 200 +mcp24.differentialRead() 4x: 180 +mcp24.deltaRead() 4x: 364 + +4000000 +mcp24.analogRead() 4x: 176 +mcp24.differentialRead() 4x: 156 +mcp24.deltaRead() 4x: 316 + +8000000 +mcp24.analogRead() 4x: 156 +mcp24.differentialRead() 4x: 144 +mcp24.deltaRead() 4x: 300 + +16000000 +mcp24.analogRead() 4x: 160 +mcp24.differentialRead() 4x: 140 +mcp24.deltaRead() 4x: 292 + +*************************************** + +1000000 +mcp28.analogRead() 8x: 484 +mcp28.differentialRead() 8x: 452 +mcp28.deltaRead() 8x: 924 + +2000000 +mcp28.analogRead() 8x: 396 +mcp28.differentialRead() 8x: 364 +mcp28.deltaRead() 8x: 728 + +4000000 +mcp28.analogRead() 8x: 340 +mcp28.differentialRead() 8x: 316 +mcp28.deltaRead() 8x: 640 + +8000000 +mcp28.analogRead() 8x: 312 +mcp28.differentialRead() 8x: 292 +mcp28.deltaRead() 8x: 584 + +16000000 +mcp28.analogRead() 8x: 312 +mcp28.differentialRead() 8x: 292 +mcp28.deltaRead() 8x: 584 + +done... diff --git a/libraries/MCP_ADC/keywords.txt b/libraries/MCP_ADC/keywords.txt index 4b185306..d89f8034 100644 --- a/libraries/MCP_ADC/keywords.txt +++ b/libraries/MCP_ADC/keywords.txt @@ -4,6 +4,7 @@ MCP3002 KEYWORD1 MCP3004 KEYWORD1 MCP3008 KEYWORD1 +MCP3201 KEYWORD1 MCP3202 KEYWORD1 MCP3204 KEYWORD1 MCP3208 KEYWORD1 @@ -15,6 +16,7 @@ channels KEYWORD2 maxValue KEYWORD2 analogRead KEYWORD2 +analogReadMultiple KEYWORD2 differentialRead KEYWORD2 deltaRead KEYWORD2 diff --git a/libraries/MCP_ADC/library.json b/libraries/MCP_ADC/library.json index d232f548..a355248c 100644 --- a/libraries/MCP_ADC/library.json +++ b/libraries/MCP_ADC/library.json @@ -1,6 +1,6 @@ { "name": "MCP_ADC", - "keywords": "MCP3002, MCP3004, MCP3008, MCP3202, MCP3204, MCP3208", + "keywords": "MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, MCP3208", "description": "Arduino library for MCP_ADC, e.g. MCP3008 SPI 10 bit, 8 channel ADC", "authors": [ @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/MCP_ADC.git" }, - "version": "0.1.9", + "version": "0.2.0", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/libraries/MCP_ADC/library.properties b/libraries/MCP_ADC/library.properties index dfc23e6b..04f5d3c5 100644 --- a/libraries/MCP_ADC/library.properties +++ b/libraries/MCP_ADC/library.properties @@ -1,9 +1,9 @@ name=MCP_ADC -version=0.1.9 +version=0.2.0 author=Rob Tillaart maintainer=Rob Tillaart -sentence=Arduino library for MCP3002, MCP3004, MCP3008, MCP3202, MCP3204, MCP3208 -paragraph= +sentence=Arduino library for MCP_ADC, e.g. MCP3008 SPI 10 bit, 8 channel ADC +paragraph=MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, MCP3208 category=Sensors url=https://github.com/RobTillaart/MCP_ADC architectures=*