Monday, December 2, 2013

Power Save with Atmega16A and Atmega8-PU

In my very first beginning of my electronic project and study (autodidact) was
so enthusiast with my Atmega8-PU (the -PU means than could run with 16Mhz crystal).
Playing with timer0/1/2 was very fun. And there was a time that i came to
power-save-mode, interesting part began.

In the power-save-mode there are several ways to wake up the chip (Atmega8):
1. External Interrupts (INT0/INT1)
2. TWI Address Match (I2C peripheral)
3. Timer2 (which has to be run in Async Mode)

I choose to use the Timer2 to trigger the wake-up. There is a cost to play with, since
i have set the fuses wrongly. The fuses were set to run in low frequency crystal, 32Khz.
And right after the setting applied, the chip is no longer be able to be programmed.

So how i can achieve to use the 32Khz crystal as my input in TOSC1 and TOSC2?
The datasheet shows that it is possible to run the 32KHz crystal at TOSC1 and
TOSC2 pins with workaround adding 2 caps of 22pF.

The timer2 prescaler set to /128 so a second period (1Hz) could be achieved, with
only set the TCNT2 = 0 (the timer2 counter) and the TIMSK |= (1 << TOEI2)
(the timer2 overflow interrupt). And it works pretty well.

OCR2 = (1 / desiredHertz) / (( N * 1 / Frequence_osc ) -1 )

desiredHertz = 1Hz
N (prescaler) = 128
Frequence_osc = 32.768Hz
Then, (1 / 1) / (( 128 * 1 / 32768) - 1) = 255. TIMSK is set to TOEI2, timer2 overflow.
Since timer2 is 8bit timer than the maximum count is 255 which is exact to our calculation

Snippet code:
#define F_CPU   1000000UL


ISR ( TIMER2_OVF_vect )
    // Wake up and enter timer2 overflow interrupt
    PORTB ^= (1 << PB1);

    // Enable INT0, set the PD2 to input
    DDRD &= ~(1 << PD2);

    // Enable puullup
    PORTD |= (1 << PD2);

    // Set the PB1 as output
    DDRB |= (1 << PB1);

    // Set the timer2 to asynchronous mode
    ASSR |= (1 << AS2);

    // Shutdown ADC
    // To save more power
    ACSR |= (1 << ACD);
    ADCSRA &= ~(1 << ADEN) ;

    // Sleep enable
    MCUCR |= (1 << SE );

    // Set to power-save mode
    MCUCR |= (0 << SM2 ) | ( 1 << SM1 ) | (1 << SM0 );

    // Set the INT0 to wakeup at any edge of signal,
    // whether rising or falling edge
    MCUCR |= (0 << ISC01) | (0 << ISC00); //Any Edge

    // Enable the INTO
    GICR |= (1 << INT0);

    // 1Hz
    // Prescaler set to 128, as the crystal input is 32.768KHz
    TCCR2 |= (1 << CS22 ) | (0 << CS21 ) | (1 << CS20);

    // Disable all timer interrupt
    // if is not disabled and interrupt is triggered the CPU
    // could be hung. Since we prematurely enter the power-save mode
    // without setting the proper timer2 interrupt to wake-up the
    // CPU at 1Hz period
    TIMSK = 0;
    TCNT2 = 0;

    // Enable global interrupt, which the INT0

    // Enable the timer interrupt
    // Set to Timer2 overflow
    TIMSK |= (1 << TOIE2 );

    // Make sure the asynchronous mode is not busy
    // setup and ready
    while ( ASSR & (1 << TCR2UB ) ){ /* Loop if Async is busy */}

    // We are ready to enter the sleep of power-save mode
    // When the CPU is wake up the process will continue at this point

        // Make sure the ASSR or the asynchronous mode is not busy
        while ( ASSR & (1 << TCR2UB ) ){/* Loop if Async is busy */}

        // We are ready to enter the sleep of power-save mode
        // When the CPU is wake up the process will continue 
        // at this point

The next level, i measured the amperage, around ~0.20mA during power-save mode,
while the datasheet says should be around 15uA. Well it is time to take a peek
to the datasheet. You really have to get yourself used to read datasheet ^^.
The circuit was arranged with 1MHz of internal oscillator, 32KHz crystal at TOSC1/2
paired with 2 caps of 22pF and 5Vcc. The ADC, BOD, Watchdog. are disabled
at the fuses setting, use engbedded fuse calculator.

I have review a lot about the atmega8 then why i am saying that use atmega16/32 instead
of atmega8? Well my focus the power consumption and atmega16A, the datasheet
shows Icc ~11.5uA during power-save mode and i got 11uA from my measurement.
When the atmega16 to use 3V, the datasheet shows ~7uA.

I personally prefer to use atmega8535A/16A/32A in my future projects.
Though the size of Atmega16A is ~4 times larger than atmega8 but the trade-off
is fair enough. I get significant power save device therefore battery enabled device at 3Vcc.

No comments: