Gyro’clock Firmware 2

Okay so today we will talk about the real time clock (RTC) module. The job of this module is obviously to keep track of time, for real. So what’ the big deal, use the Arduino Time library right? Sure you can use it but you will drift away from real time pretty fast. This is because the Time library uses the internal RC oscillator (If you got a standalone 8 MHz Arduino like I do) for clock pulses. RC oscillators aren’t that accurate. I have seen drifts of 15 min/day using the internal RC oscillators, which is pretty bad. Also if we are using the microcontroller to count the ticks, we have to keep in mind that it also has to do other stuff like reading the accelerometer data from the MMA8452. So these things add small delays which ultimately adds up to big ones. The best solution to this is to have a dedicated RTC module.

Did you know that ATmega328p has a built-in RTC module? Awesome!! This means we don’t have to buy one and that saves money. The only thing we have to buy is a 32.768 kHz crystal. You’ll see why we picked that particular number for this in a bit. The RTC module uses the asynchronous timer2 counter of the ATmega328p. Asynchronous simply means that it doesn’t use the system clock to run its timer. The timer basically gets clicked externally by our crystal. So first we have to configure the Timer2 to run in asynchronous mode:

 //disable Timer2 interrupts
 TIMSK2 = 0;
 //enable asynchronous mode
 ASSR = (1<<AS2);

We disable Timer2 interrupts while we update the timer since we don’t want it to trip at the wrong time. Next the datasheet (page 155) tells us that when switching the timer mode from synchronous to asynchronous or vice versa the timer counter value (TCNT2 register) might get corrupted. To ensure that it isn’t corrupted we initialize the counter value to 0:

//set initial counter value
 TCNT2 = 0;

Next comes the selection of the clock pre-scalar. We have a crystal that oscillates at 32.768 kHz. So a pulse from the crystal comes every 30.518 us and increments our 8-bit timer counter by 1. At this rate our counter will overflow at every 7.8125 ms. But what if we can get this counter to overflow at exactly 1 second instead? If we pre-scaled the clock pulses from the crystal by 128, now we get a clock pulse at a rate of 32.768 kHz / 128 = 256 Hz. And guess what? Our 8-bit counter (256 values) will overflow in exactly 1 second. We can only select certain pre-scalar values (8, 32, 64, 128, 256 or 1024) and that’s why we chose a 32.768 kHz crystal.

By experimentation I found a small caveat. When using a stand alone Arduino with the internal 8 MHz crystal, all the time related things seem to run twice as slow. So instead of pre-scalling the clock by 128 I had to use a pre-scallar of 64 to get the 1 second timer overflow.  And we set the timer2 clock pre-scallar like this:

 //set pre-scaller to 64
 TCCR2B |= (1<<CS22);
 //wait for registers to update
 while(ASSR & ((1<<TCN2UB)|(1<<TCR2BUB)));
 //clear existing interrupt flags if any
 TIFR2 = (1<<TOV2);
 //enable overflow interrupt
 TIMSK2 = (1<<TOIE2);
 //enable global interrupt
 sei();

That’s it! our RTC is now set. Now we will get a Timer2 overflow interrupt every second. All that is left to do is to implement the Timer2 interrupt function to keep track of the seconds.

ISR(TIMER2_OVF_vect)
{
 seconds++;
 if(seconds == 60)
 {
  minutes++;
  seconds = 0;
  if(minutes == 60)
  {
   hours++;
   minutes = 0;
   if(hours == 24)
   {
    hours = 0;
   }
  }
 }
}

The interrupt function is self explanatory. Now to a very important advantage of using the RTC module instead of the system clock; Since we only need to know when the Timer2 counter overflows, we can sleep in between! In Idle mode we nap for a whole second, wake up, update the counter, and go back to sleep again. This activity extends our battery life significantly compared to using the system clock to keep track of time.

ATmega328p implements several sleep modes, but with the RTC module running we can only implement the power-save sleep mode. And we can configure the power-save sleep mode like this:

//shutdown ADC
 PRR |= (1<<PRADC);
 //shutdown analog comparator
 ACSR |= (1<<ACD);
 //turn off watchdog timer
 cli();
 MCUSR &= ~(1<<WDRF);
 WDTCSR |= (1<<WDCE) | (1<<WDE);
 WDTCSR = 0x00;
 sei();
 //configure sleep mode to power-save
 SMCR |= (1<<SM1)|(1<<SM0)|(1<<SE);

At the same time, we also turn off a few things that we really don’t need to save some more power like the ADC, analog comparator and the watchdog timer. And to actually fall asleep we have to call from our main loop,

//sleep now
sleep_mode();

And with that it is time for me to fall a sleep for real. That covers the RTC module implementation of the Gyro’clock. Next time we’ll talk about how to display the time into thin air. Thanks for staying awake with me.

One response to “Gyro’clock Firmware 2

  1. Pingback: Gyro’Clock Firmware 3 | Light Emitting Dude

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s