buserror / simavr

simavr is a lean, mean and hackable AVR simulator for linux & OSX
GNU General Public License v3.0
1.54k stars 366 forks source link

ADC conversion with noise canceller does not work #166

Open KickerTom opened 8 years ago

KickerTom commented 8 years ago

Some AVR chips (e.g. ATMega328) has ADC noise canceller, which does ADC conversion when the MCU is sleeping to reduce noise. To start ADC conversion in this way, the ADC should be enabled in single conversion mode, ADC interrupt enabled, and MCU must be put to ADC sleep (SLEEP_MODE_ADC). The conversion is not started by ADSC bit, but by entering the sleep mode. This does not seem to be supported in the simulation. I was not able to start ADC conversion without setting the ADSC bit explicitly.

Premik commented 7 years ago

Just hit the same issue on Atiny44. MCU gets to the sleep mode but never wakes up. The ADC_IRQ_OUT_TRIGGER don't get called so seems the ADC was not started. I guess this is not implemented.

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <avr/sleep.h>
EMPTY_INTERRUPT(ADC_vect);  

void init(){    
    cbi(DDRA, PORTA2 );//PA2 Input      
    sbi(DIDR0, ADC2D); /* Disable digital inputs for ADC pins */
    ADMUX = ADC_MUX_TEMP| ADC_REF_EXT;// Select MUTEX to ADC2, and external reference (2.2V)
    ADCSRB = 0;//No Bipolar mode, free running, not left alignment, no analog comparator    
    ADCSRA = (1 << ADEN) |(1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); //64 Prescaler division = (125khz @ 8MHZ clock)
    cbi(PRR0, PRADC);//No power reduction
}
void read() {   
    set_sleep_mode(SLEEP_MODE_ADC);//ADC Sleep mode
    sbi(ADCSRA, ADIE);
    cli();
    sleep_enable();
    //sleep_bod_disable();
    sei();
    sleep_cpu();
    sleep_cpu(); //2x to discard the first result
    while (ADCSRA & _BV(ADSC))
        ; //Wait for the conv. to finish
    sleep_disable();
}