How to use a quartz clock for Real Time Clock in AVR microcontroller

Here is a write up for my DIY on making RTC using quartz crystal. Sometimes it is useful to have a clock in the system counting the time in seconds, and even with high accuracy. Often, special RTC (Real Time Clock) microcircuits such as PCF8583 are used for these purposes. That's just this additional body, and it sometimes costs like the MK itself, although you can do without it. Moreover, many MCs have a built-in RTC unit. In AVR it's really not, but there is an asynchronous timer, serving as a semi-finished product for making watches.
First of all, we need a quartz clock at 32768Hertz.

Why is quartz just 32768Hz and why is it called a sentry? Yes, everything is very simple - 32768 is a degree of deuces. Two in the fifteenth degree. Therefore, a fifteen-bit counter, ticking at a frequency of 32768 Hz, will overflow once a second. This makes it possible to build a clock on an ordinary logical rassypooh without any problems. And in the microcontroller AVR, you can organize a clock with seconds without using the brain, on the peripheral reflexes.
Asynchronous timer mode
Remember how timers work? The clock frequency from the main clock generator (RC external or internal, external quartz or external generator) goes to the prescalers, and from the output of the prescalers already clicks the values of the TCNT register. Either the input signal comes from the counting input Tn and also clicks the TCNT register

The structure of the same Timer / Counter2 is slightly different from the others - it does not have a countable input, but it is possible to use its own clock generator.

To do this, the quartz resonator is hung on the TOSC2 and TOSC1 terminals. Low-frequency, usually this is a watch clock at 32768Hz. On the Pinboard it is mounted to the right of the controller and connected by jumpers. And the processor clock speed should be higher at least four times. We have a clock from an internal generator of 8MHz, so this condition does not soar at all.

Sentry quartz hangs just on the conclusions. Without capacitors and any problems.

And do not calculate the number of cycles of the main quartz, and if it does not, then bother with the floating frequency of the built-in RC generator. Sentry quartz has much more compact dimensions than regular quartz, and costs less.

