RTCzero (issues)

I’m using RTCzero on the autonomo … but using getEpoch() seems to block interrupts too long which results in losing NMEA packets … I have read in the datasheet reading the clock registers can result in the bus being stalled, which is no no when you depend on interrupts - does anyone have a solution before I dive in and try to find a solution ? for now I’m just avoiding getEpoch() …

Can I ask where are you calling getEpoch() from? Is the call being made within an interrupt service routine?

It is called from void loop() …

while(1) {
while (Serial.available()) { … }
rtc.getEpoch(); …
… other processing

serial data comes in at 57600 baud each second about 128 bytes in total, i have increased the serial buffer to 256 bytes to make I’m not loosing data due to buffer undersize.

when I remove the rtc.getEpoch() no data is lost … when it is there i lose about 60 characters …

from the manual … 18.6.9

If an operation that requires synchronization is executed while STATUS.SYNCBUSY is one, the bus will be stalled. All operations will complete successfully, but the CPU will be stalled and interrupts will be pending as long as the bus is stalled.

I have not yet tried to insert STATUS.SYNCBUSY and see if that improves anything

It seems doesn’t really matter which readfunction you use, but anything called repeatly in the while loop will create a stalling processor. I did a quick read and looks like it it can be resolved by adding;

void RTCZero::ReadReq() {
while (RTCisSyncing());

and call this function before a read e.g.

uint8_t RTCZero::getSeconds()

Now the processor is no longer stalling while the register is read synchronised …

If you are using:

The main library has since pulled those changes and now supports the epoch and other additions.
They have also since updated the epoch methods to use another conversion method.

This will probably have the same overhead issues as it reads all of the pieces from the CLOCK register in separate operations. One possible solution would be to read the whole CLOCK register once, copying it into a local variable/struct. This would reduce the amount of read and synchronisation operations down to one.

Maybe I misunderstand, but both links do not do read requests as presented above … which you have to do to avoid stalling, I added this piece of code to all get functions getSeconds, getMinutes etc. and now it works flawlessly no more losing characters …

Yes, neither make the read request. I wanted to point out that the main library uses a different approach to calculating the Epoch time (in case your issue was caused by something else). It seems that you have found the core of the issue which is present in both versions.

I’ll test your fix tonight and see if I can get it pulled into the main Arduino library.

I ran some tests using this sketch:

#include <RTCZero.h>
RTCZero rtc;

void setup() 
  rtc.begin(); // initialize RTC
  rtc.setEpoch(1451606400); // Jan 1, 2016

void loop() 
  uint32_t ms = millis();

  SerialUSB.print("Calling getEpoch() 100 times, duration ms: ");
  for (uint8_t i = 0; i < 100; i++) {
  SerialUSB.println(millis() - ms);

Using the old code: 100x = ~606ms
Using the synced code: 100x = ~3513ms

I then updated the getEpoch() method to only access the CLOCK register in a single request.
This dropped it down to: 100x = ~585ms

The commits can be seen here:

Let me know if this works correctly for you and I will create a pull request into the Arduino library.

Cheers, I will do some testing later this week, tomorrow I’m with a customer most of the day.

BTW there seems to be no point in | RTC_READREQ_ADDR(0x10); These bits are read-only according the datasheet …

Bits 5:0 – ADDR[5:0]: Address
These bits select the offset of the register that needs read synchronization. In the RTC only COUNT and CLOCK, which share the same address, are available for read synchronization. Therefore, ADDR is a read-only constant of 0x10.

Thanks for that. I’ve removed it and pushed the change.

I’ve just pushed a few more changes.
The read and write operations now check if the RTC has been initialised first.

Previously, if the RTC was not intialised first, any calls to read or write the various parameters would result in endless blocking. Now if the RTC is not initialised, the write operations are skipped, and read operations are not synced. The RTC won’t function correctly if not initialised before use. However, now it won’t cause the sketch (and possibly the hardware) to freeze if that mistake is made.

1 Like

Just a heads up, those changes have now been pulled into the main RTCZero fork.

Another change has also been added which will preserve the previous time after a reset. However, the time will not be preserved if the board is reset by POR or either BOD.

1 Like