Teensy 4.0 which pins for which ADC

Status
Not open for further replies.
@defragster - Will have to remember that later. Luckily not building too much with it here...

@mjs513 - Pushed up a few more changes/fixes - Playing with the continuous update example. Having issues with enable ISR...

Things like, the test app assumed that there were default ISRs names for these which there app overwrites. T4 we did not setup all of these in the default ISR. So trying to set the vector... But still not being called.

Edit: Now have ISR triggering.. Was not preserving the Interrupt on completion flag in HC0 register.
 
Last edited:
@KurtE

Figured out what was happening with analogRead when doing implementing compare with the T4. The current analogRead gets stuck in in infinite loop on:
Code:
while (!(_padc.HS & ADC_HS_COCO0))
when the compare is false, if compare is true it returns the value. So I created a analogReadCmp function with a timeout in the while statement:
Code:
elapsedMillis timeout;
int ADCL_Module::getAdcCompareRes(uint8_t acmp_pin)
{
  uint8_t ch = ADCL::mapPinToChannel(acmp_pin, 0);
  if (ch == 0xff) {
    fail_flag |= ADC_ERROR::WRONG_PIN;
    return ADC_ERROR_VALUE;
  }
  timeout = 0;
  _padc.HC0 = ch;
  while (!(_padc.HS & ADC_HS_COCO0)){
		if(timeout > 100){
			timeout = 0; // wait
			return 0;
		}
  }
  int temp = _padc.R0;
  return 1;
}
not sure if this is the best way to deal with this problem though. Have to do some more testing with your sine function generator. So I guess that is the next step.

EDIT: Ok I loaded your sine wave sketch onto a T3.6. Hooked up pin A22 on the T3.6 to pin 15 of the T4 that I use in the adc compare sketch and it seems to be working correctly, here is a snapshot of the serialplotter:
Capture1.jpg
 
Last edited:
@KurtE
Just as a FYI I pushed some addition changes to the Compare WIP branch. I did test out the compare and compare range and they seem to be working. The only other change is that I made the function calls match the calls in the ADC lib. Only issue is if we want to keep the analogReadCmp function or merge it with the analogRead function, and test on whether compare is enabled.
 
@KurtE, I've tried using the ADClite files that you previously shared. I did manage to switch between the two ADCs. However, somehow the reading on ADC0 seems to be closer to the waveform: less noise, and periodic. When I switch to ADC1 for the same pin, the data is much worse. Is there a difference in sampling rate between the two? I used the same averaging and resolution for both ADCs. A0 is connected to a 5 MHz sine wave.

Code:
    for (int i = 0; i < ArrayMax-1; i++) {
      
      v1[i] = T4AnalogRead(A0, 1);
}

 for (int i = 0; i < ArrayMax-1; i++) {
      
      Serial.print(v1[i]);
}
 
@mjs513...

I hacked up my test program on T3.5 to generate the sine wave where I use one pot to change the amplitude...
Again not the cleanest setup, but:
Code:
#include <Audio.h>
#define POT_PIN 14
int last_pot_val = 0xffff;
int led_on_time = 256;
int led_off_time = 256;
elapsedMillis led_timer;

// GUItool: begin automatically generated code
AudioSynthWaveform       waveform1;      //xy=110,75
AudioOutputAnalogStereo  audioOutput;
AudioConnection          patchCord1(waveform1, 0, audioOutput, 0);
AudioConnection          patchCord2(waveform1, 0, audioOutput, 1);
// GUItool: end automatically generated code

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(115200);
  AudioMemory(15);
  audioOutput.analogReference(DEFAULT);
  waveform1.begin(WAVEFORM_SINE);
  waveform1.frequency(60);
  waveform1.amplitude(0.99);
  analogReadResolution(12);  // 12 bit resolution
  led_timer = 0;
}

