ADC library, with support for Teensy 4, 3.x, and LC

Hi,

I am aware that for the Teensy 4.0, all analog pins up to A9 can be read by both ADCs. Does anybody know which ADCs can access analog pins A10-A17 on the 4.1?
 
From the core library, looks like A12,A13,A14,A15 are the pins requiring ADC2.

Code:
const uint8_t pin_to_channel[] = { // pg 482
        7,      // 0/A0  AD_B1_02
        8,      // 1/A1  AD_B1_03
        12,     // 2/A2  AD_B1_07
        11,     // 3/A3  AD_B1_06
        6,      // 4/A4  AD_B1_01
        5,      // 5/A5  AD_B1_00
        15,     // 6/A6  AD_B1_10
        0,      // 7/A7  AD_B1_11
        13,     // 8/A8  AD_B1_08
        14,     // 9/A9  AD_B1_09
        1,      // 24/A10 AD_B0_12 
        2,      // 25/A11 AD_B0_13
        128+3,  // 26/A12 AD_B1_14 - only on ADC2, 3
        128+4,  // 27/A13 AD_B1_15 - only on ADC2, 4
        7,      // 14/A0  AD_B1_02
        8,      // 15/A1  AD_B1_03
        12,     // 16/A2  AD_B1_07
        11,     // 17/A3  AD_B1_06
        6,      // 18/A4  AD_B1_01
        5,      // 19/A5  AD_B1_00
        15,     // 20/A6  AD_B1_10
        0,      // 21/A7  AD_B1_11
        13,     // 22/A8  AD_B1_08
        14,     // 23/A9  AD_B1_09
        1,      // 24/A10 AD_B0_12
        2,      // 25/A11 AD_B0_13
        128+3,  // 26/A12 AD_B1_14 - only on ADC2, 3
        128+4,  // 27/A13 AD_B1_15 - only on ADC2, 4
#ifdef ARDUINO_TEENSY41
        255,    // 28
        255,    // 29
        255,    // 30
        255,    // 31
        255,    // 32
        255,    // 33
        255,    // 34
        255,    // 35
        255,    // 36
        255,    // 37
        128+1,  // 38/A14 AD_B1_12 - only on ADC2, 1
        128+2,  // 39/A15 AD_B1_13 - only on ADC2, 2
        9,      // 40/A16 AD_B1_04
        10,     // 41/A17 AD_B1_05
#endif
};

I have some other written notes (not tested code) that A10,A11 are only accessible with ADC1.
 
I'm glad i found this! using teensy 4.1 with single reads of several pins assuming 4.1 had "all ADC pins work with all ADCs"
It was stopping reading when ADC1 read 24/A10 and 25/A11, swapped them to ADC0 and now it is good.
 
I'm having a problem with "setReference"

--------

#include <ADC.h> //ADC support
...
setReference(EXTERNAL); //use external 2.5V ref

-------

gives the following compile error:
'setReference' was not declared in this scope

with Teensy LC / Arduino IDE v1.8.13/ Teensyduino v1.53

setReference(REF_EXT); //gives the same error...

Am I missing something really basic or has a bug crept in? Same results with Teenysduino v1.51 also.
 
Mark, thanks that did the trick. How do we fix the documentation?

Glad to be able to help !!

Sorry, I don't know the answer for your follow-up question. If the error appears on a PJRC website, there's <this thread> where you can report it. If it's some other documentation, Paul will probably need a more specific description of where you found the discrepant info.

Mark J Culross
KD5RXT
 
Last edited:
@pedvide provides the ADC library as a personal external library included with teensyduino: github.com/pedvide/ADC/

And issues could be made against that github for attention resolution in some fashion.

Was "REF_3V3" tried per the docs? The REF_EXT may have a different meaning in ADC context ... i.e. an External pin
 
Hey, you are using a ADC library method without calling it with `ADC->setReference(ref)`.
The solution given to use `analogReference` is using a Teensy core library ADC functions, so not using the ADC library.
See the examples for more information.
 
I'm using a teensy 4.0. Is there a reason why I'm getting twice the noise if I choose to read certain combinations of analog inputs simultaneously? I'm not quite sure what's going on, I'm reading all sensors, two at a time like this:

Code:
void setup() {

///// ADC0 ////
  adc->adc0->setAveraging(4);                                             // 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(4);                                             // 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

}

