Using two ADCs to sample 8 signals

Status
Not open for further replies.

SaileNav

Active member
I successfully used one ADC to measure 4 analog signals by switching between them in a round robin fashion.
Now, I want to extend this to use the second adc on the Teensy 3.1 and capture 8 analog signals.
I tried the straightforward method of duplicating my dma and adc definitions as follows;

DMA setup:
Code:
void setup_dma() {
  dma0->begin(true);              // allocate the DMA channel 
  dma0->TCD->SADDR = &ADC0_RA;    // where to read from
  dma0->TCD->SOFF = 0;            // source increment each transfer
  dma0->TCD->ATTR = 0x101;
  dma0->TCD->NBYTES = 2;     // bytes per transfer
  dma0->TCD->SLAST = 0;
  dma0->TCD->DADDR = &adcbuffer_0[0][0];// where to write to
  dma0->TCD->DOFF = 2; 
  dma0->TCD->DLASTSGA = -2*BUF_SIZE;
  dma0->TCD->BITER = BUF_SIZE;
  dma0->TCD->CITER = BUF_SIZE;    
  dma0->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0);
  dma0->disableOnCompletion();    // require restart in code
  dma0->interruptAtCompletion();
  dma0->attachInterrupt(dma0_isr);
  
  dma1->begin(true);              // allocate the DMA channel 
  dma1->TCD->SADDR = &ChannelsCfg_0[0];
  dma1->TCD->SOFF = 2;            // source increment each transfer
  dma1->TCD->ATTR = 0x101;
  dma1->TCD->SLAST = -8;
  dma1->TCD->BITER = 4;
  dma1->TCD->CITER = 4;
  dma1->TCD->DADDR = &ADC0_SC1A;
  dma1->TCD->DLASTSGA = 0;
  dma1->TCD->NBYTES = 2;
  dma1->TCD->DOFF = 0;
  dma1->triggerAtTransfersOf(*dma0);
  dma1->triggerAtCompletionOf(*dma0);

  dma2->begin(true);              // allocate the DMA channel 
  dma2->TCD->SADDR = &ADC1_RA;    // where to read from
  dma2->TCD->SOFF = 0;            // source increment each transfer
  dma2->TCD->ATTR = 0x101;
  dma2->TCD->NBYTES = 2;     // bytes per transfer
  dma2->TCD->SLAST = 0;
  dma2->TCD->DADDR = &adcbuffer_1[0][0];// where to write to
  dma2->TCD->DOFF = 2; 
  dma2->TCD->DLASTSGA = -2*BUF_SIZE;
  dma2->TCD->BITER = BUF_SIZE;
  dma2->TCD->CITER = BUF_SIZE;    
  dma2->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1);
  dma2->disableOnCompletion();    // require restart in code
  dma2->interruptAtCompletion();
  dma2->attachInterrupt(dma2_isr);
  
  dma3->begin(true);              // allocate the DMA channel 
  dma3->TCD->SADDR = &ChannelsCfg_1[0];
  dma3->TCD->SOFF = 2;            // source increment each transfer
  dma3->TCD->ATTR = 0x101;
  dma3->TCD->SLAST = -8;
  dma3->TCD->BITER = 4;
  dma3->TCD->CITER = 4;
  dma3->TCD->DADDR = &ADC1_SC1A;
  dma3->TCD->DLASTSGA = 0;
  dma3->TCD->NBYTES = 2;
  dma3->TCD->DOFF = 0;
  dma3->triggerAtTransfersOf(*dma2);
  dma3->triggerAtCompletionOf(*dma2);

  dma0->enable();
  dma1->enable();
  
  dma2->enable();
  dma3->enable();
}

ADC setup:
Code:
void setup_adc() {
  adc->adc0->setResolution(16); // set bits of resolution
  adc->adc1->setReference(INTERNAL);
  adc->adc0->setResolution(16); // set bits of resolution
  adc->adc1->setReference(INTERNAL);

  adc->adc0->enableDMA();
  adc->adc1->enableDMA();
  
  ADC0_SC1A = ChannelsCfg_0[3];
  ADC1_SC1A = ChannelsCfg_1[3];
}

