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.

Gyro’Clock Firmware 1

Today I want to talk about the Gyro’clock firmware. It has evolved quite a lot since I started this project. It can be broken down to three sections or modules:

  • Trigger point detection module
  • Real time clock module
  • Clock display module

Trigger point detection module

The most trickiest (hence the most intriguing) part to implement is the trigger point detection module. So what does the trigger point module has to do? To display the time at the same position in each rotation of the Gyro’clock, the microcontroller needs to know when the Gyro’clock gets to that point. The trigger point detection module (let’s call this TPD module) basically figures out when the Gyro’clock gets to the same position in the spin cycle and tell the microcontroller to display the image, Now! Btw if what I am talking about here makes no sense to you then you may start here.

We have an object that is tied to a string at one end and spun around in circles. How on Earth do we know where it is at any given point in time? Well, on Earth there is something called gravity, and the most amazing thing about it is that it is everywhere. It always points in the same direction: down. So if there is someway we can detect which way gravity is pointing then we can figure out which way we are pointing right? Let’s see what can we use here.. gravity is a force….force makes things accelerate… an accelerometer measures acceleration! That’s it! We are going to use an accelerometer to figure out which way gravity is pointing.

Imagine that we are strapped on to a Gyro’clock and our accelerometer is pointing away from the string that is tied to one end. And we are gonna be spun around in a giant circle (we are about to go on a wild ride). We start with our accelerometer axis pointing straight down at Earth, and it reads 1g. We start to rock back and forth and suddenly we are moving around in a big giant circle, and our accelerometer readings start to fluctuate between 3g and 8g and back to around 3g again. If we plot the accelerometer readings it would look something like this:

Accelerometer readings as the Gyro'clock is spinning.

Accelerometer readings when the Gyro’clock is spinning. Accelerometer axis pointing away from the center of the spin circle.

The accelerometer readings look like a sine curve, except at the top where it gets clipped by the maximum 8g range of the accelerometer. And the period of this sine wave is equal to the period of rotation! Let’s take a closer look at our accelerometer readings to understand what’s going on here. When we are moving around in our big circle our speed is not constant. That’s because when we are moving from the bottom of the circle to the top we are fighting against gravity, and it slows us down as we go up. When we are coming down gravity is on our side and helps us gain speed. So we move fastest when we are at the bottom of the circle and slowest when we are at the top. How is this reflected in our accelerometer readings? But before that we need to answer, what makes us go around in a circle? This force is called centripetal force, and it makes things go around in circles. It points towards the center of the circle exactly opposite to our accelerometer axis.

Okay so if the centripetal acceleration is pointing in the opposite direction from our accelerometer axis, then why isn’t our accelerometer readings negative?? Good question! Well, that’s because we are on board the Gyro’clock and we see the centripetal force in a different way; it is called the centrifugal force. Centrifugal force is an apparent force that is only seen by a rotating object. And since we are moving around in a circle our centrifugal force is equal in magnitude to the centripetal force, but opposite in direction. Centrifugal force (and acceleration) is proportional to the square of the velocity. So the faster we go the more we feel the centrifugal acceleration. Remember last time when you were at a theme park going on that ride that goes around in circles and you felt like you were being pushed to the edge of your seat pulling you away from that circle? Now that is centrifugal force in action! The following figure should make all this clear:

The centrifugal acceleration experienced by the Gyro'clock is equal in magnitude but opposite in direction to the centripetal acceleration

The centrifugal acceleration experienced by the Gyro’clock is equal in magnitude but opposite in direction to the centripetal acceleration.

Okay so how do we figure out our trigger position from the accelerometer readings? Since we are only interested in the change in acceleration, we can go ahead an delete the constant part by adding a high pass filter. The MMA8452Q accelerometer we are using has a built-in high pass filter, perfect! After the filter is applied the data looks like this:

High pass filtered accelerometer data. Smooooth curves created by the discharging of the high pass filter capacitor

High pass filtered accelerometer data. Smooooth curves created by the discharging of the high pass filter capacitor

Wow that looks nothing like a sine curve. What happened? This is because the output is getting clipped by the limited accelerometer range before it gets filtered (and I think I was spinning this one a bit harder). When the output gets clipped we see a smooooth drop in the plot created by the discharging capacitor. That is nice because it is very predictable and uniform, and not plagued by noise like the rest of the parts.

So my trigger point detection is very simple:

Trigger point detection flow chart

Trigger point detection flow chart

okay let me explain, first we read the data from the accel and check if it is above 0.4g. If so then we enable checking for the zero crossing point (checkEnable). There is a de-bounce counter to eliminate false triggers, and I found out that a value of 3 works quite well. When the de-bounce counter is greater than 3 and we read our first negative value, we have arrived at out trigger point. With this method the trigger point is at halfway between the bottom of the circle and top of the circle when we are on the way up.  Since we want the display to appear near the top we add a 35ms delay.

Now you might say, hang on, the delay should depend on how fast we are moving right? Yes you would be quite right, but speed correction is a quite taxing on the processor. However, what I found out through testing is that when spinning the Gyro’clock in normal conditions the display doesn’t move around too much. But when attempting to correct the speed it moves around a lot because we can only increase the delay in finite increments. This creates too many rounding errors that it ends up making the display look choppy.

Finally here’s a plot showing how effective this trigger point detection method is:

Trigger point detection. The red lines show where the clock is displayed.

Trigger point detection. The red lines show where the clock is displayed.

We want the display to appear when the Gyro’clock is at the top of the circle. That is where the minimum acceleration occurs. As you can see it is fairly accurate and adequate for our purpose.

I know what you are thinking now; How on Earth did you collect this data and plot it when the Gyro’clock is spinning around? Well, on Earth I made a test prototype specifically for the purpose of collecting accelerometer data as it is essential to figuring out a triggering method. The test jig had a Bluetooth module and I transmitted the data wirelessly to my computer and plotted it in real time using a python program.

The test jig used to collect accelerometer data wirelessly via Bluetooth

The test jig used to collect accelerometer data wirelessly via Bluetooth

Okay so hope you got a good idea of how the trigger point detection works. Next time lets go through the real time clock module and see how it works. Thanks for riding with me.