void loop() {




adc->startSynchronizedSingleRead(A0, A1);

//Here I do some calculations and filtering on the previous two readings

  while (adc->adc0->isConverting() || adc->adc1->isConverting());
  g_sensorValue[0] = (adc->adc0->readSingle());
  g_sensorValue[1] = (adc->adc1->readSingle());
  adc->startSynchronizedSingleRead(A2, A3);
  
//Here I do some calculations and filtering on the previous two readings

  
  while (adc->adc0->isConverting() || adc->adc1->isConverting());
  g_sensorValue[2] = (adc->adc0->readSingle());
  g_sensorValue[3] = (adc->adc1->readSingle());
  adc->startSynchronizedSingleRead(A4, A5);

  //Here I do some calculations and filtering on the previous two readings

 //and so on in the main loop

It seems I get inconsistent results. When ever I recompile and get more noise I recompile using a different combination of two sensors and usually it cleans up. I haven't noted which combinations work and which don't or if it's completely random.

Is there a best combination of analog inputs?

It's not an anomaly, we are talking literally twice the noise. And the noise is 1/f noise.

Here is a picture showing a filtered analog read of an analog input while at the same time another input is being read but not shown here. The only difference between the left and right on the picture is I changed the other analog read input. So if I for example read A0 and A1 I may get noisy readings on A0 and if I change to A0 and A2 I may get low noise on A0.

noise.jpg
 
Last edited:
@frankzappa

As I recall, on the Teensy 3.2 those channel combinations use the same ADC in one case, and different ADC's in the other.

I notice you have the ADC's set for different speeds. The faster setting on ADC0 might produce more noise whenever you are using that ADC. And it seems plausible that when you use them together for a simultaneous read, you could see different behavior.

On noise in general, you will see a lot of noise and a lot of cross talk, if you work with hookup wire and hobby board, and through hole boards will usually give you a lot of noise also.

See this for a link to a note from NXP on noise management,

https://forum.pjrc.com/threads/54977-ADC-performance-achieving-16-bits-(or-very-close-to-it)


And here is a picture of an SMT board that I built for low noise. You can see some of what is involved.

IMG_7161.small.JPG
 
Last edited:
@frankzappa

As I recall, on the Teensy 3.2 those channel combinations use the same ADC in one case, and different ADC's in the other.

I notice you have the ADC's set for different speeds. The faster setting on ADC0 might produce more noise whenever you are using that ADC. And it seems plausible that when you use them together for a simultaneous read, you could see different behavior.

On noise in general, you will see a lot of noise and a lot of cross talk, if you work with hookup wire and hobby board, and through hole boards will usually give you a lot of noise also.

See this for a link to a note from NXP on noise management,

https://forum.pjrc.com/threads/54977-ADC-performance-achieving-16-bits-(or-very-close-to-it)


And here is a picture of an SMT board that I built for low noise. You can see some of what is involved.

View attachment 25314

No the different speeds is a typo. I'm usig the same speeds.

It's an SMT board which I designed to the best of my ability. I'm not dissatisfied with the noise I just want it to be consistent.

What would it be on the board that would give inconsistent results? I'm not sure that it's the switching of analog inputs or if it's just inconsistent?

Note that this is a very filtered signal and what you see is 1/f noise zoomed in.

Here is a more common signal:signal.jpg
 
@frankzappa

Well that is interesting indeed. So the ADC's are configured identically (averaging, speed, amplifier, etc)?

The engineers at NXP are pretty knowledgeable, it would be a big surprise if the two ADC's had significantly different noise.

Nonetheless, my next step would be to compare the noise from the same channel using each of the two ADC's. I recall that the library has calls to read an input with a specific ADC, and that there are a few specific channels that can be read by either ADC.


P/S What do you mean by filtered signal? In circuitry or software? Can we see the unfiltered signals?
 
@frankzappa

Well that is interesting indeed. So the ADC's are configured identically (averaging, speed, amplifier, etc)?

The engineers at NXP are pretty knowledgeable, it would be a big surprise if the two ADC's had significantly different noise.

Nonetheless, my next step would be to compare the noise from the same channel using each of the two ADC's. I recall that the library has calls to read an input with a specific ADC, and that there are a few specific channels that can be read by either ADC.


P/S What do you mean by filtered signal? In circuitry or software? Can we see the unfiltered signals?

Yes same configuration on both channels. The signal I showed is low pass filtered in software. It is a 1.25V DC signal from a voltage reference although you are seeing it as 0. I didn't take a snaphot of the unfiltered signal but it's visible there as well. The noise is the same peak to peak but it switches to the neighboring values much more often.

You are misunderstanding, the ADC's don't have different noise. They behave differently depending on which two analog inputs are selected. Sometimes if I read 10 sensors, 7 of them can look very clean and the other three are misbehaving. If I switch the order of the ADC acquisitons and switch them around I can maybe get 9 of them to look clean.

This is the same on breadboards, SMD PCB's, through hole PCB's. I've only tried it on teensy 4.

It would seem the order of the ADC readings and/or which two are sampled together seems to affect the quality. However I'm not sure it's consistent, I need to write down which analog pairs work well together and test if that's always the case.
 
Last edited:
This will be capacitive coupling issues I think - ADC input sample/hold caps on modern silicon are only a few pF.
If you want noise-free ADC operation you may have to stop the processor to eliminate wide-band signals banging
around the chip all the time. The more complex the chip (code excuting, DMA running, IRQs running, peripherals
active), the more noise is around on the die. If the pins used were only connected to the ADC multiplexer and
nothing else it might be possible to route them away from crosstalk, but if not its pretty much impossible I suspect.

Basically an ADC on a microcontroller/microprocessor chip is always quite a compromize. A dedicated ADC chip with
separate analog and digital supplies and grounds is able to perform way better. But there is a strong business case
for an on-chip ADC even if its poor, as often this enables a smaller BoM when any old ADC will do...
 
This will be capacitive coupling issues I think - ADC input sample/hold caps on modern silicon are only a few pF.
If you want noise-free ADC operation you may have to stop the processor to eliminate wide-band signals banging
around the chip all the time. The more complex the chip (code excuting, DMA running, IRQs running, peripherals
active), the more noise is around on the die. If the pins used were only connected to the ADC multiplexer and
nothing else it might be possible to route them away from crosstalk, but if not its pretty much impossible I suspect.

Basically an ADC on a microcontroller/microprocessor chip is always quite a compromize. A dedicated ADC chip with
separate analog and digital supplies and grounds is able to perform way better. But there is a strong business case
for an on-chip ADC even if its poor, as often this enables a smaller BoM when any old ADC will do...

Yeah I figured it would be something like that. It seems to not be consistent. It doesn't matter which two analog inputs I read simultaneously. If I get noisy signals I just have to recompile a few times until I get a compilation when the planets have aligned and the ones and zeros inside the teensy are in order (or something).
 
I noticed something else. I connected a sensor that I deliberately used a much longer cable so it picks up 60 Hz mains hum, you can see the 60Hz oscillation clearly. When it's misbehaving the 60Hz hum is exactly twice the amplitude. What the hell is going on?

How can it pick up twice the amount of 60Hz from the long cable?

As far as I understand an unshileded cable will pick up mains hum from the power in the walls by capacitive coupling. How come it's sometimes twice as susceptible? It's like a switch inside that randomly turns on to mess with you.
 
explainations !

Hie,
Could you explain your code line by line in order to understand the meaning of the different commands ?

I can guess the global meaning but i 'd like to understand deeper to build my own code for my project.

Sincerely Yours
JC



@Paul, @Pedvide - Not sure what version of sources are in current beta. Some of the test cases did not compile, I edited one and adc_pdb and when I compared my possible push up to github, it showed more differences... So don't think the current beta release matches github\pedvide master? - Code is using old way to specify speeds...

Also when I tried the ringbuffer DMA example it did not appear to do any conversions... I have not debugged...

As I mentioned in the Well monitoring thread, I am playing around with my own version (@hobi not sure if this one will work for you or not).

When I converted to try to use both ADC0 and ADC1 using DMA and PDB, it worked first time, hung second time. Figured out a fix that got it to work... Wonder if maybe should update ADC stopPDB method to zero out the appropriate(PDB0_CH1C1 or PDB0_CH0C1), doing that allowed it to work multiple times.

Not sure if anyone will find this version interesting or not... Again WIP...
Code:
#include <ADC.h>
#include <DMAChannel.h>
#define BUFFER_SIZE 100

ADC adc;

// Variables for ADC0
volatile DMAMEM uint16_t adc0_buf[BUFFER_SIZE]; // buffer 1...
volatile uint8_t adc0_busy = 0;
DMAChannel adc0_dma;

// Variables for ADC1
volatile DMAMEM uint16_t adc1_buf[BUFFER_SIZE];
volatile uint8_t adc1_busy = 0;
DMAChannel adc1_dma;

// References for ISRs...
extern void adc0_dma_isr(void);
extern void adc1_dma_isr(void);


void setup() {
  while (!Serial && millis() < 3000) ;
  Serial.begin(115200);
  Serial.println("Test DMA Analog Read");

  // Initialize the
  adc.setAveraging(4);
  adc.setResolution(12);
  adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_0); // change the conversion speed
  adc.setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_0); // change the sampling speed


  adc.setAveraging(4, ADC_1);
  adc.setResolution(12, ADC_1);
  adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_1); // change the conversion speed
  adc.setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_1); // change the sampling speed
  Serial.printf("First Read of A13: %d\n", adc.analogRead(A13));
  Serial.printf("First Read of A14: %d\n", adc.analogRead(A14));
  Serial.printf("First Read of A15: %d\n", adc.analogRead(A15));
  Serial.printf("First Read of A16: %d\n", adc.analogRead(A16));

  // Lets setup Analog 0 dma
  adc0_dma.source((volatile uint16_t&)ADC0_RA);
  adc0_dma.destinationBuffer(adc0_buf, sizeof(adc0_buf));
  adc0_dma.triggerAtHardwareEvent (DMAMUX_SOURCE_ADC0);
  adc0_dma.interruptAtCompletion();
  adc0_dma.disableOnCompletion();
  adc0_dma.attachInterrupt(&adc0_dma_isr);
  NVIC_DISABLE_IRQ(IRQ_PDB); // we don't want or need the PDB interrupt


  // Lets setup Analog 1 dma
  adc1_dma.source((volatile uint16_t&)ADC1_RA);
  adc1_dma.destinationBuffer(adc1_buf, sizeof(adc1_buf));
  adc1_dma.triggerAtHardwareEvent (DMAMUX_SOURCE_ADC1);
  adc1_dma.interruptAtCompletion();
  adc1_dma.disableOnCompletion();
  adc1_dma.attachInterrupt(&adc1_dma_isr);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Enter any key to run sample");
  while (Serial.read() == -1) ;
  while (Serial.read() != -1) ;
  Serial.println("Start Sample");
  memset((void*)adc0_buf, 0, sizeof(adc0_buf));
  memset((void*)adc1_buf, 0, sizeof(adc1_buf));
  uint32_t start_time = millis();

  // Start 0
  adc0_busy = 1;
  adc1_busy = 1;
  adc.adc0->startSingleRead(A14);
  adc.adc1->startSingleRead(A13);
  adc0_dma.enable();
  adc1_dma.enable();
  adc.enableDMA(ADC_0);
  adc.enableDMA(ADC_1);
  adc0_dma.enable();
  adc1_dma.enable();
  adc.adc0->startPDB(60 * 50);
  adc.adc1->startPDB(60 * 50);

  dumpDMA_TCD("ADC_0", &adc0_dma);
  dumpDMA_TCD("ADC_1", &adc1_dma);

  while (adc0_busy || adc1_busy) {
    if ((millis() - start_time) > 1000) {
      Serial.printf("Timeout %d %d\n", adc0_busy, adc1_busy);
      break;
    }
  }
  