Interrupt routines:
Code:
void dma0_isr(void) {
    ibuf_0=(ibuf_0+1) % NO_BUFFERS;
    dma0->TCD->DADDR = &adcbuffer_0[ibuf_0][0];
    dma0->clearInterrupt();
    dma0->enable();
}

void dma2_isr(void) {
    ibuf_1=(ibuf_1+1) % NO_BUFFERS;
    dma2->TCD->DADDR = &adcbuffer_1[ibuf_1][0];
    dma2->clearInterrupt();
    dma2->enable();
}

Channel configurations (pin numbers):
Code:
const uint16_t ChannelsCfg_0 [] =  { 0x46, 0x47, 0x4F, 0x44 };
const uint16_t ChannelsCfg_1 [] =  { 0x44, 0x45, 0x46, 0x47 };

Completely symmetrical.
Unfortunately I am only able to record the analog signals coming from adc0.
Here is a plot of the captured signals:
amplitude_8ch.png
ch 1,2,3,4 are coming from adc0 and ch 5,6,7,8 are samples from adc1.
So channel 4,5,6,7 show a signal that seems to be grounded, but this seems weird because the reference is 1.2V.

Does anyone have an idea about what I am doing wrong here?
Thanks in advance
 
Last edited:
I already use Pedvide's Teensy 3.x ADC library

This project uses Pedvide's Teensy 3.x ADC library, as you can see in the code snippets of my first post. The adc object is used in setup_adc() function.

Code:
#include "DMAChannel.h"
#include "ADC.h" 

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

DMA channel dma1 and dma3 overwrite the registers of adc0 and adc1 respectively, to be able to switch the target pin of the adcs.
ChannelsCfg_0 -> dma1 -> target adc0
ChannelsCfg_1 -> dma3 -> target adc1

A single cycle happens as follows;
At the end of the conversion (ADC0), DMA channel dma0 is triggered and the result is copied to adcbuffer_0. Once the transfer of dma0 is completed, dma1 is triggered, which loads a new configuration to the ADC register. The configuration contains the target pin. adc0 starts converting automatically once the transfer to the setting register is completed, which brings us back to the beginning.

The bottom line:
The project worked perfect when I only use one adc0.
In case I try to also use adc1 in a similar manner the output is a signal close to the ground.
 
