///// ADC0 ////
adc->adc0->setAveraging(2); // set number of averages
adc->adc0->setResolution(12); // set bits of resolution
adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED ); // change the conversion speed
adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED ); // change the sampling speed
////// ADC1 /////
adc->adc1->setAveraging(2); // set number of averages
adc->adc1->setResolution(12); // set bits of resolution
adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED ); // change the conversion speed
adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED ); // change the sampling speed
P#24: 2.77V <P#16: 2.97V <P#25: 2.77V <P#18: 3.19V <P#19: 3.19V <P#20: 0.18V <P#21: 0.20V <P#22: 0.13V <P#23: 0.11V <P#14: 0.11V <
10 pins read 49362 times per second at us=386300015 [12062 waitCnt]
The last code I have here was asking for 12 bit ADC reads - with 1 avg - not sure if that gives a more stable 10 bit value? It takes longer - but with the dual read improvement it offset the longer read time.
Here is the code I have last edited - there is an #ifdef for loop versus unrolled with cycle count around the two methods.
YMMV - not sure what I poked at last - but here it is - don't forget to call errCkADC() during debug to test that pin order in array works with the ADC it gets assigned to - perhaps in the 1 second update "if ( lT >= 1000 ) {":
Code:#include <ADC.h> #include <ADC_util.h> ADC *adc = new ADC(); // adc object #define PINS 10 // MUST BE EVEN to read on paired ADC's const uint32_t adc_pins[] = {A10, A2, A11, A4, A5, A6, A7, A8, A9, A0}; void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); while (!Serial && millis() < 4000 ); Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__); ///// ADC0 //// adc->adc0->setAveraging(1); // set number of averages adc->adc0->setResolution(12); // set bits of resolution adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED ); // change the conversion speed adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED ); // change the sampling speed ////// ADC1 ///// adc->adc1->setAveraging(1); // set number of averages adc->adc1->setResolution(12); // set bits of resolution adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED ); // change the conversion speed adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED ); // change the sampling speed //BSerial.println(" ENTER to START \n"); //while ( !Serial.available() ); delay(500); } int value = 0; int pin = 0; uint32_t lC = 0; uint32_t lShow = 0; elapsedMillis lT = 0; void errCkADC(); uint32_t priorR[PINS + 1]; uint32_t wc = 0; void loop() { // delayMicroseconds(32); // Benchmark guess at the time per loop to maintain 25+K reads of 8 pins per second lC++; if ( lT >= 1000 ) { lShow = lC; lC = 0; } uint32_t lastR[PINS + 1]; lastR[PINS] = micros(); uint32_t r10c = ARM_DWT_CYCCNT; #if 0 for (int i = 0; i < PINS; i += 2) { // reads >> 10 pins read 145200 times per second // start reads on both ADCs adc->startSynchronizedSingleRead(adc_pins[i], adc_pins[i + 1]); // wait for both to complete { // some amount of work on prior value testing could be done here // substituting this line for below averages 124 counts waiting for each read delayNanoseconds(60); // Benchmark guess at the time per loop to maintain 25+K reads of 8 pins per second //while (adc->adc0->isConverting() || adc->adc1->isConverting()) wc++; while (adc->adc0->isConverting() || adc->adc1->isConverting()); } // now get both results lastR[i] = adc->adc0->readSingle(); lastR[i + 1] = adc->adc1->readSingle(); } #else { #define someWork //{ delayNanoseconds(50);} uint32_t ii=0; adc->startSynchronizedSingleRead(A10, A2); while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); adc->startSynchronizedSingleRead(A11, A4); someWork while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); adc->startSynchronizedSingleRead(A5, A6); someWork while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); adc->startSynchronizedSingleRead(A7, A8); someWork while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); adc->startSynchronizedSingleRead(A9, A0); someWork while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); } #endif wc += ARM_DWT_CYCCNT - r10c; if ( lShow ) { errCkADC( 999 ); for (int i = 0; i < PINS; i++) { Serial.print("P#"); Serial.print(adc_pins[i]); Serial.print(": "); Serial.print(lastR[i] * 3.3f / adc->adc0->getMaxValue(), 2); Serial.print("V <"); } Serial.printf("\n\t%u pins read %u times per second at us=%lu [%lu waitCnt]\n", PINS, lShow, lastR[PINS], wc / lShow ); lShow = 0; lT = 0; wc = 0; } } void errCkADC( uint32_t vv ) { // Print errors, if any. if (adc->adc0->fail_flag != ADC_ERROR::CLEAR) { Serial.print(vv); Serial.print("<< ADC0: "); Serial.println(getStringADCError(adc->adc0->fail_flag)); } if (adc->adc1->fail_flag != ADC_ERROR::CLEAR) { Serial.print(vv); Serial.print("<< ADC1: "); Serial.println(getStringADCError(adc->adc1->fail_flag)); } adc->resetError(); }
> adc->adc1->setAveraging(1);
You can change the 1 to 2 or more for less noise. Also consider posting a schematic to get a lower noise design - there is more to it than just here and there capacitors.
Thanks man, I will test this.
I tried up to 4 averages. 4 averages gave me an OK result but not as good as analogRead. However I only tested 10bits.
BTW, the delay you are adding. Is that important for the readings to work? I didn't add delay, just ran my code between. I'm guessing it doesn't matter but asking just in case.
Didn't check for errors, I ran my program with monitoring software that prints out telemetry data so I can easily see what's going on. I will check for errors.
#else
{
#define someWork //{ delayNanoseconds(50);}
uint32_t ii=0;
adc->startSynchronizedSingleRead(A10, A2);
[B][COLOR="#FF0000"] someWork_GLOBAL // There will be 'spare' time here as well - but only for working with PRIOR data as no new data yet read this pass.[/COLOR][/B]
while (adc->adc0->isConverting() || adc->adc1->isConverting());
#define someWork_Global { delayNanoseconds(3500);} // Delay waiting for first data to arrive - do Global work
#define someWork { delayNanoseconds(3500);} // stepwise work after 4 of 5 new readings request is pending
uint32_t ii = 0;
adc->startSynchronizedSingleRead(A10, A2);
[B]someWork_Global[/B]
while (adc->adc0->isConverting() || adc->adc1->isConverting());
lastR[ii++] = adc->adc0->readSingle();
lastR[ii++] = adc->adc1->readSingle();
adc->startSynchronizedSingleRead(A11, A4);
[B]someWork[/B]
while (adc->adc0->isConverting() || adc->adc1->isConverting());
lastR[ii++] = adc->adc0->readSingle();
lastR[ii++] = adc->adc1->readSingle();
...
P#24: 2.77V <P#16: 2.97V <P#25: 2.77V <P#18: 3.19V <P#19: 3.19V <P#20: 0.18V <P#21: 0.20V <P#22: 0.13V <P#23: 0.11V <P#14: 0.11V <
10 pins read 49356 times per second at us=291300007 [12065 waitCnt]
#define someWork_Global // { delayNanoseconds(3500);} // Delay waiting for first data to arrive - do Global work
#define someWork // { delayNanoseconds(3500);} // stepwise work after 4 of 5 new readings request is pending
That circuit cant work.
What opamp are you using?
Just coded that in place - where someWork and someWork_Global are just placeholders for timing measure:
Code:#define someWork_Global { delayNanoseconds(3500);} // Delay waiting for first data to arrive - do Global work #define someWork { delayNanoseconds(3500);} // stepwise work after 4 of 5 new readings request is pending uint32_t ii = 0; adc->startSynchronizedSingleRead(A10, A2); [B]someWork_Global[/B] while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); adc->startSynchronizedSingleRead(A11, A4); [B]someWork[/B] while (adc->adc0->isConverting() || adc->adc1->isConverting()); lastR[ii++] = adc->adc0->readSingle(); lastR[ii++] = adc->adc1->readSingle(); ...
With 12 bit read and (2) avg - adding that _Global does not change the unrolled loop runtime:
Code:P#24: 2.77V <P#16: 2.97V <P#25: 2.77V <P#18: 3.19V <P#19: 3.19V <P#20: 0.18V <P#21: 0.20V <P#22: 0.13V <P#23: 0.11V <P#14: 0.11V < 10 pins read 49356 times per second at us=291300007 [12065 waitCnt]
The placeholder is quickly removed with comments:
Code:#define someWork_Global // { delayNanoseconds(3500);} // Delay waiting for first data to arrive - do Global work #define someWork // { delayNanoseconds(3500);} // stepwise work after 4 of 5 new readings request is pending
if ( lT >= 1000 ) {
[B]errCkADC( 1001 ); // call this to be sure ADC reads are working during initial setup[/B]
lShow = lC;
lC = 0;
}
Do add some filtering on the output of the op amps to reduce noise. Try a 1K resistor in series followed by a .1u capacitor to ground. Change capacitor as needed.
The data goes into priorR[] for reference.
The unrolled loop code has the pin #' refs hard coded as array ref took cycles.
Do add some filtering on the output of the op amps to reduce noise. Try a 1K resistor in series followed by a .1u capacitor to ground. Change capacitor as needed.
BTW is it not better to only have the filtering before the op amp to keep the signal as low impedance as possible?
What is an array ref took cycle?
adc_pins[] array reference indexing like in the for(i=0... ) code when unrolled added processor cycles - it seemed because 'i' was no longer an active variable stored in a register.The data goes into priorR[] for reference.
The unrolled loop code has the pin #' refs hard coded as array ref took cycles.
The reference manual says that 4K ohms is low enough source resistance for a T4 ADC input. 1K will be fine, even if an adjustment is needed for higher speed modes. Lower won't make any difference.
adc_pins[] array reference indexing like in the for(i=0... ) code when unrolled added processor cycles - it seemed because 'i' was no longer an active variable stored in a register.
adc->startSynchronizedSingleRead(adc_pins, adc_pins[i + 1]);
versus
adc->startSynchronizedSingleRead(A10, A2);
You can try a 10 ohm resistor and then a 10u capacitor on line from power supply to the op amp.
Like this:
https://electronics.stackexchange.com/questions/275755/rc-low-pass-filters-for-op-amp-power-in-pins
You may not notice the difference.
Also try a capacitor from the piezo negative to ground.