[COLOR="#FF0000"]  PDB0_CH1C1 = 0;
  PDB0_CH0C1 = 0;[/COLOR]

  adc.adc0->stopPDB();
  adc0_dma.disable();
  adc.disableDMA(ADC_0);
  adc0_dma.disable();

  adc.adc1->stopPDB();
  adc.adc1->stopPDB();
  adc1_dma.disable();
  adc.disableDMA(ADC_1);

  dumpDMA_TCD("ADC_0", &adc0_dma);
  dumpDMA_TCD("ADC_1", &adc1_dma);

  Serial.printf("Sample completed: %d\n", millis() - start_time);
  for (int i = 0; i < BUFFER_SIZE; i++) {
    Serial.printf("%4u ", adc0_buf[i]);
    if ((i % 20) == 19) Serial.println();
  }
  Serial.println("\n");

  for (int i = 0; i < BUFFER_SIZE; i++) {
    Serial.printf("%4u ", adc1_buf[i]);
    if ((i % 20) == 19) Serial.println();
  }
  Serial.println();


}


void adc0_dma_isr(void)
{
  adc0_busy = false;
  adc0_dma.clearInterrupt();
  adc0_dma.clearComplete();
}

void adc1_dma_isr(void)
{
  adc1_busy = false;
  adc1_dma.clearInterrupt();
  adc1_dma.clearComplete();
}