void loop() {
  int pot_val = analogRead(POT_PIN); // lets reduce noise
  if (abs(pot_val - last_pot_val) > 8) {
    last_pot_val = pot_val;
    float new_amp = (float)last_pot_val / 4096.0;
    led_on_time = new_amp * 512;
    led_off_time = 512 - led_on_time;
    waveform1.amplitude(new_amp);
    if (Serial) {
      Serial.print("New Amp: ");
      Serial.print(new_amp, 4);
      Serial.print("(");
      Serial.print(pot_val, DEC);
      Serial.println(")");
    }
  }
  if (digitalReadFast(13)) {
    if (led_timer > led_on_time) {
      digitalWriteFast(13, LOW);
      led_timer = 0;
    }
  } else if (led_timer > led_off_time) {
    digitalWriteFast(13, HIGH);
    led_timer = 0;
  }
}

Now maybe back to figuring out the DMA...

EDIT: FYI - I added in the attachInterrupt(isr_handler, ADC_NUM) like functions as to take care of issue that T4 we don't have fixed ADC irq completion interrupt names which you can overwrite...
 
Last edited:
@mjs513 - Hopefully next up figure out what we should do with the DMA cod with ADC..

Currently there is code in ADC library called class RingBufferDMA which I am sure started from his RingBuffer code, which you could in an ISR do a call to his ringbuffer class, which stores the value in a FIFO...
Where you can then also later call read and the like to extract the data... Makes sense...

But with the RingBufferDMA code, yes he has stuff in it to create a DMAChannel object, and initialize it. But really nothing else after that...
Yes there are read/write functions like above, but no one actually uses them. You register your own callback function, which he registers with the dmaChannel, which gets called when the buffer is filled... In his example he calls back to dmaChannel code to clear the interrupt.

Now to figure out what it should do... Or if most of this calls should be excised and simply add methods to higher level to manage dmabuffer? Or leave it to the caller...
 
@KurtE
Library taking shape. Instead of the ringbuffer @tonton81 has his circular buffer library not sure which is better. Will look at ring buffer tomorrow but wanted to let you know that I did merge for the timeout in analogRead. Next up to get rid of the analogReadCmp function. Wanted to get this baselined first then delete the other function.
 
@mjs513...

Yep coming along.

I am doing a little playing with DMA. So far not updating any of the ADCL class. But here is the start of an example that is continuously doing DMA read operations, and I have it setup to interrupt at half and at end... Then I try to search through the one half of the structure, that should be completed, trying to compute: Min, Max, Avg, Sort of an RMS value...
Still buggy, but in case anyone wishes to see the WIP...

Code:
/*
    It doesn't work for Teensy LC yet!
*/

#include <ADCL_t4.h>
#include <DMAChannel.h>
const int readPin = 15;

ADCL *adc = new ADCL(); // adc object
DMAChannel* dmaChannel;
extern void dumpDMA_TCD(DMABaseClass *dmabc);

volatile uint32_t dma_complete_dt = 0;
volatile uint32_t dma_interrupt_count = 0;

// Define the array that holds the conversions here.
// buffer_size must be a power of two.
// The buffer is stored with the correct alignment in the DMAMEM section
// the +0 in the aligned attribute is necessary b/c of a bug in gcc.
const uint32_t buffer_size = 3200;
const uint32_t HALF_BUFFER = buffer_size / 2;
DMAMEM static volatile int16_t __attribute__((aligned(32))) dma_buffer[buffer_size];

// use dma with ADC0
//RingBufferDMA *dmaBuffer = new RingBufferDMA(buffer, buffer_size, ADC_0);

#if ADC_NUM_ADCS>1
//const int buffer_size2 = 8;
//DMAMEM static volatile int16_t __attribute__((aligned(buffer_size2+0))) buffer2[buffer_size2];
//
//// use dma with ADC1
//RingBufferDMA *dmaBuffer2 = new RingBufferDMA(buffer2, buffer_size2, ADC_1);
#endif // defined

