ADC trigger from counter #0 setup problem

Hello,

I am trying to set up my Arduino ADC to trigger from my 0 counter. I’ve attached both initialization functions and my ISR. Measuring a test pin I get a 3kHz sampling rate regardless of what I set OCR0A to my scaling factor to. At about every 50ms the ISR just stops for about 5ms and the starts again. Any input is appreciated.

Thank you,
Jordan

void AD_Init(void)
{
  //ADMUX
  //7 bit   6 bit  5 bit  4 bit  3 bit  2 bit  1 bit  0 bit  
  //REFS1   REFS0  ADLAR  NA     MUX3   MUX2   MUX1   MUX0  

  // clear ADLAR in ADMUX (0x7C) to right-adjust the result
  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)
  ADMUX &= B11011111;
  
  // Set REFS1..0 in ADMUX (0x7C) to change reference voltage to 5v
  ADMUX |= B01000000;
  
  // Clear MUX3..0 in ADMUX (0x7C) in preparation for setting the analog input
  ADMUX &= B11110000;
  
  // Set MUX3..0 in ADMUX (0x7C) to read from AD0
  ADMUX |= B00000000;
  
  //ADCSRA
  //7 Bit  6 Bit  5 Bit  4 Bit  3 Bit  2 Bit  1 Bit  0 Bit
  //ADEN   ADSC   ADATE  ADIF   ADIE   ADPS2  ADPS1  ADPS0 
  
  // Set ADEN in ADCSRA (0x7A) to enable the ADC
  ADCSRA |= B10101100; // enable ADC, enable auto-triggering, enable interrupt on conversion done, 
                        //and select prescaling factor 128 (125 kHz clk)
                        
  DIDR0  = bit(ADC0D);            // disable digital input buffer for analog input pin 0

  
  // Set ADATE in ADCSRA (0x7A) enable auto-triggering.
  //ADCSRA |= B00000000; //
  ADCSRA |= B00100011; //timer Counter0 Compare Match A
  //ADCSRA |= B00100101; //timer Counter0 Compare Match B

  
  //7 Bit  6 Bit  5 Bit  4 Bit  3 Bit  2 Bit  1 Bit  0 Bit
  //ACME   NA     NA     NA     NA     ADTS2  ADTS1  ADTS0
  
  // Clear ADTS2..0 in ADCSRB (0x7B) to set trigger mode to Timer/Counter0 Compare Match A
  ADCSRB &= B11111011;

  // Set the Prescaler to 128 (16000KHz/64 = 250KHz)
  ADCSRA |= B00000110;
  
  // Set ADIE in ADCSRA (0x7A) to enable the ADC interrupt.
  ADCSRA |= B00001000;
    
  // Start the first ADC
  read_Flag = 0;
  // Set ADSC in ADCSRA (0x7A) to start the ADC conversion
  ADCSRA |=B01000000;
  
}


void Timer_Init(void)
{
  

  TCCR0A = 0;
  TCCR0B = 0;
  //TIMSK0 = 0; 
  //TIMSK0
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //-       -       -       -       -      OCIE0B OCIE0A TOIE0
  TIMSK0 &= B00000000;  // disable Arduino timer interrupt

  //TCCR0A
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //COM0A1  COM0A0  COM0B1  COM0B0  –      –      WGM01  WGM00
  TCCR0A |= B00000010;   // select clear-timer-on-compare mode
  
  //TCCR0B
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //FOC0A   FOC0B   –       –       WGM02  CS02   CS01   CS00 
  TCCR0B |= B0000011;    // select CK/64 prescaling factor (4 us)

  OCR0A = 3; // set period to 3 * 4 us = 12 us (83.33 kHz)
  
}

ISR(ADC_vect)
{ 
  read_Flag = 1; // Data set ready
  analog_Val = ADCL | (ADCH << 8) ; // Must read low first
}

Please use code tags.

Read this before posting a programming question

analog_Val = ADCL | (ADCH << ; // Must read low first

…is clearly a syntax error. By posting something that is not your actual complete code you are wasting your time and the time of anyone who tries to help you.

Sorry about that and it’s not my intent to waste anyone’s time. The 8) turned into “cool smiley” and when I added the code bracket it was removed.

analog_Val = ADCL | (ADCH << 8);
sketch_dec21c.ino: In function 'void AD_Init()':
sketch_dec21c:50: error: 'read_Flag' was not declared in this scope
sketch_dec21c.ino: In function 'void __vector_21()':
sketch_dec21c:85: error: 'read_Flag' was not declared in this scope
sketch_dec21c:86: error: 'analog_Val' was not declared in this scope