typedef struct  __attribute__((packed, aligned(4))) {
  uint32_t SADDR;
  int16_t SOFF;
  uint16_t ATTR;
  uint32_t NBYTES;
  int32_t SLAST;
  uint32_t DADDR;
  int16_t DOFF;
  uint16_t CITER;
  int32_t DLASTSGA;
  uint16_t CSR;
  uint16_t BITER;
} TCD_DEBUG;

void dumpDMA_TCD(const char *psz, DMABaseClass *dmabc)
{
  Serial.printf("%s %08x %08x:", psz, (uint32_t)dmabc, (uint32_t)dmabc->TCD);
  TCD_DEBUG *tcd = (TCD_DEBUG*)dmabc->TCD;
  Serial.printf("%08x %04x %04x %08x %08x ", tcd->SADDR, tcd->SOFF, tcd->ATTR, tcd->NBYTES, tcd->SLAST);
  Serial.printf("%08x %04x %04x %08x %04x %04x\n", tcd->DADDR, tcd->DOFF, tcd->CITER, tcd->DLASTSGA,
                tcd->CSR, tcd->BITER);

}
Adding the lines in RED was what got it to work multiple times... Now back to next part of what I mentioned in well monitor...
 
If both the noise and the 60 Hz pickup change by a factor of 2, that sounds like the different sampling configurations are somehow either changing the effective impedance of the ADC input at those frequencies, or simply the actual overall gain of the channel. Is it possible there is a single-ended vs. differential mode being used? Seems like there should be a way to measure that systematically.
 