You're trying to read pins that ADC1 can't access!
ADC1 can only read A2, A3, A15-A20, A10, A12, A13. (see the image at in the first post of the ADC library). A11 cannot be used in single-ended mode by ADC1, only in differential mode.
Change your ChannelsCfg_1 to those channels, but be careful because some of them need the muxel a set in ADC1_CFG2 (those marked with ADC1_SE#a in the figure).
 
I aim to use A16-A19.

Thanks for the reply!

To make the discussion easier, I added the figure you are referencing.
Teensy3_1_AnalogCard.png

I aim to use A16-A19.
A16 -> ADC1_SE5b
A17 -> ADC1_SE4b
A18 -> ADC1_SE6b
A19 -> ADC1_SE7b

They are all marked with #b so we don't have to change ADC1_CFG2.

In the K20 Sub-Family Reference Manual p654, I checked how the ADCx_SC1n register should be set.
I copied the figure here;

Screenshot 2016-06-23 14.27.26.png


Everything from bit 31-8 does not matter.
COCO (bit 7) is the conversion complete flag. I don't really know what to set here, but I guess it is zero because after we are done with writing to this register the conversion should start.
AIEN (bit 6) is the Conversion complete interrupt, this should be enabled in our case
DIFF (bit 5) should be disabled.
ADCH (bit 4-0) is input channel select setting.

A16 -> ADC1_SE5b -> input channel 5 -> 0b01000101 -> 0x45
A17 -> ADC1_SE4b -> input channel 4 -> 0b01000100 -> 0x44
A18 -> ADC1_SE6b -> input channel 6 -> 0b01000110 -> 0x46
A19 -> ADC1_SE7b -> input channel 7 -> 0b01000111 -> 0x47

Code:
const uint16_t ChannelsCfg_1 [] =  { 0x44, 0x45, 0x46, 0x47 };

So it seems to me that it should work.

Thanks in advance
 
Last edited:
Yes, you're right! I was looking at the ADC0 numbers by mistake.
Now I see that in adc_setup you use adc->adc1->setReference(INTERNAL);
What's INTERNAL? You should be using ADC_REF_3V3, ADC_REF_1V2, or ADC_REF_EXT.
How are you doing the tests? Is ch4 connected to the same as ch0? or to something different?
 
Another thing: Have dma2_isr blink a led to make sure it executes, do the same for adc0_isr and adc1_isr.
 
Yes, you're right! I was looking at the ADC0 numbers by mistake.
Now I see that in adc_setup you use adc->adc1->setReference(INTERNAL);
What's INTERNAL? You should be using ADC_REF_3V3, ADC_REF_1V2, or ADC_REF_EXT.
How are you doing the tests? Is ch4 connected to the same as ch0? or to something different?

ch0 and ch4 are sampling the same signal
ch1 and ch5 are sampling the same signal
ch2 and ch6 are sampling the same signal
ch3 and ch7 are sampling the same signal

I changed INTERNAL to ADC_REF_1V2.

Code:
void setup_adc() {
  adc->adc0->setResolution(16); // set bits of resolution
  adc->adc1->setReference(ADC_REF_1V2);
  adc->adc0->setResolution(16); // set bits of resolution
  adc->adc1->setReference(ADC_REF_1V2);

  adc->adc0->enableDMA(); //ADC0_SC2 |= ADC_SC2_DMAEN;  // using software trigger, ie writing to ADC0_SC1A
  adc->adc1->enableDMA();
  
  ADC0_SC1A = ChannelsCfg_0[3];
  ADC1_SC1A = ChannelsCfg_1[3];
}

Nonetheless I get the same result:
amplitude_8ch.png
 
Another thing: Have dma2_isr blink a led to make sure it executes, do the same for adc0_isr and adc1_isr.

As you suggested I changed dma2_isr to blink the led.

Code:
void dma2_isr(void) {
    digitalWrite(ledPin, HIGH);   // set the LED on
    delay(100);                  // wait for a second
    digitalWrite(ledPin, LOW);    // set the LED off
    delay(100); 
    ibuf_1=(ibuf_1+1) % NO_BUFFERS;
    dma2->TCD->DADDR = &adcbuffer_1[ibuf_1][0];
    dma2->clearInterrupt();
    dma2->enable();
}

and now the teensy constantly blinks, which is what we expect.
The same thing happens for dma0_isr in case I add the digitalwrite lines.

I don't have adc0_isr and adc1_isr.
The dma channels directly trigger on the ADC hardware event.
Code:
dma0->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0);
Code:
dma2->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1);
 
Last edited:
Well, I'm at my wit's end!
If you post (or send me privately) the full source code I can test it today or tomorrow.
 
SaileNav,
Have you tried a simple test sketch that does not use any advanced settings to make sure you can actually read those ADC pins? When I test I always try to rule out the hardware first.
 
I simplified the sketch to only 4 channels and only one adc (adc1).
And I can't seem to find my signals who are connected to pin 27-30 (which is also called A16-A19, and also ADC1_SE4b-ADC1_SE7b, rather confusing!)
I went through all the pin numbers to find my signals but I get a floating signal, high or low.

For ChannelsCfg
0x40-0x43: signal is floating
0x44-0x4B: signal is high
0x4C-0x58: signal is floating except for 0x52 and 0x55 which are low
0x59 high
0x5A constant at 38000
0x5B high
0x5C noise
0x5D low

In case I set the ADC1_CFG2 register:
Code:
void setup_adc() {
  ADC1_CFG2 &= ~ADC_CFG2_MUXSEL;
  adc->adc1->setResolution(16); // set bits of resolution
  adc->adc1->setReference(ADC_REF_1V2);
  adc->adc1->enableDMA();
  ADC1_SC1A = ChannelsCfg[3];
}

