0.2.0 MCP_ADC

This commit is contained in:
Rob Tillaart 2023-08-16 10:07:24 +02:00
parent 24d89995de
commit 1e5fb139fb
22 changed files with 842 additions and 90 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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 --

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 --

View File

@ -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...

View File

@ -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

View File

@ -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": "*",

View File

@ -1,9 +1,9 @@
name=MCP_ADC
version=0.1.9
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
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=*