I succeeded in setting up the ADC + DMA library example on a Teensy 4.1 for continuous conversion of a single pin. Is it possible to extend that to multiple pins?

I come from ST microcontrollers and there it is pretty common to have an adc buffer with length = number of pins to measure and let the DMA transfer the ADCs results continuously. That way you can access the latest ADC measurements whenever you want in your code without need to worry about timing.

Thank you for any hint :)
 
I succeeded in setting up the ADC + DMA library example on a Teensy 4.1 for continuous conversion of a single pin. Is it possible to extend that to multiple pins?
...
Thank you for any hint :)[/QUOTE]

Possible? Yes. Is the support in the library? I don't think so.
Would it be hard to hack it up... Probably not...

Look at the example adc_timer_dma.ino

Code:
#if defined(__IMXRT1062__)

  Serial.println("\n*** ADC and ADC_ETC ***");
  Serial.printf("ADC1: HC0:%x HS:%x CFG:%x GC:%x GS:%x\n", IMXRT_ADC1.HC0, IMXRT_ADC1.HS,  IMXRT_ADC1.CFG, IMXRT_ADC1.GC, IMXRT_ADC1.GS);
  Serial.printf("ADC2: HC0:%x HS:%x CFG:%x GC:%x GS:%x\n", IMXRT_ADC2.HC0, IMXRT_ADC2.HS,  IMXRT_ADC2.CFG, IMXRT_ADC2.GC, IMXRT_ADC2.GS);
  Serial.printf("ADC_ETC: CTRL:%x DONE0_1:%x DONE2_ERR:%x DMA: %x\n", IMXRT_ADC_ETC.CTRL,
                IMXRT_ADC_ETC.DONE0_1_IRQ, IMXRT_ADC_ETC.DONE2_ERR_IRQ, IMXRT_ADC_ETC.DMA_CTRL);
  for (uint8_t trig = 0; trig < 8; trig++) {
    Serial.printf("    TRIG[%d] CTRL: %x CHAIN_1_0:%x\n",
                  trig, IMXRT_ADC_ETC.TRIG[trig].CTRL, IMXRT_ADC_ETC.TRIG[trig].CHAIN_1_0);
  }