Also important is the fact that an asynchronous timer can tick itself, from hourly quartz, because it does not need a processor clock speed, which means clocking the controller's core (the most densely, that it has) can be disabled by driving the processor into hibernation, significantly reducing power consumption and waking up only over the timer overflow (1-2 times per second) to record new time readings.
Configuring
To enable it, you just need to set the AS2 bit of ASSR register - and everything, the timer works in asynchronous mode. But there is one feature that cost me a lot of guns in my time. The fact is that when you work from your quartz, all the internal registers of the timer begin to synchronize on your own quartz. And it's slow and the main program can change the value already entered much more quickly than it is processed by the timer.
For example, preset you the value of TCNT2, the timer at its 32kHz threshing it still did not have time to chew, but your algorithm already ran and again there something that was written down - as a result, TCNT2 will probably get garbage. To prevent this from happening, the record is buffered. Those. this you think you wrote down the data in TCNT2, but in fact they fall into the temporary register and in the counting will only get through three clock cycles of the slow generator.
The OCR2 comparison registers and the TCCR2 configuration register are also buffered
How do you know if the data has already been added to the timer or hanging in the intermediate cells? Yes, it's very simple - with the flags in the ASSR register. These bits are TCN2UB, OCR2UB and TCR2UB - each is responsible for its own register. When we, for example, write a value in TCNT2, TCNUB becomes 1, and as soon as our number from the intermediate register has passed to the real register register TCNT2 and the beginning is ticking, this flag is automatically discarded.
Thus, in asynchronous mode, when writing to the registers TCNT2, OCR2 and TCCR2, you first need to check the flags TCN2UB, OCR2UB and TCR2UB and record only if they are zero. Otherwise, the result may be unpredictable.
Yes, another important point - when switching between synchronous and asynchronous mode, the value in the counting register TCNT can be beaten. So for reliability we switch this way:
- We prohibit interrupts from this timer
- Switch to the desired mode (synchronous or asynchronous)
- Re-configure the timer as we need. Those. set the preset TCNT2 if necessary, re-configure TCCR2
- If we switch to asynchronous mode, then wait until all the flags TCN2UB, OCR2UB and TCR2UB are reset. Those. settings are applied and ready to go.
- Reset the timer / counter interrupt flags. Because at all these perturbations they can be randomly established
- Allow interrupts from this timer
Failure to comply with this sequence leads to unpredictable and difficult to detect glitches.
Sleep modes and asynchronous timer
Because Asynchronous timer is often used in different saving modes, then there is one feature that decomposes an entire field of rakes.
The bottom line is that a timer that runs on slow quartz does not keep up with the main processor, and in that dofig dependencies from the periphery are the same interrupts, for example. And when the percentage is asleep, then these dependencies can not be realized, as a result, there are glitches like non-working interrupts or damaged values in the registers. So the logic of working with an asynchronous timer and a sleeping mode should be built in such a way that between an awakening and a dormancy in hibernation, an asynchronous timer has time to work out a few of its measures and has completed all of its operations.
Examples:
The controller uses the power-saving and kernel-off mode, but wakes up by interrupts from the asynchronous timer. Here we must take into account the fact that if we change the values of the registers TCNT2, OCR2 and TCCR2, then the hibernation should be done ONLY after the flags TCN2UB, OCR2UB and TCR2UB fall. Otherwise, such a mess will happen - the asynchronous timer has not yet managed to take data from the intermediate registers (it's slow, hundreds of times slower than the kernel), and the kernel has already been chopped off. And it's okay to have a new configuration that does not apply, it's nonsense.
Worse, the operation of the comparison block is blocked for the time of TCNT or OCR register modifications, which means that if the kernel falls asleep earlier, then the comparison block will not start - there will be no one to turn it on. And we will have an interruption in comparison. What is more than the fact that we will slip through the event and will lose them until the next awakening from hibernation.
And if the controller is interrupted by comparison? Then he will fall asleep completely. Shit!
Here, catch such a bug later.
So before leaving for power saving modes it is necessary to give the asynchronous timer to chew the entered values (if they were entered) and wait for the flags to be reset.
Another trick with asynchronous mode and power saving is that the interrupt subsystem when it leaves hibernation starts at 1 clock cycle slow generator. So even if we did not change anything, then we can not fall back into hibernation - we will not wake up, tk. interrupts will not have time to start.
Worse, the operation of the comparison block is blocked for the time of TCNT or OCR register modifications, which means that if the kernel falls asleep earlier, then the comparison block will not start - there will be no one to turn it on. And we will have an interruption in comparison. What is more than the fact that we will slip through the event and will lose them until the next awakening from hibernation.
And if the controller is interrupted by comparison? Then he will fall asleep completely. Shit!
Here, catch such a bug later.
So before leaving for power saving modes it is necessary to give the asynchronous timer to chew the entered values (if they were entered) and wait for the flags to be reset.
Another trick with asynchronous mode and power saving is that the interrupt subsystem when it leaves hibernation starts at 1 clock cycle slow generator. So even if we did not change anything, then we can not fall back into hibernation - we will not wake up, tk. interrupts will not have time to start.
So the way out of hibernation and falling asleep by interrupting an asynchronous timer should be like this:
Woke up
...
Something did the right thing
...
They fell asleep
And the duration of the operation between Woke up and Fallen Down SHOULD NOT BE LESS THAN than one tick of an asynchronous timer. Otherwise, suspended animation will be eternal. You can delay the delay, but you can do as the datasheet suggests:Woke up
Something did the right thing
For fun, they recorded something in any of the buffered registers. For example, TCNT had 1, and we recorded 1 again. Nothing has changed, but there was a recording, the TCN2UB flag has risen which will last three cycles of the slow generator.
Wait until the flag falls
We fell asleep.
Also it is not recommended to leave the hibernation immediately to read the TCNT values - it can be considered lazh. It is better to wait for one tick of an asynchronous timer. Or make a joke with a record in the register and wait until the flag goes down, as it was written above.
Well, the last, but important, moment - after power on, or out of deep sleep, with the disconnection of not only the core, but in general the entire periphery, it is strongly recommended to use a slow generator not earlier than 1 second (not a millisecond, but a whole second!) . Otherwise, the generator can still be unstable and there will be more porridge and garbage in the registers.


This post has received a 0.32 % upvote from @booster thanks to: @techlife.
For more information, click here!!!!
Send minimum 0.100 SBD to bid for votes.
Before sending a transfer to @minnowhelper, verify that your publication meets these conditions (http://www.minnowhelper.com/conditions.php). After the transfer is made, no claims will be received.
The Minnowhelper team is still looking for investors (Minimum 10 SP), if you are interested in this, read the conditions of how to invest click here!!!
ROI Calculator for Investors click here!!!