Double Analog Read Finish Interrupt

Hello

I am using this code to read one analog input with analog finish interrupt.

int numSamples = 0;
long t, t0;
int a0, au0;
void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (0 << ADLAR);  
  
  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect){
  a0 = ADCL | ADCH << 8; // read 10 bit value from AD
  numSamples++;
}

void loop()
{
  if (numSamples >= 1000){
    au0 = a0;
    t = micros() - t0; // calculate elapsed time
    Serial.println(au0);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    delay(500);
    t0 = micros();
    numSamples = 0;
  }
}

The problem is that I am trying to read 2 analog input
I write this code but it doesn't work

int numSamples = 0;
long t, t0;
int a0, a1, au0, au1;
void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  a = 0;
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (0 << ADLAR);

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect)
{
  if (a == 0) {
    a0 = ADCL | ADCH << 8;
    ADMUX |= (1 & 0x07);// reading pin 1
    a = 1;
  }
  else if (a == 1) {
    a1 = ADCL | ADCH << 8;
    ADMUX |= (0 & 0x07);//reading pin 0
    a = 0;
  }
  numSamples++;
}

void loop()
{
  if (numSamples >= 1000)
  {
    au0 = a0;
    au1 = a1;
    t = micros() - t0; // calculate elapsed time
    Serial.println(au0);
    Serial.println(au1);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    delay(500);
    t0 = micros();
    numSamples = 0;
  }
}

Can someone help me?
Thank You

Try these modifications from the previous sketch for 1 analog input(A0) conversion to 2 analog inputs conversions(A0 and A1 alternatively)(not tested though):

Todo : You will have to adjust the frequency accordingly.

/*****************************************************************/
/*************     Measure alternatively A0 and A1      **********/
/*****************************************************************/

volatile uint16_t A0numSamples;
volatile uint16_t A1numSamples;

long t, t0, t1;
int a0, au0;
int a1, au1;

volatile boolean Flag;

void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (1 << MUX0);    // set A0 analog input pin ****
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX &= ~(1 << ADLAR);  // Conversion Result = ADCL | ADCH << 8

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupt when a measurement is completed
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect) {
  if (Flag == false) {
    a0 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX0) | (1 << MUX1); // Set A1 analog input pin instead of A0
    Flag = true;          // Next measure will be A1
    A0numSamples++;
  }
  else {  // If (Flag == true)
    a1 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX1) | (1 << MUX0); // Set A0 analog input pin instead of A1
    Flag = false;          // Next measure will be A0
    A1numSamples++;
  }
  
}

void loop()
{
  if (A0numSamples >= 1000) {  // Print every 1000 samples of A0
    au0 = a0;
    t = micros() - t0; // calculate elapsed time
    Serial.println(au0);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t0 = micros();
    A0numSamples = 0;
  }
  if (A1numSamples >= 1000) {  // Print every 1000 samples of A1
    au1 = a1;
    t = micros() - t1; // calculate elapsed time
    Serial.println(au1);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t1 = micros();
    A1numSamples = 0;
  }

}
ADMUX |= (0 & 0x07);//reading pin 0

This line is wrong. When you AND 7 with 0 you get 0. When you OR 0 with whatever was in ADMUX you just get the same thing back. So this isn't changing ADMUX at all.

ard_newbie:
Try these modifications from the previous sketch for 1 analog input(A0) conversion to 2 analog inputs conversions(A0 and A1 alternatively)(not tested though):

Todo : You will have to adjust the frequency accordingly.

/*****************************************************************/

/*************    Measure alternatively A0 and A1      **********/
/*****************************************************************/

volatile uint16_t A0numSamples;
volatile uint16_t A1numSamples;

long t, t0, t1;
int a0, au0;
int a1, au1;

volatile boolean Flag;

void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;            // clear ADCSRA register
  ADCSRB = 0;            // clear ADCSRB register
  ADMUX |= (1 << MUX0);    // set A0 analog input pin ****
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX &= ~(1 << ADLAR);  // Conversion Result = ADCL | ADCH << 8

// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                    // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupt when a measurement is completed
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect) {
  if (Flag == false) {
    a0 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX0) | (1 << MUX1); // Set A1 analog input pin instead of A0
    Flag = true;          // Next measure will be A1
    A0numSamples++;
  }
  else {  // If (Flag == true)
    a1 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX1) | (1 << MUX0); // Set A0 analog input pin instead of A1
    Flag = false;          // Next measure will be A0
    A1numSamples++;
  }
 
}