#endif
Notice the .CHAIN_1_0...
To understand these you need to look at the Reference Manual ADC_ETC chapter (67).
You will see there are 4 chain registers, each can handle 2 pins, (The pins need to be defined as the ADC pin number... And if I remember correctly there is another register
that will say how many in the chain.

When setup if I remember correctly, the DMA output, will intermix all of the results in the same DMA stream, one after another.....
 
Okay, i am getting closer after digging into chapter 67.
What i tried to do:
Based on the example "adc_timer_dma" i try to make the (Quad-)Timer trigger the ADC conversion of ADC1 and ADC2.
ADC0 is set up as the library does with only one Pin (= chain length 1) with Teensy Pin 14 = ADC0_NR 7
ADC1 is set up as a chain of length 2 with Teensy Pin 40 has ADC1_NR 9 and Teensy Pin 27 has ADC1_NR 4

But only ADC0 throws interrupts, i don't know if ADC1 actually runs.
Below is the result of print_debug_information().
I am not sure what the settings of ADC2:HC0 should be...

Code:
*** DMA structures for ADC_0 ***
2004d6a0 400e9000:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200002 DO: 2 CI:7 DL:2004d680 CS:12 BI:8
2004d620 2004d640:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200000 DO: 2 CI:8 DL:2004d680 CS:12 BI:8
2004d660 2004d680:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200020 DO: 2 CI:8 DL:2004d640 CS:12 BI:8

*** DMA structures for ADC_1 ***
2004d760 400e9020:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20200042 DO: 2 CI:7 DL:2004d740 CS:12 BI:8
2004d6e0 2004d700:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20200040 DO: 2 CI:8 DL:2004d740 CS:12 BI:8
2004d720 2004d740:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20200060 DO: 2 CI:8 DL:2004d700 CS:12 BI:8

*** ADC and ADC_ETC ***
ADC1: HC0:10 HS:0 CFG:16278 GC:22 GS:0
ADC2: HC0:10 HS:0 CFG:16278 GC:22 GS:0
ADC_ETC: CTRL:20000011 DONE0_1:0 DONE2_ERR:0 DMA: 11
    TRIG[0]_CTRL: 0 CHAIN_1_0: 2017
    TRIG[1]_CTRL: 0 CHAIN_1_0:0
    TRIG[2]_CTRL: 0 CHAIN_1_0:0
    TRIG[3]_CTRL: 0 CHAIN_1_0:0
    TRIG[4]_CTRL: 100 CHAIN_1_0: 2004 1019
    TRIG[5]_CTRL: 0 CHAIN_1_0:0
    TRIG[6]_CTRL: 0 CHAIN_1_0:0
    TRIG[7]_CTRL: 0 CHAIN_1_0:0

The interesting part is probably:

* this works *
TRIG[0]_CTRL: 0 CHAIN_1_0: 2017
TRIG chain length = 1, no Sync mode, lowest priority, hardware trigger
Chain 0:
- Interrupt on Done0
- Hardware trigger 0 (timer overflow creates a hardware trigger?)
- ADC channel 7 selected
Chain 1: not used

* this does not create interrupts (or work at all) *
TRIG[4]_CTRL: 100 CHAIN_1_0: 2004 1019
Chain 0:
- No interrupt
- B2B back-to-back enabled
- HW trigger 0
- ADC channel 9
Chain 1:
- Interrupt on Done0
- B2B disabled
- No hardware trigger
- ADC channel 4
 
Sorry for not seeing this sooner @KurtE pointed me too it. Back in the T4 test days played a lot with ADC to get chaining to work. Put together a sketch (non-DMA) that sets up the proper configuration and interrupts to get it working.

View attachment ADCLpitxbaradcV8.zip

The sketch uses both ADC0 and ADC1. In the adc_etc_setup.ino file has the interesting bits on configuration for chaining and setting up the ISRs. For instance:

Code:
void adc0_etc_ctrl_init(uint8_t chainLength_0,
                  int adc_0_pinArray[], 
                  uint8_t trigger_adc_0, bool DMA) 
{
  int numPins_adc_0 = sizeof(adc_0_pinArray);
  uint8_t adc_pin_channel, res;

  delay(5);
  
  // Now lets process ADC1(ADC_0) pin...
  
  for(uint8_t i = 0; i < numPins_adc_0; i++){
    // check pins
    if ( !adc->adc0->checkPin(adc_0_pinArray[i]) ) {
        Serial.printf("ADC_ETC_INIT: pin:%d did not map to channnel on %d\n", adc_0_pinArray[i], ADC_0);
        adc->adc0->fail_flag |= ADC_ERROR::WRONG_PIN;
        return res;
    }
    //adc_pin_channel = mapPinToChannel(adc_0_pinArray[i], ADC_0);
    //if (adc_pin_channel == 0xff) 
    //  Serial.printf("ADC_ETC_INIT: pin:%d did not map to channnel on %d\n", adc_0_pinArray[i], ADC_0);
  }
  IMXRT_ADC_ETC.CTRL = (ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1<<trigger_adc_0)); // 0x40000001;  // start with trigger 0
  IMXRT_ADC_ETC.TRIG[trigger_adc_0].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(chainLength_0-1);

  if(DMA)
    IMXRT_ADC_ETC.DMA_CTRL = ADC_ETC_DMA_CTRL_TRIQ_ENABLE(trigger_adc_0);
  Serial.printf("ADC1: HC0:%x HS:%x CFG:%x GC:%x GS:%x\n", ADC1_HC0, ADC1_HS,  ADC1_CFG, ADC1_GC, ADC1_GS);
  Serial.printf("ADC_ETC: CTRL:%x DMA: %x TRIG0: CTRL: %x CHAIN01:%x\n",
                IMXRT_ADC_ETC.CTRL, IMXRT_ADC_ETC.DMA_CTRL, ADC_ETC_TRIG0_CTRL, ADC_ETC_TRIG0_CHAIN_1_0);

}
the function takes as input the chain length = number of adc pins which is read in via the pin array from the main sketch:
Code:
int adc_0_pins[] = {14, 15, 16, 17};
uint8_t trigger_adc_0 = 0;