void setup() {
    while (!Serial && millis() < 5000) ;

    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(readPin, INPUT); //pin 23 single ended

    Serial.begin(9600);
    Serial.println("Setup");
    // reference can be ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
    //adc->setReference(ADC_REFERENCE::REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2

    adc->setAveraging(8); // set number of averages
    adc->setResolution(12); // set bits of resolution


    // always call the compare functions after changing the resolution!
    //adc->enableCompare(1.0/3.3*adc->getMaxValue(ADC_0), 0, ADC_0); // measurement will be ready if value < 1.0V
    //adc->enableCompareRange(1.0*adc->getMaxValue(ADC_1)/3.3, 2.0*adc->getMaxValue(ADC_1)/3.3, 0, 1, ADC_1); // ready if value lies out of [1.0,2.0] V

    // enable DMA and interrupts
    Serial.println("before enableDMA"); Serial.flush();


    // setup a DMA Channel.
    dmaChannel = new DMAChannel(); // reserve a DMA channel
    // Now lets see the different things that RingbufferDMA setup for us before
    dmaChannel->source(ADC1_R0);

    dmaChannel->destinationCircular((uint16_t*)dma_buffer, sizeof(dma_buffer)); // 2*b_size is necessary for some reason

    dmaChannel->transferSize(2); // both SRC and DST size

    dmaChannel->transferCount(sizeof(dma_buffer) / sizeof(dma_buffer[0])); // transfer b_size values

    dmaChannel->interruptAtHalf(); //interruptAtHalf or interruptAtCompletion
    dmaChannel->interruptAtCompletion(); //interruptAtHalf or interruptAtCompletion


    dmaChannel->attachInterrupt(dmaBuffer_isr);
    dmaChannel->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1); // start DMA channel when ADC finishes a conversion
    arm_dcache_flush((void*)dmaChannel, sizeof(dmaChannel));
    dmaChannel->enable();


    dumpDMA_TCD(dmaChannel);
    Serial.printf("ADC1: HC0:%x HS:%x CFG:%x GC:%x GS:%x\n", ADC1_HC0, ADC1_HS,  ADC1_CFG, ADC1_GC, ADC1_GS);


    adc->enableDMA(ADC_0);

    // ADC interrupt enabled isn't mandatory for DMA to work.
//  Serial.println("before enableInterrupts"); Serial.flush();
//  adc->enableInterrupts(ADC_0);

    // Start the dma operation..
    adc->analogRead(readPin, ADC_0);

    Serial.println("End Setup");
}

char c = 0;

int average_value = 2048;

void loop() {

    if (dma_complete_dt) {
        // Lets find min/max and compute average...
        uint32_t sum_values = 0;
        uint16_t min_val = 0xffff;
        uint16_t max_val = 0;
        uint16_t *pbuffer = &dma_buffer[(dma_interrupt_count & 1) ? 0 : HALF_BUFFER];
        uint16_t *end_pbuffer = pbuffer + HALF_BUFFER;
        float sum_delta_sq = 0.0;

        arm_dcache_delete((void*)pbuffer, sizeof(dma_buffer)/2);
        while (pbuffer < end_pbuffer) {
            if (*pbuffer < min_val) min_val = *pbuffer;
            if (*pbuffer > max_val) max_val = *pbuffer;
            sum_values += *pbuffer;
            int delta_from_center = (int) * pbuffer - average_value;
            sum_delta_sq += delta_from_center * delta_from_center;

            pbuffer++;
        }

        float rms = sqrt(sum_delta_sq / HALF_BUFFER);
        Serial.printf("%u(%u): %u <= %u <= %u %f\n", dma_interrupt_count, dma_complete_dt, min_val, sum_values / HALF_BUFFER, max_val, rms);
        dma_complete_dt = 0;

    }

}

uint32_t last_isr_time = 0;
void dmaBuffer_isr() {
    uint32_t cur_time = millis();

    digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    //Serial.printf("dmaBuffer_isr: %u\n", cur_time-last_isr_time);
    dma_complete_dt = cur_time - last_isr_time;
    dma_interrupt_count++;
    last_isr_time = cur_time;
    // update the internal buffer positions
    dmaChannel->clearInterrupt();
    asm("DSB");
}