Now, can you post code that compiles?

http://snippets-r-us.com/

Here is my code in its entirety. The test signal is on the led (output #13). Sorry, being the “newbie” I made some assumptions about posting code.

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

Multilateration 
Time Difference of Arrival (TDOA) 

/*************************************************************/
#define Data_Size 256
#define sample_Rate 60 //set by timer setup function
#define ledPin 13   // LED connected to digital pin 13

//calibration
#define AVG_Chnl_0 915
#define AVG_Chnl_1 899
#define AVG_Chnl_2 895

// High when a value is ready to be read
volatile int read_Flag;

// High when a value is ready to be computed
volatile int event_Flag;
volatile int event_Timer;

// Value to store analog result
volatile unsigned int analog_Val;

volatile unsigned int event_Size;
volatile unsigned int event_X;
volatile unsigned int event_Y;
volatile unsigned int event_TOA;
volatile unsigned int event_Theta;



//fifo
int Fifo_0[Data_Size];
int Fifo_1[Data_Size];
int Fifo_2[Data_Size];
volatile double Fifo_Channel;
volatile int Fifo_Head;


void AD_Init(void)
{
  //ADMUX
  //7 bit   6 bit  5 bit  4 bit  3 bit  2 bit  1 bit  0 bit  
  //REFS1   REFS0  ADLAR  NA     MUX3   MUX2   MUX1   MUX0  

  // clear ADLAR in ADMUX (0x7C) to right-adjust the result
  ADMUX &= B11011111;
  
  // Set REFS1..0 in ADMUX (0x7C) to change reference voltage to 5v
  ADMUX |= B01000000;
  
  // Clear MUX3..0 in ADMUX (0x7C) in preparation for setting the analog input
  ADMUX &= B11110000;
  
  // Set MUX3..0 in ADMUX (0x7C) to read from AD0
  ADMUX |= B00000000;
  
  //ADCSRA
  //7 Bit  6 Bit  5 Bit  4 Bit  3 Bit  2 Bit  1 Bit  0 Bit
  //ADEN   ADSC   ADATE  ADIF   ADIE   ADPS2  ADPS1  ADPS0 
  
  // Set ADEN in ADCSRA (0x7A) to enable the ADC
  ADCSRA |= B10101100; // enable ADC, enable auto-triggering, enable interrupt on conversion done, 
                        //and select prescaling factor 128 (125 kHz clk)
                        
  DIDR0  = bit(ADC0D);            // disable digital input buffer for analog input pin 0

  
  // Set ADATE in ADCSRA (0x7A) enable auto-triggering.
  ADCSRA |= B00100011; //timer Counter0 Compare Match A
   
  //7 Bit  6 Bit  5 Bit  4 Bit  3 Bit  2 Bit  1 Bit  0 Bit
  //ACME   NA     NA     NA     NA     ADTS2  ADTS1  ADTS0
  
  // Clear ADTS2..0 in ADCSRB (0x7B) to set trigger mode to Timer/Counter0 Compare Match A
  ADCSRB &= B11111011;

  // Set the Prescaler to 128 (16000KHz/64 = 250KHz)
  ADCSRA |= B00000110;
  
  // Set ADIE in ADCSRA (0x7A) to enable the ADC interrupt.
  ADCSRA |= B00001000;
    
  // Start the first ADC
  read_Flag = 0;
  
  // Set ADSC in ADCSRA (0x7A) to start the ADC conversion
  ADCSRA |=B01000000;
  
}


void Timer_Init(void)
{
  

  TCCR0A = 0;
  TCCR0B = 0;
  //TIMSK0 = 0; 
  //TIMSK0
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //-       -       -       -       -      OCIE0B OCIE0A TOIE0
  TIMSK0 &= B00000000;  // disable Arduino timer interrupt

  //TCCR0A
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //COM0A1  COM0A0  COM0B1  COM0B0  –      –      WGM01  WGM00
  TCCR0A |= B00000010;   // select clear-timer-on-compare mode
  
  //TCCR0B
  //7 Bit   6 Bit   5 Bit   4 Bit   3 Bit  2 Bit  1 Bit  0 Bit
  //FOC0A   FOC0B   –       –       WGM02  CS02   CS01   CS00 
  TCCR0B |= B0000011;    // select CK/64 prescaling factor (4 us)
  
  //OCR0A = 57; // set period to 57 * 4 us = 228 us (4.386 kHz)
  //OCR0A = 8; // set period to 8 * 4 us = 32 us (31.25 kHz)
  OCR0A = 3; // set period to 3 * 4 us = 12 us (83.33 kHz)
  
  /*
  Velocity in rubber (approx.):	                60m/sec.
  Distance between pickups:	                0.13m
  Sample Hz for 128 Samples:	                59076Hz
  Sample Hz for 64 Samples:	                29538Hz

  Samples at 12uS (3 heads):	                27777Hz
  Samples at that distance at this rate:	0.00216m/sample 60.18 samples over 0.13m	
  */
  
  
   
}


// Interrupt service routine for the ADC completion
ISR(ADC_vect)
{ 
  read_Flag = 1; // Data set ready
  analog_Val = ADCL | (ADCH << 8);  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)
   //ADCSRA |= B01000000; // Set ADSC in ADCSRA (0x7A) to start another ADC conversion if not triggered
}