As well as the trigger pin (trigger_adc_0) and a boolean if you want to config it to use DMA.

There are a few more things like setting it up for a timer interrupt. Enjoy - hope it helps
 
Thank you so much for your input! I got the chain to work without DMA.
The key was to set the CHAIN_X_Y registers correctly.
Therefore i made a modified version of the library function "startQuadTimer":

Code:
void ADC_Module::startQuadTimer(uint32_t freq)
{
    // Update the ADC
    uint8_t adc_pin_channel = adc_regs.HC0 & 0x1f; // remember the trigger that was set 
    uint8_t arr[1];
    arr[0] = adc_pin_channel;
    startQuadTimer(freq, 1, arr, false);
}


void ADC_Module::startQuadTimer(uint32_t freq, uint8_t nrOfPins, uint8_t* pinArray, bool pinsAreTeensyPins)
{  
    if(pinsAreTeensyPins) {
        for (uint8_t k=0; k<nrOfPins; k++) {
            Serial.printf("startQuadTimer: Teensy Pin %i has ADC%i_NR ", pinArray[k], ADC_num);
            pinArray[k] = channel2sc1a[pinArray[k]];
            Serial.println(pinArray[k]);
        }
    }  
    Serial.printf("startQuadTimer: ADC_ETC_TRIGGER_INDEX = %i", ADC_ETC_TRIGGER_INDEX);
    Serial.println();

    // First lets setup the XBAR
    CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON); //turn clock on for xbara1
    xbar_connect(XBAR_IN, XBAR_OUT);

    // Update the ADC
    // uint8_t adc_pin_channel = adc_regs.HC0 & 0x1f; // remember the trigger that was set 
    setHardwareTrigger();                          // set the hardware trigger
    adc_regs.HC0 = (adc_regs.HC0 & ~0x1f) | 16;    // trigger only by ADC_ETC channel remember other states...
    singleMode();                                  // make sure continuous is turned off as you want the trigger to di it.

    // 
    Serial.printf("startQuadTimer: adc_regs.HC0 = 0x");
    Serial.println(adc_regs.HC0, 16);

    // setup adc_etc - BUGBUG have not used the preset values yet.
    if (IMXRT_ADC_ETC.CTRL & ADC_ETC_CTRL_SOFTRST)
    { // SOFTRST
        // Soft reset - ORIGINAL from lib
        //atomic::clearBitFlag(IMXRT_ADC_ETC.CTRL, ADC_ETC_CTRL_SOFTRST);
        // Soft reset from PJRC forum
        IMXRT_ADC_ETC.CTRL = ADC_ETC_CTRL_SOFTRST; // SOFTRST
        IMXRT_ADC_ETC.CTRL &= ~ADC_ETC_CTRL_SOFTRST; // SOFTRST
        delay(5); // give some time to be sure it is init
    }
    if (ADC_num == 0)
    { // BUGBUG - in real code, should probably know we init ADC or not..
        // what is this Bypass thing?
        IMXRT_ADC_ETC.CTRL |= (ADC_ETC_CTRL_TSC_BYPASS | ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1 << ADC_ETC_TRIGGER_INDEX)); // 0x40000001;  // start with trigger 0
        //IMXRT_ADC_ETC.CTRL = (ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1 << ADC_ETC_TRIGGER_INDEX)); // 0x40000001;  // start with trigger 0
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(nrOfPins-1);   // TH: chain length // chainlength -1 only us
    }
    else
    {
        // This is our second one... Try second trigger?
        // what is this Bypass thing? Manual says clear that bit on ADC2
        IMXRT_ADC_ETC.CTRL &= ~(ADC_ETC_CTRL_TSC_BYPASS); // 0x40000001;  // start with trigger 0
        IMXRT_ADC_ETC.CTRL |= ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1 << ADC_ETC_TRIGGER_INDEX); // Add trigger
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(nrOfPins-1);   // TH: chain length // chainlength -1 only us
    }
    if(nrOfPins == 1) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 = ADC_ETC_TRIG_CHAIN_IE0(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]); /*| ADC_ETC_TRIG_CHAIN_B2B0 */
    } else if (nrOfPins == 2) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
    } else if (nrOfPins == 3) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0;
    } else if (nrOfPins == 4) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[3]) | ADC_ETC_TRIG_CHAIN_B2B1;
    } else if (nrOfPins == 5) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[3]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_5_4 |= 
        ADC_ETC_TRIG_CHAIN_IE0(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[4]) | ADC_ETC_TRIG_CHAIN_B2B0;
    } else if (nrOfPins == 6) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[3]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_5_4 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[4]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[5]) | ADC_ETC_TRIG_CHAIN_B2B1;
    } else if (nrOfPins == 7) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[3]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_5_4 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[4]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[5]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_7_6 |= 
        ADC_ETC_TRIG_CHAIN_IE0(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[6]) | ADC_ETC_TRIG_CHAIN_B2B0;
    } else if (nrOfPins >= 8) {
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[0]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[1]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_3_2 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[2]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[3]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_5_4 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[4]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(0) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[5]) | ADC_ETC_TRIG_CHAIN_B2B1;
        IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_7_6 |= 
        ADC_ETC_TRIG_CHAIN_IE0(0) | ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(pinArray[6]) | ADC_ETC_TRIG_CHAIN_B2B0 |
        ADC_ETC_TRIG_CHAIN_IE1(ADC_num+1) | ADC_ETC_TRIG_CHAIN_HWTS1(1) | ADC_ETC_TRIG_CHAIN_CSEL1(pinArray[7]) | ADC_ETC_TRIG_CHAIN_B2B1;
    }

    if (interrupts_enabled)
    {
        // Not sure yet?
    }
    if (adc_regs.GC & ADC_GC_DMAEN)
    {
        IMXRT_ADC_ETC.DMA_CTRL |= ADC_ETC_DMA_CTRL_TRIQ_ENABLE(ADC_ETC_TRIGGER_INDEX);
    }

    // Now init the QTimer.
    // Extracted from quadtimer_init in pwm.c but only the one channel...
    // Maybe see if we have to do this every time we call this.  But how often is that?
    IMXRT_TMR4.CH[QTIMER4_INDEX].CTRL = 0; // stop timer
    IMXRT_TMR4.CH[QTIMER4_INDEX].CNTR = 0;
    IMXRT_TMR4.CH[QTIMER4_INDEX].SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS | TMR_SCTRL_VAL | TMR_SCTRL_FORCE;
    IMXRT_TMR4.CH[QTIMER4_INDEX].CSCTRL = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_ALT_LOAD;
    // COMP must be less than LOAD - otherwise output is always low
    IMXRT_TMR4.CH[QTIMER4_INDEX].LOAD = 24000; // low time  (65537 - x) -
    IMXRT_TMR4.CH[QTIMER4_INDEX].COMP1 = 0;    // high time (0 = always low, max = LOAD-1)
    IMXRT_TMR4.CH[QTIMER4_INDEX].CMPLD1 = 0;
    IMXRT_TMR4.CH[QTIMER4_INDEX].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) |
                                        TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);

    quadtimerFrequency(&IMXRT_TMR4, QTIMER4_INDEX, freq);
    quadtimerWrite(&IMXRT_TMR4, QTIMER4_INDEX, 5);
}