So far results of lower half of reads looks better than upper half. Probably something stupid, like I am deleting the wrong memory cache area... Next quick test is to move it out of DMAMEM...
 
Quick update:
I updated the above sketch not to use the DestinationCircular and interrupt on half way to instead be a setup of two different buffers, each pointed to by a dmaSetting object and then one dmaChannel object which is setup to the same as the first setting...

I am now getting what looks like reasonable values for my averages/counts...

So I added this as an example sketch, which you can play with.

I also updated the Sine wave sketch to be mine with the ability to use a pot to adjust the amplitude... So I have a T3.5 DAC0 pin connected up to the T4 ...

So far this DMA test goes as fast as DMA will run... Have not done the timer through ADC_ETC and XBar...
Maybe first will add 2nd DAC -> other Analog pin ...

Maybe better output stuff...
 
@KurtE

Dug out a pot and hooked into the T3.6 and then ran you updated DMA example. Bottom line up front it works great. Also works no problem with compare. Haven't tried playing with other settings yet. Getting tired again :( Verified the results against my compare sketch that I use for testing.

BTW> The sketch actually makes a great learning tool for setting up DMA :) Thank you.
 
@mjs513 - I just updated both sketches ;)
Now have some of the DMA stuff in a class as part of the sketch, where I then created two instances of it, Where I setup two dma operations, one on ADC1 and other on ADC2...

So updated other sketch to allow second POT and so both DACs can have different amplitude.

Let me know what you think.

Also found an edit bug in the main class for enableDMA, which I fixed and pushed up...
 
Last edited:
@KurtE

I gave your new DMA sketch a test last night and this morning. Looks like only adc fires if 2 adc's are used. In other words if I use adc_0 for pin 15 and adc_1 for pin 14 only adc_0 DMA ISR1 fires and data with be printed for adc_0. Now, if I change pin to use adc_1 and pin 14 to use adc_0 only DMCA isr will fire and data from pin 14 will be printed.

This is what I am getting from the initial output
Code:
Setup ADC_0

before enableDMA

before enableDMA

20001160 400e9000:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200000 DO: 2 CI:640 DL:20001140 CS:12 BI:640
200010e0 20001100:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200000 DO: 2 CI:640 DL:20001140 CS:12 BI:640
20001120 20001140:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200c80 DO: 2 CI:640 DL:20001100 CS:12 BI:640
ADC1: HC0:1f HS:1 CFG:47bb GC:20 GS:0
Setup ADC_1

before enableDMA

20001220 400e9020:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20201900 DO: 2 CI:640 DL:20001200 CS:12 BI:640
200011a0 200011c0:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20201900 DO: 2 CI:640 DL:20001200 CS:12 BI:640
200011e0 20001200:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20202580 DO: 2 CI:640 DL:200011c0 CS:12 BI:640
ADC2: HC0:1f HS:1 CFG:47bb GC:20 GS:0
End Setup
Tried a couple of things but couldn't figure it out. DMA magic I guess.
 
Quick update:
I updated the above sketch not to use the DestinationCircular and interrupt on half way to instead be a setup of two different buffers, each pointed to by a dmaSetting object and then one dmaChannel object which is setup to the same as the first setting...

I am now getting what looks like reasonable values for my averages/counts...

So I added this as an example sketch, which you can play with.

I also updated the Sine wave sketch to be mine with the ability to use a pot to adjust the amplitude... So I have a T3.5 DAC0 pin connected up to the T4 ...

So far this DMA test goes as fast as DMA will run... Have not done the timer through ADC_ETC and XBar...
Maybe first will add 2nd DAC -> other Analog pin ...

