We have almost gone through main modes of AVR timers. It is impossible to review them all in more detail as there are lots of unique uses and cases. Anyway we will get back to them in future, as lots of routines are usually based on timer operations.
We haven’t touched Timer/Counter2, which is another 8-bit timer of Atmega328. This is very similar to Timer0 with all pretty same features, including CTC, fast PWM and correct phase PWM modes. If you can run these modes in Timer0 then this will be easy doing on Timer2. The only difference is the naming of registers. So let’s leave this behind and get to something new and untouched. As I mentioned before, each timer has something unique, making them useful on special occasions. So this one isn’t an exception. It has a particular asynchronous timing mode which can be set to count events from an external clock source or be clocked with 32.768kHz crystal.
Asynchronous is less predictable
When operating in the asynchronous timer mode, there are some dangers to getting wrong results. As datasheet says counter, compare, and control registers must be preserved when switching between a synchronous mode and asynchronous to avoid corruption. Also, there is an additional Asynchronous Status Register (ASSR) used, which allows selecting asynchronous modes and holds busy status bits of the register, indicating successful register update. Atmega328 doesn’t have dedicated pins for this – it uses TOSC1 and TOSC2 pins. So this leaves us without main crystal oscillator or another external clock source. So we can have two options – clock microcontroller with 32kHz crystal (or another external clock on TOSC1 pin) or use internal oscillator.
Clocking timer with a 32kHz crystal
Probably you know what 32.768kHz crystals are mainly used for? In most cases, it is used to clock Real-Time Clocks (RTC). Such frequency is chosen because it may be scaled down to 1Hz by dividing it by two fifteen times. Of course, there are some historical issues and prices. Making lower frequency crystals, souls lead to higher rates and dimensions. So why bother changing things? These already do a great job and are available on every corner. This frequency is convenient for our 8-bit timer as it may be scaled down to 1Hz with prescaller 128. Dividing 32768 by 128 gives 256 – one full counter with overflow interrupt. So we are going to use this. Let’s make a simple 1Hz LED flasher.
In our program microcontroller is clocked with internal 1MHz clock source while Timer2 is clocked by 32.768kHz crystal.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//Prepare LED pin
void PortInit(void)
{
//Initlally LED OFF
PORTD&=~(1<<PD0);
//PD0 as output
DDRD|=(1<<PD0);
}
//Timer2 init acording datasheet
void RTCInit(void)
{
//Disable timer2 interrupts
TIMSK2 = 0;
//Enable asynchronous mode
ASSR = (1<<AS2);
//set initial counter value
TCNT2=0;
//set prescaller 128
TCCR2B |= (1<<CS22)|(1<<CS00);
//wait for registers update
while (ASSR & ((1<<TCN2UB)|(1<<TCR2BUB)));
//clear interrupt flags
TIFR2 = (1<<TOV2);
//enable TOV2 interrupt
TIMSK2 = (1<<TOIE2);
}
//Overflow ISR
ISR(TIMER2_OVF_vect)
{
//Toggle pin PD0 every second
PIND=(1<<PD0);
asm volatile("nop"::);
//_delay_us(10);
}
int main (void)
{
SMCR|=(1<<SM1)|(1<<SM0);
//Initialize port
PortInit();
//Initialise the timer2
RTCInit();
//Enable global interrupts
sei();
while(1)
{
SMCR|=(1<<SE);
asm volatile("sleep"::);
SMCR&=~(1<<SE);
//Do nothing
}
}
This program is almost good enough. But if we need only to count time, why run core at 1MHz. Running MCU at high speeds consume more energy. For such a simple application, it is better to clock entire microcontroller from the same 32.768kHz crystal. We only have to delete one line from the above code:
ASSR = (1<<AS2);
This will make the timer be clocked from the system clock. Our problem now is to make a system to be clocked from the 32.768kHz crystal. It can be done by selecting the proper fuses. Just be careful with setting AVR to such low speed because not all programmers (especially DIY) will support low baud rates for SPI. In all cases, the SPI programmer has to run four times slower than the MCU clock. I find this web application useful when I need to set AVR fuse bits.
If you need to make really efficient RTC of your Atmega328, then you need to use power management. One of options is to put AVR int-to Power-Safe sleep mode, where Timer2 can run in asynchronous mode. We will get to sleep modes other time. Next time think twice if you need a separate RTC chip.
You can’t run Timer2 and the CPU from the same crystal. The CPU has to be at least 4x the Timer frequency. However, if using a 32.768kHz crystal as your system crystal, the CPU power consumption is very low anyway so just use a regular timer in conjunction with idle power saving mode.
(p.s. your captcha is set way too sensitive!)
If you set 32.768kHz as system clock – then actually timer will become synchronous. As I mentioned clearing line ASSR = (1<<AS2); will make it possible.
I’m not sure I understand what you mean by “I/O ports are disabled while CPU is sleeping. LEDs won’t light up while sleep”. In sleep, the I/Os stay exactly where you leave them, so a lit LED will stay lit. Clearly, to change an IO while sleeping you’ll need to wake up for a short time.
I made wrong conclusions according to some sources. Removed this part. Thanks.
Why 18 pF and 8 pF, are experimentaly discovered values? I can’t find something find in datastheets.
CAP value should be 18pF. Missed that. Thanks.
And accuracy? Min in Hour or min in day?
If I understand correctly you want to know accuracy of such RTC? It depends on crystal accuracy. Crystals are characterized by frequency tolerance parameter in ppm (parts per million). Lets say 32.768kHz crystal is characterized by -50ppm then it may miss 50 seconds every million seconds. If year has 31536000 seconds then clock might miss 1577 seconds per year or ~26min/year. This means ~4 seconds per day.
@Admin: I found cyrstal /-10ppm, with load capacitance=12,5pF. What’s mean? Can I use 2x18pF as described in schematic? Thanks for sharing.
Correct code:
//wait for registers update
while (ASSR & ((1<<TCN2UB)|(1<<TCR2BUB)));
Thank you AAA.
The loop has to wait for bits to be cleared by hardware.
Code has been fixed.
you help me too much , too many thanks. I developed a project using a atmega328p with 32768Hz xtal for time, and only put to work correcty after read details of your project.
Great code, been struggling for a while until i found this page. Awesome! Thank You!
The way you toggle the LED is incorrect, it looks like you’re modifying the PIND register when you should be modifying the PORTD register.
error-> TCCR2B |= (1<<CS22)|(1< TCCR2B |= (1<<CS22)|(1<<CS20);