I get the following
0x40-0x49: floating
0x4A-0x4B: low
0x4C-0x5B: floating (except for 0x51 and 0x55 which are low)
0x5C: low
05D: high
 
Last edited:

Try the below code, replace readPin and readPin2 with ADC0 and ADC1 pins your using.
Its one of the examples(synchronizedMeasurements) from the ADC library.
If it does not work you most likely have a hardware problem.

Code:
/* Example for synchonized measurements using both ADC present in Teensy 3.1
*  You can change the number of averages, bits of resolution and also the comparison value or range.
*/


#include <ADC.h>

const int readPin = A9;
const int readPin2 = A3;

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

elapsedMicros time;

void setup() {

    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(readPin, INPUT);
    pinMode(readPin2, INPUT);

    Serial.begin(9600);

    ///// ADC0 ////
    //adc->setReference(ADC_REF_INTERNAL, ADC_0); change all 3.3 to 1.2 if you change the reference

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

    // it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED_16BITS, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
    // see the documentation for more information
    adc->setConversionSpeed(ADC_HIGH_SPEED); // change the conversion speed
    // it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
    adc->setSamplingSpeed(ADC_HIGH_SPEED); // change the sampling speed

    // 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_0)/3.3, 2.0*adc->getMaxValue(ADC_0)/3.3, 0, 1, ADC_0); // ready if value lies out of [1.0,2.0] V

    ////// ADC1 /////
    adc->setAveraging(1, ADC_1); // set number of averages
    adc->setResolution(12, ADC_1); // set bits of resolution
    adc->setConversionSpeed(ADC_HIGH_SPEED, ADC_1); // change the conversion speed
    adc->setSamplingSpeed(ADC_HIGH_SPEED, ADC_1); // change the sampling speed

    // always call the compare functions after changing the resolution!
    //adc->enableCompare(1.0/3.3*adc->getMaxValue(ADC_1), 0, ADC_1); // 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



    // You can also try:
    //adc->startSynchronizedContinuous(readPin, readPin2);
    //adc->startSynchronizedContinuousDifferential(A10, A11, A12, A13);
    // Read the values in the loop() with readSynchronizedContinuous()

    delay(500);
    Serial.println("end setup");
}

int value = 0;
int value2 = 0;

ADC::Sync_result result;

void loop() {

    result = adc->analogSynchronizedRead(readPin, readPin2);

    //result = adc->analogSynchronizedReadDifferential(A10, A11, A12, A13);

    //result = adc->readSynchronizedContinuous();
    // if using 16 bits and single-ended is necessary to typecast to unsigned,
    // otherwise values larger than 3.3/2 will be interpreted as negative
    //result.result_adc0 = (uint16_t)result.result_adc0;
    //result.result_adc1 = (uint16_t)result.result_adc1;

    if( (result.result_adc0 !=ADC_ERROR_VALUE) && (result.result_adc1 !=ADC_ERROR_VALUE) ) {

      // the test results below were obtained commenting out all Serial.print*() and the delay() lines
      //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));

      //Serial.print("Value ADC0: ");
      Serial.print(time, DEC);
      Serial.print(" ");
      Serial.print(result.result_adc0*3.3/adc->getMaxValue(ADC_0), DEC);
      Serial.print(" ");
      Serial.println(result.result_adc1*3.3/adc->getMaxValue(ADC_1), DEC);
    }

    /* fail_flag contains all possible errors,
        They are defined in  ADC_Module.h as

        ADC_ERROR_OTHER
        ADC_ERROR_CALIB
        ADC_ERROR_WRONG_PIN
        ADC_ERROR_ANALOG_READ
        ADC_ERROR_COMPARISON
        ADC_ERROR_ANALOG_DIFF_READ
        ADC_ERROR_CONT
        ADC_ERROR_CONT_DIFF
        ADC_ERROR_WRONG_ADC
        ADC_ERROR_SYNCH

        You can compare the value of the flag with those masks to know what's the error.
    */
    if(adc->adc0->fail_flag) {
        Serial.print("ADC0 error flags: 0x");
        Serial.println(adc->adc0->fail_flag, HEX);
        if(adc->adc0->fail_flag == ADC_ERROR_COMPARISON) {
            adc->adc0->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
            Serial.println("Comparison error in ADC0");
        }
    }
    #if defined(__MK20DX256__)
    if(adc->adc1->fail_flag) {
        Serial.print("ADC1 error flags: 0x");
        Serial.println(adc->adc1->fail_flag, HEX);
        if(adc->adc1->fail_flag == ADC_ERROR_COMPARISON) {
            adc->adc1->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
            Serial.println("Comparison error in ADC1");
        }
    }
    #endif

    digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));


  delay(50);
}

