Ruuvi Firmware – Part 8: Real Time Clock

Ruuvi Firmware series part 8 intro image

In this part of the tutorial we’ll add support for the Real Time Clock (RTC) on nRF52832. Final code of this blog post can be downloaded at Ruuvi GitHub in the ruuviblog-branch, tag 3.8.0-alpha.

Please follow part 1 of the series for details on how to clone the repository and compile the code. Final hex of this tutorial can be downloaded from the Ruuvi Jenkins.

ruuvi-firmware.c architecture 3.8.0

Real Time Clock

The RTC is used for keeping track of the passage of time outside the program state. For now we’ll be happy with counting milliseconds since the program boot and timestamping our sensor data samples. Later on we might add a mechanism to synchronize internal clock of nRF52832 to externally given time, such as the Unix Epoch.

RTC interface

Since configuring things such as scale, resolution or sample rate does not really make sense for the RTC we won’t be using the sensor interface for the RTC peripheral. We’ll define only init, uninit and mills -functions for the RTC and add a function pointer to the timestamp function in our sensor interface.

ruuvi_interface_rtc.h
ruuvi_interface_rtc.h

RTC driver

The internal counter of nRF52 has only 24 bits, but luckily we have an overflow event which can be used to track the times when the internal counter has rolled over.

Up until now our sleep has kept all the clocks off, and only way to wake up has been via external interrupt, such as button press. This however means that time does not exist for our device while it is sleeping. We can start the low-frequency clock (LFCLK) when we initialize the RTC and keep the LFCLK active during sleep to keep track of the time through the sleep periods.

As the Nordic Softdevice used by the Bluetooth stack will keep the low-frequency crystal active, LFCLK comes without any “extra” energy cost in the final program. The SDK provides convenient request– and release-functions for the LFCLK which keep track on if the LFCLK can be stopped in case there are several users for the clock, so we can let our RTC driver request and release the LFCLK without worrying other drivers state.

Since we’re using 64 bits as the counter width, we don’t really need the prescaler of the RTC. We’ll increment the ticks at 32.768 kHz of the LFCLK which gives us roughly 512 seconds between the hardware counter overflows and 17850 years before our software counter overflows. We could also get sub-millisecond resolution for the timestamps, but for now it won’t be necessary.

Integrating the RTC

We’ll add the timestamping function to our RTC interface and adjust our drivers to call it rather than just marking the timestamp of the samples as invalid. To avoid dependencies between the sensor interfaces and RTC itself, we add timestamping function as a function pointer to the sensor interface and set the function pointer to the interface at the RTC initialization.

Now we can also finally add debouncing support to our button code: we timestamp the button press and unless enough time has passed since last registered press we’ll ignore the event.

task_button.c — no more double-clicks
task_button.c — no more double-clicks

Finally, we’ll fix the UINT64 printing bug on ARMGCC by simply dropping out the higher 32 bits of the timestamp. This still gives us almost 50 days before our timestamp rolls over.

Testing

In previous part we started building unit tests which check that each sensor interface has proper behavior on initialization and uninitialization. Let’s append the test and add test for getting and setting scale, sample rate and resolution. Since all of the functions have the same signature we can use the same tests on each of the functions.

This time, our new test finds a problem in the previous test. Since the initialization test does not set the sensor structure to all zeroes before first initialization, our initialization test is happy to see that a function pointer is not NULL if some old values remain in the memory where our struct points at. When we actually try to call the function, program crashes as the function pointer does not point to a valid address. Let’s get both the test and the bug fixed and continue.

Debug terminal
Once again our tests find errors

Time to go back and clean up the drivers a bit. First we see that the we have had issues with lines 187, 193 and 223 of our ADC self-test.

Our error is in NULL check
Our error is in NULL check
Error source is in scale functions
Error source is in scale functions

It seems that our ADC does not have proper NULL pointer checking in the scale setter and getter, let’s fix it.

NULL checks added
NULL checks added

Now we re-run the tests:

The ADC test passes now
The ADC test passes now

After the fix we pass 11 / 16 tests, up from previous 9 / 16. Rest of the errors are similarly tracked down and fixed.

Issues found
Issues found by the tests are now fixed and timestamps are looking good

Power Consumption

As we have the LFCLK constantly running, we can expect some power consumption increase after enabling the RTC. Let’s see how it looks like.

Idle power consumption
Idle power consumption

Our current consumption is now 6.4 μA at idle, 1.4 μA up from 5.0 μA in our previous post.

Conclusion

In this tutorial we have added RTC support and timestamps to our sensor readouts. Now we have everything we need to implement the Ruuvi data format 3. In the next post we’ll start broadcasting the data from RuuviTag.

Stay tuned and follow @ojousima and @ruuvicom on Twitter for #FirmwareFriday posts!

Featured Products

Find the right products for your measuring needs
  • On backorder
    RuuviTag Pro is an environmental sensor that fits perfectly...
    Read more

    RuuviTag Pro (2-in-1, breathable, estimated shipping in middle of December)

    49,90
  • RuuviTag temperature sensorIn stock
    This RuuviTag model is without an air pressure sensor....
    Read more

    RuuviTag – Wireless Temperature Sensor (3-in-1)

    38,90
  • In stock
    With Ruuvi Gateway, you can read your Ruuvi sensors...
    Read more

    Ruuvi Gateway

    199,00
  • On backorder
    RuuviTag Pro is an environmental sensor that fits perfectly...
    Read more

    RuuviTag Pro (3-in-1, breathable, estimated shipping in middle of December)

    49,90