Maybe better output stuff...
From T4 beta testing, i had a proof-of-concept sketch for ADC with double-buffered DMA. I only count ticks in the half/complete ISR.
https://github.com/manitou48/teensy4/blob/master/adcdma.ino
and I could get ADC and PIT/XBAR to work together
https://github.com/manitou48/teensy4/blob/master/pitxbaradc.ino
BUT I never figured out how to get PIT+XBAR+ADC+DMA to work (needed for audio lib ADC DMA)
https://github.com/manitou48/teensy4/blob/master/adcdmapit.ino (not working)

(but i haven't been following this thread closely, so this post may not be relevant)
 
@manitou
Thanks for the references. Was poking around your repository yesterday looking what to get ADC and PIT/XBAR to work together. Kept going back to the beta thread to get your links :)
 
@mjs513 - Make sure you picked up the bug fix to enableDMA in adcl_t4.cpp
Code:
void ADCL::enableDMA(int8_t adc_num) 
{
  if (adc_num == 1) 
    [COLOR="#FF0000"]adc1->enableDMA();[/COLOR]
  else 
    adc0->enableDMA();
}
It was using adc0 in both cases... So ADC1 never would work for DMA... (I pulled my hair out for awhile on that one)

Unfortunately I printed out the register settings before the call to enableDMA... Locally I moved the enableDMA to above the dump of the Debug stuff so that the GC value should show DMA enabled...

Also in test sketch when stuff was not working on 2nd ADC, I changed the test sketch slightly:
Code:
#ifdef PROCECESS_2_PINS
    if ( abdma1.interrupt_delta_time && abdma2.interrupt_delta_time) {
        if (abdma1.interrupt_delta_time) ProcessAnalogData(&abdma1, 0);
        if (abdma2.interrupt_delta_time) ProcessAnalogData(&abdma2, 1);
        Serial.println(); 
    }
Where I changed the && to ||
So it would print data if either had info... I left the secondary checks for each one, which in the && case are totally not needed...

I also commented out the changing of pin 13 when ADC1 DMA ISR is called so only when ADC2s... So if no blink again no ISR calls...
 
@manitou - Thanks for the links. I cloned your Teensy4 test project, as to make it easy to find...

I saw that you had a few of these sketches.. Will look some more.

What I am/was curious about, is suppose I wish to read in example 8 Analog pins, and maybe try to set them up to read 4 per ADC.

I was curious if one could use ADC along with ADC_ETC to chain them to each other, where maybe:
ADC1_HC0/R0 is setup to read pin 14, _HC1/R1 pin 15, _HC2/R2 pin 16, _HC3/R3 pin 17.
Can ADC_ETC triggers be setup that when the conversion for HC0 is completed it automatically triggers to read HC1...
I am guessing this would be part of ADC_ETC and probably XBAR...
 
KurtE said:
Make sure you picked up the bug fix to enableDMA in adcl_t4.cpp
Yep. Didn't pick up the bug fix in adcl_t4.cpp. When i copied the example forgot to copy the updates to the lib. Oh I already changed the && to ||. Like you said other wise nothing prints.

Now its working fine. Man its fast :) Looks like you got that solved. Almost time to include it in the lib and get rid of ringBuffer?

Oh, just did a wacky test. I removed the connections to pins 14 and 15 and the isr's keep firing, it keeps printing out the last values read I think. If I plug the pins back in it picks up where it started.
 
@manitou - …..
What I am/was curious about, is suppose I wish to read in example 8 Analog pins, and maybe try to set them up to read 4 per ADC.
….....

Was looking at "I could get ADC and PIT/XBAR to work together https://github.com/manitou48/teensy4...pitxbaradc.ino" and what it is doing is chaining A0 and A1 and then the PIT triggers using XBARA to link to ADC module the read of the of A0 and A1, think that's what you are referring to.

Of, @manitou could answer this one better.
 
Yep. Didn't pick up the bug fix in adcl_t4.cpp. When i copied the example forgot to copy the updates to the lib. Oh I already changed the && to ||. Like you said other wise nothing prints.