void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 
  AD_Init();
  Timer_Init();
  sei();// Enable global interrupts
 
  event_Flag = 0;
  event_Timer = 0;
  Fifo_Channel = 0;
  Fifo_Head = 0;
  event_TOA = 0;
  event_Theta = 0;
 }

void loop()
{
  // Check to see if the value has been updated
  if (read_Flag == 1)
  {
    ADMUX &= B11110000; //
    //__________________________________________________
    //send data to approriate location
    
    
    switch ((char)(Fifo_Channel + 1) % 3)
    {
      case 0:
      // test sampling frequency - High is sample rate (33% duty cycle)
      digitalWrite(ledPin, HIGH);

      Fifo_0[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_0 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000001;
      break;
      
      case 1:
      digitalWrite(ledPin, LOW);
      Fifo_1[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_1 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000010;
      break;
      
      case 2:
      digitalWrite(ledPin, LOW);
      Fifo_2[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_2 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000000;
      Fifo_Head ++; //increment the head on last rung
      
      break;
      
      default:// error reset
       digitalWrite(ledPin, LOW);
       Fifo_Head = 0;
       Fifo_Channel = 0;
       event_TOA = 0;
       event_Theta = 0;
    }  
    }
 
}

The read order is not guaranteed…

analog_Val = ADCL | (ADCH << 8);  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)

The correct way to read the value…

analog_Val = ADC;
ISR(ADC_vect)
{ 
  read_Flag = 1; // Data set ready
  analog_Val = ADCL | (ADCH << 8);  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)
   //ADCSRA |= B01000000; // Set ADSC in ADCSRA (0x7A) to start another ADC conversion if not triggered
}

read_Flag and analog_Val are the only two variables that should be declared volatile.

This line of code serves no useful purpose; remove it…

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 
  AD_Init();
  Timer_Init();
  sei();// <<<<< REMOVE THIS LINE
...
  read_Flag = 1; // Data set ready
  analog_Val = ADCL | (ADCH << 8);  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)

A bit optimistic about the data being ready. How about:

  analog_Val = ADC;
  read_Flag = 1; // Data set ready (now)

I think you need to make up your mind what the prescaler is:

  // Set ADEN in ADCSRA (0x7A) to enable the ADC
  ADCSRA |= B10101100; // enable ADC, enable auto-triggering, enable interrupt on conversion done, 
                        //and select prescaling factor 128 (125 kHz clk)
...
  // Set ADATE in ADCSRA (0x7A) enable auto-triggering.
  ADCSRA |= B00100011; //timer Counter0 Compare Match A
...
  // Set the Prescaler to 128 (16000KHz/64 = 250KHz)
  ADCSRA |= B00000110;

Better written as:

 // Set ADEN in ADCSRA (0x7A) to enable the ADC
  ADCSRA |= B10101000; // enable ADC, enable auto-triggering, enable interrupt on conversion done, 
                        
  // Set the Prescaler to 128 (16000KHz/64 = 250KHz)
  ADCSRA |= B00000110;