Anyways, when using a DMA, the DMA buffer does not always start with the same ADC value. My buffer length is equal to the nr of pins i am measuring and i also see all the values correctly, but the start index in the DMA buffer changes.
I am practicacally using the library example adc_timer_dma.ino with my modified startQuadTimer function.
I also noticed, that:
- pabdma->interruptDeltaTime() does not correspond to the timer interval, instead it is always shorter by roughly factor 2
- the buffer length changes the frequency of DMA interrupts (= debug output in my case), smaller buffer means higher interrupt rate
- Done0/1/2 settings in the chain registers do not affect the DMA triggering at all (which is expected as the DMA seems to be linked to the trigger source of the ADC chain...)

Code:
void setup() {
const uint32_t buffer_size = 5;
DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);

adc->adc0->setAveraging(32); // set number of averages
adc->adc0->setResolution(12); // set bits of resolution
abdma1.init(adc, ADC_0);
adc->adc0->startTimer(100, 5, potPins, true); // This uses my modified function from above, start timer at 100 Hz, sample an array (potPins) of length 5
}

void loop() {
  if ( abdma1.interrupted()) {
    ProcessAnalogData(&abdma1, 0);
  }
}

void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {

  volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
  if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff2_1));

  Serial.printf("interruptDeltaTime: %i ms    ", pabdma->interruptDeltaTime());
  for(uint8_t i=0; i<5; i++) {
      Serial.printf("%i     ", pbuffer[i]);
  }
  Serial.println();
  pabdma->clearInterrupt();
}
 
Back
Top