ADC in ISR - using NRM

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

I've got a current system that works well that involves performing an ADC operation within an ICP ISR. I'd like to use NRM for this conversion. Is it simply a matter of (re-)enabling interrupts before entering sleep mode? Are there any other potential side effects of enabling interrupts inside of an ISR? Do I have to turn interrupts back off after waking back up? Will the return from the ISR restore interrupts to what they were before the ICP interrupt (I'd have to assume they were enabled or else the ICP interrupt wouldn't have happened)?

 

ISR(TIMER1_CAPT_vect) {
    // ...
    set_sleep_mode(SLEEP_MODE_ADC);
    NONATOMIC_BLOCK(NONATOMIC_RESTORESTATE) {
        sleep_enable();
        sleep_cpu();
        sleep_disable();
    }
    unsigned int adcval = ADC;
    // ...
}
EMPTY_INTERRUPT(ADC_vect);

 

Last Edited: Sat. Apr 30, 2016 - 05:18 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Enabling interrupts inside ISR will allow nested interrupts form all sources (with lower priorities too).

If you have any other interrupts enabled except TIMER1_CAPT_vect and ADC_vect, capture interrupt can be waked up before conversion complete so it is better to read result in ADC ISR.

You do not need to restore the state (disable interrupts) if no further operations to be performed atomically. So you can just enable interrupts.

 

I used TIMER0 OVF interrupt instead of TIMER1 capture because limitation of my board.

 

void main() {
    DDRE = 0xE0;

    ADCSRA = (1<<ADEN) | (1<<ADIE) | (5 << ADPS0); // clk/32
    ADMUX  = (1<<REFS0);

    TCCR0A = 0;
    TCCR0B = 2<<CS00; // clk/8
    TIMSK0 = 1<<TOIE0;

    sei();

    for(;;) {
    	PINE = (1<<7); // toggle PORTE.7 in IDLE loop
    }
}

uint16_t drain;

ISR(ADC_vect)
{
    PORTE |= (1<<6);  // ADC ISR marker
    drain = ADCW;
    PORTE &= ~(1<<6);
}

ISR(TIMER0_OVF_vect)
{
    PORTE |= (1<<5);  // TIMER ISR marker
    set_sleep_mode(SLEEP_MODE_ADC);
    sei();
    sleep_enable();
    sleep_cpu();
    sleep_disable();
    PORTE &= ~(1<<5);
}

wbr, ReAl