Thank you. I'll hook it to a scope tomorrow in the lab to see if this makes a difference, but this shouldn't affect my timer registers (I wouldn't think anyway).

read_Flag is never cleared so the if-condition is always true after the first interrupt...

void loop()
{
  // Check to see if the value has been updated
  if (read_Flag == 1)
  {

The original posted code doesn't seem to flash pin 13 at all. I'm trying to find out why (apart from the issue you mentioned with read_Flag which I spotted).

double Fifo_Channel;
...
    switch ((char)(Fifo_Channel + 1) % 3)
...
    case 1:

A double is not a good choice for comparing to exact numbers.

I can’t get the timer-based ADC reading to work at all, but if you want the fastest frequency you may as well do what you had commented-out and start a new conversion when the old one ends.

Doing that I got a sample rate of 9.6 kHz as you would expect, as one conversion takes 104 µS.

 1 / (1/16e6 * 128 * 13) = 9615.4

I fixed up various things in the code, there were so many I forgot exactly what I did. :slight_smile:

/**************************************************************
 * 
 * Multilateration 
 * Time Difference of Arrival (TDOA) 
 * 
/*************************************************************/
#define Data_Size 256
#define sample_Rate 60 //set by timer setup function
#define ledPin 13   // LED connected to digital pin 13

//calibration
#define AVG_Chnl_0 915
#define AVG_Chnl_1 899
#define AVG_Chnl_2 895

// High when a value is ready to be read
volatile bool read_Flag;

// High when a value is ready to be computed
int event_Flag;
int event_Timer;

// Value to store analog result
volatile unsigned int analog_Val;

unsigned int event_Size;
unsigned int event_X;
unsigned int event_Y;
unsigned int event_TOA;
unsigned int event_Theta;

//fifo
int Fifo_0[Data_Size];
int Fifo_1[Data_Size];
int Fifo_2[Data_Size];
unsigned int Fifo_Channel;
int Fifo_Head;

void AD_Init(void)
{
  DIDR0  = bit (ADC0D);            // disable digital input buffer for analog input pin 0

  // Set REFS1..0 in ADMUX  to change reference voltage to 5v
  // (and) Clear MUX3..0 in ADMUX (0x7C) in preparation for setting the analog input
  ADMUX = bit (REFS0);

  ADCSRB = 0;

  // Set ADEN in ADCSRA to enable the ADC and select prescaling factor 128 (125 kHz clk).
  // Enable interrupts on completion, clear pending interrupt
  ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF) | bit (ADPS0) | bit (ADPS1) | bit (ADPS2);

  // Set ADSC in ADCSRA  to start the ADC conversion
  ADCSRA |= bit (ADSC);
}

// Interrupt service routine for the ADC completion
ISR(ADC_vect)
{ 
  analog_Val = ADC;  // ADCL will contain lower 8 bits, ADCH upper 2 (in last two bits)
  read_Flag = true; // Data set ready
  ADCSRA |= bit (ADSC); // Set ADSC in ADCSRA to start another ADC conversion if not triggered
}

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  pinMode (8, OUTPUT);  // Debug output

  AD_Init ();

  event_Flag = 0;
  event_Timer = 0;
  Fifo_Channel = 0;
  Fifo_Head = 0;
  event_TOA = 0;
  event_Theta = 0;
}

void loop()
{

  // Check to see if the value has been updated
  if (read_Flag)
    {
    PINB = bit (0); // toggle D8
      
    ADMUX &= B11110000; //
    //__________________________________________________
    //send data to approriate location

    switch (Fifo_Channel & 3)
    {
    case 0:
      // test sampling frequency - High is sample rate (33% duty cycle)
      digitalWrite(ledPin, HIGH);

      Fifo_0[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_0 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000001;
      Fifo_Channel++;
      break;

    case 1:
      digitalWrite(ledPin, LOW);
      Fifo_1[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_1 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000010;
      Fifo_Channel++;
      break;

    case 2:
      digitalWrite(ledPin, LOW);
      Fifo_2[Fifo_Head] = analog_Val;
      if (analog_Val < (int)(AVG_Chnl_2 * 0.985))
      {
        event_Flag = 1;
        event_TOA = Fifo_Channel;
      }
      ADMUX |= B00000000;
      Fifo_Head ++; //increment the head on last rung
      if (Fifo_Head >= Data_Size)
        Fifo_Head = 0;
      Fifo_Channel++;
      break;

    default:// error reset
      digitalWrite(ledPin, LOW);
      Fifo_Head = 0;
      Fifo_Channel = 0;
      event_TOA = 0;
      event_Theta = 0;
    }  
    
  read_Flag = false;
  }  // end of conversion done

}  // end of loop

What would you choose beyond the double? I had concern that when the number rolled over I would have a discontinuity in my data and the time I took it at (big number = less chance of discontinuity). As for the clearing of the read Flag, I do clear it in a subset of later code (my TDOA math was over the text limit). After I calculated where my event came from I cleared it. I can send you the TDOA part, but I’m sensitive about my math… And you guys are really critical. Smiling.

A double is 4 bytes and a long is 4 bytes. So whilst it can be "big" in the sense that it can store a large number (like 3.4e22) it doesn't actually hold 22 digits of precision.

(BTW a double on Arduino is the same as a float: 4 bytes).