Now its working fine. Man its fast :) Looks like you got that solved. Almost time to include it in the lib and get rid of ringBuffer?

Oh, just did a wacky test. I removed the connections to pins 14 and 15 and the isr's keep firing, it keeps printing out the last values read I think. If I plug the pins back in it picks up where it started.
The question is, do I extract the simple class I put into the sketch and make it a reasonable library class object. If so should probably clean up, probably remove direct access to variables, but instead have helper functions for set and query...

Also some times hard to know if it would be helpful or not, to expand on the example. Like maybe add a display to it, which shows the analog data as it changes. Either as simple text or maybe as some gauge or ... But in this case maybe already enough for this test case.

I think their RingBuffer class is OK... In that in this case they setup to use the Analog completion ISR, which then calls the write function to put the data into the ring buffer and you can find out if there is data in the buffer or not and do reads...

However their RingBufferDma class is sort of useless. Also with my example, I was having issue trying to make it work with DMA with circular buffer and interrupt on half way... So instead I went to chained... I noticed a comment in his code that the size of buffer needed to be a power of 2... Not sure if that was issue or not, but was finding that the top half of memory buffer was not going to right place... When I used DMAMEM it was never showing up, when I removed DMAMEM the T4 crashed... So I went to a way that I knew works...


Was looking at "I could get ADC and PIT/XBAR to work together https://github.com/manitou48/teensy4...pitxbaradc.ino" and what it is doing is chaining A0 and A1 and then the PIT triggers using XBARA to link to ADC module the read of the of A0 and A1, think that's what you are referring to.

Of, @manitou could answer this one better.

Looks like an interesting case. In this test case using PIT to trigger, wonder if it would also work with Software trigger of the first one...
If something like this works, wonder if it would make sense to create some member function(s) to read multiple pins... Probably won't have time to look at it for a few days..

Always other diversions ;)
 
Morning @KurtE
This cold is kicking my you know what. Had to crash for a while. But before more coffee.
The question is, do I extract the simple class I put into the sketch and make it a reasonable library class object. If so should probably clean up, probably remove direct access to variables, but instead have helper functions for set and query...

Think you should - it would make life easier to use DMA with ADC. As for using a display - think that may be overkill. What I was using was the SerialPlotter to watch the data changed as adjusted the pot on the T3.6. SerialPlotter does come in handy sometimes for variables at least in the same ranges.

I noticed a comment in his code that the size of buffer needed to be a power of 2
Yep it does make a difference otherwise things get screwy.

When I used DMAMEM it was never showing up, when I removed DMAMEM the T4 crashed... So I went to a way that I knew works..
Always the best way to go. Don't change what you know works especially on the T4.

Looks like an interesting case. In this test case using PIT to trigger, wonder if it would also work with Software trigger of the first one...
If something like this works, wonder if it would make sense to create some member function(s) to read multiple pins... Probably won't have time to look at it for a few days..
Looking at the RM is should work with a Software Trigger as well. There are use cases in the SDK that use a hardware trigger as well as a software trigger. Haven't looked at them yet. I did run @manitou's example and it does work well.

As for incorporating some of it in the lib - was thinking about that myself. But analog is strange so have to figure it out and play with it for a while. At least XBARA stuff doesn't scare me any more after playing it with the encoder stuff.

Ok more coffee.
 
@mjs513 will cleanup...

Also may try an intervalTimer example and see if it works.

Probably won’t be the same as the main ADC library one, but simpler...
 
@mjs513 will cleanup...

Also may try an intervalTimer example and see if it works.

Probably won’t be the same as the main ADC library one, but simpler...

I have started playing with an IntervalTimer based sketch, that reads in 2 different analog pins for both ADCs. Currently I just stuff them into one array inside the interval timer interrupt handler... I deviated from the ADC interval timer code, which only reads one pin per ADC, and uses the ADC ringbuffer. I could still use that.