void loop()
{
  if (A0numSamples >= 1000) {  // Print every 1000 samples of A0
    au0 = a0;
    t = micros() - t0; // calculate elapsed time
    Serial.println(au0);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t0 = micros();
    A0numSamples = 0;
  }
  if (A1numSamples >= 1000) {  // Print every 1000 samples of A1
    au1 = a1;
    t = micros() - t1; // calculate elapsed time
    Serial.println(au1);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t1 = micros();
    A1numSamples = 0;
  }

}

ard_newbie:
Try these modifications from the previous sketch for 1 analog input(A0) conversion to 2 analog inputs conversions(A0 and A1 alternatively)(not tested though):

Todo : You will have to adjust the frequency accordingly.

/*****************************************************************/

/*************    Measure alternatively A0 and A1      **********/
/*****************************************************************/

volatile uint16_t A0numSamples;
volatile uint16_t A1numSamples;

long t, t0, t1;
int a0, au0;
int a1, au1;

volatile boolean Flag;

void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;            // clear ADCSRA register
  ADCSRB = 0;            // clear ADCSRB register
  ADMUX |= (1 << MUX0);    // set A0 analog input pin ****
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX &= ~(1 << ADLAR);  // Conversion Result = ADCL | ADCH << 8

// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                    // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupt when a measurement is completed
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect) {
  if (Flag == false) {
    a0 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX0) | (1 << MUX1); // Set A1 analog input pin instead of A0
    Flag = true;          // Next measure will be A1
    A0numSamples++;
  }
  else {  // If (Flag == true)
    a1 = ADCL | ADCH << 8; // read 10 bit value from AD
    ADMUX = ADMUX & ~(1 << MUX1) | (1 << MUX0); // Set A0 analog input pin instead of A1
    Flag = false;          // Next measure will be A0
    A1numSamples++;
  }
 
}

void loop()
{
  if (A0numSamples >= 1000) {  // Print every 1000 samples of A0
    au0 = a0;
    t = micros() - t0; // calculate elapsed time
    Serial.println(au0);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t0 = micros();
    A0numSamples = 0;
  }
  if (A1numSamples >= 1000) {  // Print every 1000 samples of A1
    au1 = a1;
    t = micros() - t1; // calculate elapsed time
    Serial.println(au1);
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    Serial.println();
    //delay(500);
    t1 = micros();
    A1numSamples = 0;
  }

}

Thanks you ard_newbie
I test the code but i doesn't work

I find this code

volatile uint8_t Au0, Au1;
volatile uint8_t Aut0, Aut1;
volatile uint8_t ADCvalue;

volatile uint16_t A0numSamples;
volatile uint16_t A1numSamples;

long t, t0, t1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(250000);
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX = 0;                // use ADC0
  ADMUX |= (1 << REFS0);    // use AVcc as the reference
  ADMUX |= (1 << ADLAR);    // Right adjust for 8 bit resolution
  //ADMUX |= (0 << ADLAR);  // Right adjust for 10 bit resolution

  ADCSRA |= (1 << ADPS2);   // 16 prescale for 16Mhz
  ADCSRA |= (1 << ADATE);   // Set ADC Auto Trigger Enable

  ADCSRB = 0;               // 0 for free running mode
  ADCSRA |= (1 << ADEN);    // Enable the ADC
  ADCSRA |= (1 << ADIE);    // Enable Interrupts
  ADCSRA |= (1 << ADSC);    // Start the ADC conversion
}

ISR(ADC_vect)
{
  uint8_t tmp;            // temp register for storage of misc data
  tmp = ADMUX;            // read the value of ADMUX register
  tmp &= 0x0F;            // AND the first 4 bits (value of ADC pin being used)
  if (tmp == 0){
    Au0 = ADCH;   // Right adjust for 8 bit resolution
    //Au0=ADCL | ADCH << 8;   // Right adjust for 10 bit resolution
    ADMUX++;            // add 1 to ADMUX to go to the next sensor
    A0numSamples++;
  }
  else if (tmp == 1){
    Au1 = ADCH;   // Right adjust for 8 bit resolution
    //Au1=ADCL | ADCH << 8;    // Right adjust for 10 bit resolution
    ADMUX &= 0xF8;
    A1numSamples++;
  }
}