/*
 With a AWG I generated a sine wave of 1 Hz and 2 V amplitude.
 I measure synchronously on pins A0 (ADC0) and A2 (ADC1), sampling at 20 Hz (every 50ms).
 The relative error: mean(value(A0)-value(A2))/mean(value(A0)) is approx 0.02%


*/
 
synchronizedMeasurements example works

Try the below code, replace readPin and readPin2 with ADC0 and ADC1 pins your using.
Its one of the examples(synchronizedMeasurements) from the ADC library.
If it does not work you most likely have a hardware problem.

Hi Donziboy2,
I tried out your code and it works perfectly.
I tested all the pins I want to use and they worked flawlessly.
So I think we can rule out a hardware issue.

synchronized_read.png
This plot is for pins A9 and A17. They are connected to the same signal source.
 
Last edited:
I have been digging in the source code and I have a question about pin A16.
in avr/cores/teensy3/pins_arduino.h i find the following definition for A16.
Code:
const static uint8_t A16 = 27;
In the startReadFast and other read methods the function channel2sc1a is used to convert the A16 value to a sc1a register value.
My question is: How is that possible if there are only 23 values in the channel2sc1a array definition?
Code:
#elif defined(__MK20DX256__)
static const uint8_t channel2sc1a[] = {
	5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
	0, 19, 3, 19+128, 26, 18+128, 23,
	5+192, 5+128, 4+128, 6+128, 7+128, 4+192
// A15  26   E1   ADC1_SE5a  5+64
// A16  27   C9   ADC1_SE5b  5
// A17  28   C8   ADC1_SE4b  4
// A18  29   C10  ADC1_SE6b  6
// A19  30   C11  ADC1_SE7b  7
// A20  31   E0   ADC1_SE4a  4+64
};

Am I missing something?
 
You're mixing things!
That code belongs to the core analog.c, while the ADC library uses a different one!
The analogRead function in analog.c in subtracts from the pin number to "compress" them into a smaller array, that means that you cannot do channel2sc1a[pin]==SC1A.
In the ADC library you can do it, but channel2sc1a then occupies more space.
Be careful and don't mix ADC code with analog.c code, they are completely separate and independent.
 
OK thanks pedvide!
So I assume this definition would be the correct one:

In avr/libraries/ADC/ADC.cpp:
Code:
#if defined(ADC_TEENSY_3_1)
const uint8_t ADC::channel2sc1aADC1[]= { // new version, gives directly the sc1a number. 0x1F=31 deactivates the ADC.
    31, 31, 8, 9, 31, 31, 31, 31, 31, 31, 3, 31, 0, 19, // 0-13, we treat them as A0-A13
    31, 31, 8, 9, 31, 31, 31, 31, 31, 31, // 14-23 (A0-A9)
    31, 31,  // 24,25 are digital only pins
    5+ADC_SC1A_PIN_MUX, 5, 4, 6, 7, 4+ADC_SC1A_PIN_MUX, 31, 31, // 26-33 26=5a, 27=5b, 28=4b, 29=6b, 30=7b, 31=4a, 32,33 are digital only
    3+ADC_SC1A_PIN_DIFF, 31+ADC_SC1A_PIN_DIFF, 0+ADC_SC1A_PIN_DIFF, 19+ADC_SC1A_PIN_DIFF, // 34-37 (A10-A13) A11 isn't connected.
    26, 18, 31, 27, 29, 30 // 38-43: temp. sensor, VREF_OUT, A14 (not connected), bandgap, VREFH, VREFL.
};
 