The other way I deviated was to only use one Interval timer. Also I did not setup to get an ISR on the completion of the analog conversion, but instead simply pull it in during the interval callback, before it starts the next operation... Right now I have it setup to read each at 100us cycles... So pretty fast...
Code:
/*
    This example shows how to use the IntervalTimer library and the ADC library in the Teensy 3.0/3.1

*/



#include "ADCL_t4.h"
#include <IntervalTimer.h>

const int ledPin = LED_BUILTIN;

#define SAMPLES_COUNT  512
const uint8_t ADC0_pins[] = {A0, A1};
const uint8_t ADC1_pins[] = {A2, A3};
#define COUNT_PINS_PER_ADC  sizeof(ADC1_pins)
volatile uint8_t ADCPinIndex = 0;
volatile uint16_t samplesIndex = 0;
DMAMEM uint16_t samples[SAMPLES_COUNT * COUNT_PINS_PER_ADC * 2];

volatile bool timer_running = false;
volatile bool samples_completed = false;

const int interval_period = 100; // us

ADCL *adc = new ADCL(); // adc object

IntervalTimer timer; // timers
extern void timer_callback(void);

void setup() {

  pinMode(ledPin, OUTPUT); // led blinks every loop
  while (!Serial && millis() < 4000) ;
  Serial.begin(9600);

  delay(1000);

  ///// ADC0 ////
  Serial.printf("Configure ADC 1 and 2");
  adc->setAveraging(8); // set number of averages
  adc->setResolution(12); // set bits of resolution
  adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
  adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // change the sampling speed
  adc->setAveraging(8); // set number of averages
  adc->setResolution(12); // set bits of resolution
  adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
  adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // change the sampling speed
  Serial.println("Press any key to run test");
  delay(500);
}

void loop() {

  // First test is to run 512 samples of each analog
  if (Serial.available()) {
    while (Serial.read() != -1) ;
    // first pass just toggle on/off test
    if (!timer_running) {
      samples_completed = false;
      ADCPinIndex = 0;
      samplesIndex = 0;
      adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
      adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
      Serial.println("Starting Timer");
      if (!timer.begin(timer_callback, interval_period)) {
        Serial.println("Failed to start interval timer");
      } else {
        Serial.println("Timer started");
        timer_running = true;
      }
    } else {
      // we should try to kill the timer...
      timer.end();
      Serial.println("Stopped timer");
    }
  }
  if (timer_running) Serial.println(samplesIndex, DEC);
  if (samples_completed) {
    Serial.println("Completed samples");
    samples_completed = false;  // only report once
  }
  delay(10);
}

//==============================================================
// Timer callbck
//==============================================================
void timer_callback(void) {

  digitalWriteFast(ledPin, !digitalReadFast(ledPin));

  // try to grab data from ADC_0
  if (adc->adc0->isComplete()) {
    samples[samplesIndex++] = adc->adc0->readSingle();
  } else {
    Serial.println("ADC_0: did not complete");
  }
  if (adc->adc1->isComplete()) {
    samples[samplesIndex++] = adc->adc1->readSingle();
  } else {
    Serial.println("ADC_1: did not complete");
  }
  if (samplesIndex >= (sizeof(samples) / sizeof(samples[0]))) {
    timer.end();
    timer_running = false;
    samples_completed = true;
  } else {
    ADCPinIndex++;
    if (ADCPinIndex >= sizeof(ADC0_pins)) ADCPinIndex = 0;
    adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
    adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
  }
}

But now may go back and play with other example sketch
 
That looks clean and easy.

Should the setup() of ///// ADC0 really look redundant with 4 commands issued twice to same object?

In the 'not complete' case would it make sense to flag 'no value read' and keep the data in (paired) order? Then it could be handled by the (true == samples_completed) code?
Code:
 else {
    Serial.println("ADC_0: did not complete");
    samples[samplesIndex++] = 65535;
  }
 
Status
Not open for further replies.
Back
Top