ADC interrupt

Hello everyone,

I am trying to trigger the adc measurement with a fixed sample rate, so I am using the timer 2 to generate the interrupt to start the adc measurement.
It all seems to work fine, the adc gets started, the adc interrupt gets triggered but for some reason the result is always read as a 0.
Testing the input with a normal analogRead returns reasonable values.

Right now I have trippechecked the datasheet but I can not find the mistake. I am now sitting the second day at this problem and just do not understand what is wrong.

#include <Arduino.h>

volatile uint8_t _val[5];
volatile uint8_t _curVal = 0;

volatile uint8_t _sampleNow = 0;

volatile uint8_t _selectedDetector; 

void sampleData();

ISR(ADC_vect)
{
  _val[_curVal] = ADCH;
  _curVal++;
  if (_curVal == 5)
    _curVal = 0;
}

ISR(TIMER2_COMPA_vect)          //New Measurement
{
  sampleData();
}

ISR(TIMER2_COMPB_vect)          //Sample & Hold already happend
{                               //Deactivate to reduce power
  if (_selectedDetector == 1)
    //PORTD &= ~ (1<<PD3);        //Detector 1 Disable
    ;
  else
  {
    TIMSK2 &= ~ (1<<OCIE2B);    //Disable Comp B Interrupt
    //PORTC &= ~ (1<<PC0);        //Detector 2 Disable
    //PORTB &= ~ (1<<PB1);        //IR LED Disable  
  }
}

void setupADC()
{
  if (_selectedDetector == 1)
    ADMUX =  bit(REFS0) | bit(ADLAR) | bit(MUX2) | bit(MUX1);             //Detector 1 = ADC Chanel 6, Left Adjusted, AVcc as Ref
  else
    ADMUX = bit(REFS0) | bit(ADLAR) | bit(MUX2) | bit(MUX1) | bit(MUX0);  //Detector 2 = ADC Chanel 7, Left Adjusted, AVcc as Ref

  ADCSRA = bit(ADEN) | bit(ADIE) | bit(ADPS1) | bit(ADPS0);               //Interrupt & ADC Enable & Prescaler 8
}

void setupTimer2()
{
    cli();                    //Disable Interrupts globally
    TCCR2B = 0;               //Set controlregister to 0
    TCCR2A = 0;               
    if (_selectedDetector)
    {
      OCR2A = 125;                      //2000 Hz samplerate => f_clk / pre / f_sample = counts = 8MHz / 32 / 2kHz = 125
      OCR2B = 4;                        //16ADC clocks => 16* f_clk / pre /  (f_clk / pre_adc) = 16* pre_adc / pre = 16 * 8 / 32 = 4
      TCCR2A = 1 << WGM21;              //No output, ctc 
      TCCR2B = 1 << CS21 | 1 << CS20;   //Perscaler 32 -> 8MHz / 32 = 250kHz
    }   
    else
    {
      OCR2A = 156;                      //400 Hz samplerate => f_clk / pre / f_sample = counts = 8MHz / 128 / 400Hz = 156 
      OCR2B = 1;                        //16ADC clocks => 16* f_clk / pre /  (f_clk / pre_adc) = 16* pre_adc / pre = 16 * 8 / 128 = 1
      TCCR2A = 1 << WGM21;              //No output, ctc 
      TCCR2B = 1 << CS22 | 1 << CS20;   //Perscaler 128 -> 8MHz / 64 = 62,5kHz     
    }
    
    sei();
  
}

void sampleData()
{
  if (bit_is_set(ADCSRA,ADSC))    //If converstation is running
    return;                       //Exit


  if (_selectedDetector)
  {
    PORTD = PORTD | 1<<PD3;       //Detector 1 Enable
    ADCSRA |= bit(ADSC);          //ADC start conversion
  }
  else if (_sampleNow)            //Measure every second interrupt
  {
    _sampleNow = 0;
    PORTC = PORTC | 1<<PC0;       //Detector 2 Enable
    PORTB = PORTB | 1<<PB1;       //IR LED Enable
    ADCSRA |= bit(ADSC);          //ADC start conversion
    TIMSK2 |= 1 << OCIE2B;        //Enable comp B interrupt
  }  
  else
  {
    _sampleNow = 1;
  }
  
}