Yes, that's the one that gives directly the sc1a value, as you see ADC::channel2sc1aADC1[A16]=ADC::channel2sc1aADC1[27]=5, but some space is wasted with 31's that Paul manages to save.
 
ok, so the goal is to be able to write the sc1a register myself.
A16 -> 27 (avr/cores/teensy/pins_arduino.h)
27 -> 5 (avr/libraries/ADC/ADC.cpp)
5 -> 0x45 (enable interrupts, ADC_SC1_AIEN, avr/libraries/ADC/ADC_module.cpp)

I think I should also set ADC_CFG2, because A16 is only reachable via mux b.
Is it ok if I do it this way?
Code:
ADC1_CFG2 &= ~ADC_CFG2_MUXSEL;
 
I don't really now what to do next.

Here is the full source code for the four channel recorder. This works for ADC0 but for ADC1 it records grounded signals.
Code:
#include <string.h>
#include "DMAChannel.h"
#include "ADC.h" 

#define BUF_SIZE 256
#define NO_BUFFERS 50

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

DMAChannel* dma0 = new DMAChannel(false);
DMAChannel* dma1 = new DMAChannel(false);


const uint16_t ChannelsCfg [] =  { 0x44, 0x45, 0x46, 0x47 };
const int ledPin = 13;

DMAMEM static volatile uint16_t __attribute__((aligned(BUF_SIZE+0))) adcbuffer[NO_BUFFERS][BUF_SIZE];
volatile int ibuf;
volatile int obuf;
volatile int d2_active;
volatile int d4_active;
volatile int d6_active;
volatile int d8_active;

void setup() {
  // initialize the digital pin as an output.
  pinMode(ledPin, OUTPUT);

  delay(500); 
  ibuf = 0;
  obuf = 0;

  d2_active = 0;
  d4_active = 0;
  d6_active = 0;
  d8_active = 0;
  
  pinMode(2, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);

  attachInterrupt(2, d2_isr, FALLING);
  attachInterrupt(4, d4_isr, FALLING);
  attachInterrupt(6, d6_isr, FALLING);
  attachInterrupt(8, d8_isr, FALLING);

  // Initialize buffer
  for (int i = 0; i < NO_BUFFERS; ++i){
    for (int j = 0; j < BUF_SIZE; ++j){
      adcbuffer[i][j] = 50000;
    }
  }
   
  setup_adc();
  setup_dma(); 
  

}

void loop() {

  char password[] = "start";
  uint8_t index = 0;
  char c = '0';
  
  Serial.begin(9600); // USB is always 12 Mbit/sec
  delay(100);
  // data acquisition will start with a synchronisation step:
  while(index!=5){
    while(Serial.available() == 0){
      delay(100);// polls whether anything is ready on the read buffer - nothing happens until there's something there
    }
    c = Serial.read();
    if(password[index]==c){
      index++;
    }else{
      index = 0;
    }
    delay(1);
  }
  Serial.println("Ready");

  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(500);                  // wait for a second
  digitalWrite(ledPin, LOW);    // set the LED off
  delay(500); 
  
  Serial.println("Start");

  while(1){
    uint8_t pin = 0;
    if(d2_active) pin=1;
    if(d4_active) pin=2;
    if(d6_active) pin=3;
    if(d8_active) pin=4;

    if(pin>0){

      Serial.println(pin);
      
      obuf=(ibuf+2) % NO_BUFFERS;
      for (int i = 0; i < 100; ++i){
        Serial.write((uint8_t *)adcbuffer[obuf],2*BUF_SIZE); 
        obuf=(obuf+1) % NO_BUFFERS;
        while(obuf==ibuf);
      }

      digitalWrite(ledPin, HIGH);   // set the LED on
      delay(50);                  // wait for a second
      digitalWrite(ledPin, LOW);    // set the LED off

      d2_active = 0;
      d4_active = 0;
      d6_active = 0;
      d8_active = 0;
      
    }
  }

  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(100);                  // wait for a second
  digitalWrite(ledPin, LOW);    // set the LED off
  delay(100);   
}