void loop() {
  if (A0numSamples >= 1000) {  // Print every 1000 samples of A0
    Aut0 = Au0;
    t = micros() - t0; // calculate elapsed time
    Serial.print(Aut0);
    Serial.print("    Sampling 0 frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    t0 = micros();
    A0numSamples = 0;
  }
  if (A1numSamples >= 1000) {  // Print every 1000 samples of A1
    Aut1 = Au1;
    t = micros() - t1; // calculate elapsed time
    Serial.print(Aut1);
    Serial.print("    Sampling 1 frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    t1 = micros();
    A1numSamples = 0;
  }
}

It Works ok but now i have two problems
1.It doesn't work for 10 bit resolution
2.I have connect on pin to 5v and the other to GND
So the outputs must be 255 and zero
but the output is:
28 Sampling 1 frequency: 38.44 KHz
249 Sampling 0 frequency: 38.47 KHz
if i test one by one analog it works well
With analogRead i know that we do 2 analogRead and we keep the second value to fix the
problem but i don't know what i must do in this way

I changed ADMUX setting because it seems that ADMUX has an abnormal behaviour (see datasheet), although I didn't see this one clearly documented.

/*****************************************************************/
/*************     Measure alternatively A0 and A1      **********/
/*****************************************************************/

volatile uint16_t A0numSamples;
volatile uint16_t A1numSamples;

volatile long t, t0, t1;
volatile uint16_t a0, au0;
volatile uint16_t a1, au1;

volatile boolean Flag;

void setup()
{
  Serial.begin(250000);
  ADCSRA = 0;             // clear ADCSRA register 
  ADCSRB = 0;             // clear ADCSRB register 
  ADMUX = 0;              // clear ADMUX register
  ADMUX |= (1 << MUX0);    // set A0 analog input pin 
  ADMUX |= (1 << REFS0);  // set reference voltage  AVCC with external capacitor at AREF pin !!
  ADMUX &= ~(1 << ADLAR);  // Conversion Result = ADCL | ADCH << 8

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz  *****
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupt when a measurement is completed  
  ADCSRA |= (1 << ADEN);  // enable ADC 
  ADCSRA |= (1 << ADSC);  // start ADC measurements 
}

ISR(ADC_vect) {
  if (Flag == false) {
    a0 = ADCL;
    a0|= ADCH << 8; // read 10 bit value from A0
    //ADMUX = (ADMUX & ~(1 << MUX0)) | (1 << MUX1); // Set A1 analog input pin instead of A0
    // There is a weird bahaviour of ADMUX  , see datasheet !!
    
    ADMUX++; 
    Flag = true;          // Next measure will be A1
    A0numSamples++;
  }
  else {  // If (Flag == true)
    a1 = ADCL;
    a1|= ADCH << 8; // read 10 bit value from A1
    //ADMUX = (ADMUX & ~(1 << MUX1)) | (1 << MUX0); // Set A0 analog input pin instead of A1
    //ADCSRA |= (1 << ADSC);  // start ADC measurements
    // There is a weird bahaviour of ADMUX , see datasheet !!
    
    ADMUX &= 0xF8;
    Flag = false;          // Next measure will be A0
    A1numSamples++;
  }
  
}

void loop()
{
  if (A0numSamples >= 1000) {  // Print every 1000 samples of A0
    au0 = a0;
    t = micros() - t0; // calculate elapsed time
   
    Serial.print(au0);
    Serial.print("  Sampling frequency A0: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    
    t0 = micros();
    A0numSamples = 0;
  }
  if (A1numSamples >= 1000) {  // Print every 1000 samples of A1
    au1 = a1;
    t = micros() - t1; // calculate elapsed time
    
    Serial.print(au1);
    Serial.print("  Sampling frequency A1: ");
    Serial.print((float)1000000 / t);
    Serial.println(" KHz");
    
    t1 = micros();
    A1numSamples = 0;
  }

}

Thanks :smiley:

Now it works but the problem with values is still the same

it read

1000 Sampling frequency A1: 38.45 KHz
113 Sampling frequency A0: 38.44 KHz

and the A1 is 5v and A0 Gnd

Normally when you're in free running mode like that you would read each pin twice and throw away the first result. See the datasheet for why.

You have an int volatile variable set by the ISR but read unsafely in loop(). Use a critical section
to read any multi-byte variables that may change under your feet:

int read_A0numSamples()
{
  noInterrupts() ; // enter critical section
  int value = A0numSamples ;
  interrupts() ;  // exit critical section
  return value ;
}

void loop()
{
  if (read_A0numSamples() >= 1000) {  // Print every 1000 samples of A0
  ...