void startSampleing(void)
{
  if (_selectedDetector)
  {
    TIMSK2 = 1<<OCIE2A | 1<<OCIE2B;    //Enable Comp A & Comp B Interrupt      
  }
  else
  {
    TIMSK2 = 1<<OCIE2A;               //Enable Comp A Interrupt
  }
}

void setup() 
{
  /* Port Setup */
  pinMode(9,OUTPUT);              //IR LED 

  pinMode(3,OUTPUT);              //Detector 1 Enable
  pinMode(A0,OUTPUT);             //Detector 2 Enable 
  pinMode(A6,INPUT);              //Detector 1 Input
  pinMode(A7,INPUT);              //Detector 2 Input

  pinMode(A2,OUTPUT);             //CS Poti
  pinMode(A1,OUTPUT);             //Shutdown Poti

  pinMode(2,OUTPUT);              //Writecontrol EEPROM
  pinMode(A3,OUTPUT);             //Select EEPROM

  digitalWrite(A1,HIGH);

  /* ADC Setup */
  _selectedDetector = 0;
  setupADC();

  /* Timer 2 Setup */
  setupTimer2();

  startSampleing();

  Serial.begin(115200);
  
}

void loop() 
{
  while (_curVal > 0)
  {
    Serial.println(_val[_curVal]);
    _curVal--;
  }
}

However testing it without the timer interrupt works fine:

#define IRLED 9
#define DETECTOR2 A7
#define DET2EN A0
#define POTISHTDWN A1
#define POTIPIN A2


volatile int test;
volatile unsigned int val;

ISR(ADC_vect)
{
  test = 1;
  val = ADCH;
}

void setup() {
  // put your setup code here, to run once:
    Serial.begin(115200); 

    pinMode(POTISHTDWN,OUTPUT);
    pinMode(POTIPIN,OUTPUT);
    pinMode(DET2EN, OUTPUT);
    pinMode(IRLED,OUTPUT);
    pinMode(DETECTOR2,INPUT);

    digitalWrite(POTISHTDWN,HIGH);  //Digital Potentiometer enable  

    ADMUX = bit(REFS0) | bit(ADLAR) | bit(MUX2) | bit(MUX1) | bit(MUX0);  //Detector 2 = ADC Chanel 7, Left Adjusted, AVcc as Ref
    ADCSRA = bit(ADEN) | bit(ADIE) | bit(ADPS1) | bit(ADPS0);               //Interrupt & ADC Enable & Prescaler 8
}

void loop() 
{ 
    digitalWrite(DET2EN,HIGH);      //Detektor 2 enable
    digitalWrite(POTISHTDWN,HIGH);  //Digital Potentiometer
    digitalWrite(IRLED,HIGH);       //IR LED enable
    
    
    ADCSRA |= bit(ADSC);

    while (test == 0)
    {
      
    }

    test = 0;

    digitalWrite(POTISHTDWN,LOW);  
    digitalWrite(DET2EN,LOW);      
    digitalWrite(IRLED,LOW);   

    Serial.println(val);    
}

Has anyone an idea why this happens?

I don't know why your code doesn't work, but it'll probably be easier to just select the timer event as the ADC trigger, instead of starting a conversion in software in the timer ISR. You can then use the ADC ready interrupt to get the result of the conversion.

ADC triggers are explained in §23.9.4 (p.220) of the datasheet

Pieter

Sadly it is not possible with the timer 2. Only 0 and 1. But those are not enabled in the sleep modes. In the end the µc should be in the IDLE mode while the measurement is performed to safe power.

Edit: I just realized I was wrong. In IDLE the timers 0 and 1 do run. So I guess I will give that a try and then see. However the behavior is still quite strange to me.