void setup_dma() {
  dma0->begin(true);              // allocate the DMA channel 
  dma0->TCD->SADDR = &ADC1_RA;    // where to read from
  dma0->TCD->SOFF = 0;            // source increment each transfer
  dma0->TCD->ATTR = 0x101;
  dma0->TCD->NBYTES = 2;     // bytes per transfer
  dma0->TCD->SLAST = 0;
  dma0->TCD->DADDR = &adcbuffer[0][0];// where to write to
  dma0->TCD->DOFF = 2; 
  dma0->TCD->DLASTSGA = -2*BUF_SIZE;
  dma0->TCD->BITER = BUF_SIZE;
  dma0->TCD->CITER = BUF_SIZE;    
  dma0->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1);
  dma0->disableOnCompletion();    // require restart in code
  dma0->interruptAtCompletion();
  dma0->attachInterrupt(dma0_isr);
  
  dma1->begin(true);              // allocate the DMA channel 
  dma1->TCD->SADDR = &ChannelsCfg[0];
  dma1->TCD->SOFF = 2;            // source increment each transfer
  dma1->TCD->ATTR = 0x101;
  dma1->TCD->SLAST = -8;
  dma1->TCD->BITER = 4;
  dma1->TCD->CITER = 4;
  dma1->TCD->DADDR = &ADC1_SC1A;
  dma1->TCD->DLASTSGA = 0;
  dma1->TCD->NBYTES = 2;
  dma1->TCD->DOFF = 0;
  dma1->triggerAtTransfersOf(*dma0);
  dma1->triggerAtCompletionOf(*dma0);

  dma0->enable();
  dma1->enable();
  
} 


void setup_adc() {
  adc->setResolution(16, ADC_1); // set bits of resolution
  adc->setReference(ADC_REF_1V2, ADC_1);
  ADC1_CFG2 &= ~ADC_CFG2_MUXSEL;
  adc->adc1->enableDMA(); //ADC0_SC2 |= ADC_SC2_DMAEN;  // using software trigger, ie writing to ADC0_SC1A
  ADC1_SC1A = ChannelsCfg[3];
  
} 

void d2_isr(void) {
    d2_active = 1;
}

void d4_isr(void) {
    d4_active = 1;
}
void d6_isr(void) {
    d6_active = 1;
}
void d8_isr(void) {
    d8_active = 1;
}

void dma0_isr(void) {
    ibuf=(ibuf+1) % NO_BUFFERS;
    dma0->TCD->DADDR = &adcbuffer[ibuf][0];
    dma0->clearInterrupt();
    dma0->enable();
}

Somebody an idea about what I am doing wrong?
 
Last edited:
I'm testing it, but I really really don't understand what your code is doing.
I've tried to get rid of the python stuff and print the mean value of a pin in the serial port, but I don't even understand how the different channels get in the same buffer?
Please, please, simplify it much much more: forget about python, forget about 4 channels per ADC.
Use just serial, just one channel per ADC.
 
Found the bug!

Good news,
I found the error and it actually relates to something Pedvide mentioned here:
Yes, you're right! I was looking at the ADC0 numbers by mistake.
Now I see that in adc_setup you use adc->adc1->setReference(INTERNAL);
What's INTERNAL? You should be using ADC_REF_3V3, ADC_REF_1V2, or ADC_REF_EXT.
How are you doing the tests? Is ch4 connected to the same as ch0? or to something different?

I changed INTERNAL to ADC_REF_1V2, but that was not a good idea.
I looked in the source code and when I use INTERNAL nothing happens, but when ADC_REF_1V2 is used, things change.
So I tried to comment the line:
Code:
//adc->adc1->setReference(ADC_REF_1V2);
Now things work like they should.

Thanks Pedvide for your comments!
 
I'm testing it, but I really really don't understand what your code is doing.
I've tried to get rid of the python stuff and print the mean value of a pin in the serial port, but I don't even understand how the different channels get in the same buffer?
Please, please, simplify it much much more: forget about python, forget about 4 channels per ADC.
Use just serial, just one channel per ADC.

Do you want me to explain how it works?
 
Status
Not open for further replies.
Back
Top