ATMega2560 Timer Compare Triggering ADC

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

I did find related topics to this but they used double compare points.

My task is to trigger the ADC via a compare point. I already had it working via timer overflow but now it's time to up the resolution.

 

ADMUX = adcBufferAt->channel;
ADCSRB = bit (ADTS1) | bit (ADTS0); // trigger of timer 1 compareA
ADCSRA = bit (ADEN) | bit(ADATE) | bit (ADIE) | bit(ADPS2); // enable, auto-trigger interrupt, prescaler = 16

 

OCR1A = 15000; // 16MHz/15000 = 1067Hz
TCCR1B = bit (CS10); // start Timer 1, no prescaler
TIMSK1 = bit (OCIE1A); // interrupt on match
TCCR1B = bit (WGM12); // clear on match

 

According to the documentation the ADC triggers on compare interrupt (not just the flag), so it makes some sense that the interrupt enable flag has to be set.

Executing with OCIE1A=1 results in the main loop() not entered unless I have an empty handler to clear the interrupt.

 

ISR (TIMER1_COMPA_vect) {

 
}

Not ideal, but it could be wrong anyhow as the ADC still isn't being triggered.

 

Anything glaringly obvious?

This topic has a solution.
Last Edited: Thu. Jul 23, 2020 - 08:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you looked at the analog comparator?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I apologize first. I don't use Arduino. Therefore it does not understand the Arduino language.

Your mistake:
1) ADC start by TIMER1 is only comparison B and overflow.
2) If you want the time every 15000 cycles, you have to set it to 14999.

3) It is not necessary to execute the TIMER1 interrupt if the only purpose is to start the ADC.

 

It was simulated with Atmel Studio that I use.
An ADC conversion end interrupt is generated every 15000 cycles.

 

#include <avr/io.h>
#include <avr/interrupt.h>

int main(void){
    // Init ADC
    ADMUX = 0;
    ADCSRB = _BV(ADTS2) | _BV(ADTS0); // trigger of timer1 compareB
    ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // enable, auto-trigger interrupt, prescaler = 16

    // Init TIMER1
    OCR1B = 15000 - 1; // ADC trigger on TOP
    OCR1A = 15000 - 1; // TOP:16MHz/15000 = 1067Hz
    TCCR1B = _BV(WGM12) | _BV(CS10); // start Timer 1, no prescaler, MODE4

    sei();
    while (1);
}

ISR(ADC_vect){
    TIFR1 = _BV(OCF1B); // clear flag
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice response thank you. I'm just checking the datasheet to see how I missed it only being CompareB.

I see you have set the same value for CompareA, is that necessary?

 

Update - groan, CompareA for Timer0. Ok!

Last Edited: Thu. Jul 23, 2020 - 07:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As written in the comment.
It is OCR1A that sets the count top in MODE4. It cannot be omitted.
If the trigger source of the ADC is an overflow, just set ICR1 in MODE8.

 

 

Please use Atmel Studio's simulator and debugger.

It will be a powerful tool in understanding how the chip works.

It doesn't exist in the Arduino IDE.