RTC library

GrumpyOldPizza
Tue May 24, 2016 9:27 pm
Quickly would love to ask for input about the design of an RTC library. The goal is to be RTCZero compatible API wise.

I am wondering whether all the necessary addon functionality is there, or whether something was overlooked. N.b there is only 1 alarm exposed. The 2nd in hardware is reserved for internal purposes.

Thanx for looking.

class RTClock {
public:
enum RTCAlarmMatch
{
MATCH_OFF, // Never
MATCH_SS, // Every Minute
MATCH_MMSS, // Every Hour
MATCH_HHMMSS, // Every Day
MATCH_DDHHMMSS, // Every Month
MATCH_MMDDHHMMSS, // Every Year
MATCH_YYMMDDHHMMSS, // Once, on a specific date and a specific time
};

RTClock();
void begin(bool resetTime = false);

void enableAlarm(RTCAlarmMatch match);
void disableAlarm();

void attachInterrupt(void(*callback)(void));
void detachInterrupt();

void standbyMode();

// Get Functions
uint8_t getSeconds();
uint8_t getMinutes();
uint8_t getHours();

uint8_t getDay();
uint8_t getMonth();
uint8_t getYear();

uint8_t getAlarmSeconds();
uint8_t getAlarmMinutes();
uint8_t getAlarmHours();

uint8_t getAlarmDay();
uint8_t getAlarmMonth();
uint8_t getAlarmYear();

// Set Functions
void setSeconds(uint8_t seconds);
void setMinutes(uint8_t minutes);
void setHours(uint8_t hours);
void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds);

void setDay(uint8_t day);
void setMonth(uint8_t month);
void setYear(uint8_t year);
void setDate(uint8_t day, uint8_t month, uint8_t year);

void setAlarmSeconds(uint8_t seconds);
void setAlarmMinutes(uint8_t minutes);
void setAlarmHours(uint8_t hours);
void setAlarmTime(uint8_t hours, uint8_t minutes, uint8_t seconds);

void setAlarmDay(uint8_t day);
void setAlarmMonth(uint8_t month);
void setAlarmYear(uint8_t year);
void setAlarmDate(uint8_t day, uint8_t month, uint8_t year);

// Epoch Functions
uint32_t getEpoch();
uint32_t getY2kEpoch();
void setEpoch(uint32_t ts);
void setY2kEpoch(uint32_t ts);

// EXTENSTION: subsecond handling for timer synchronisation
uint32_t getSubSeconds();
void shiftSubSeconds(int32_t micros);

// EXTENSTION: clock calibration [-511..512] int32_t getCalibration();
void setCalibration(int32_t calibration);

// EXTENSTION: periodic wakeup
void wakeup(uint32_t millis, void(*callback)(void));
};

extern RTClock RTC;


martinayotte
Wed May 25, 2016 12:09 am
Hi @GrumpyOldPizza,

Why would you not expose the second Alarm ?

On F1, if I remember, there is only 1, but on F4, I’ve implemented the lib with both available.


GrumpyOldPizza
Wed May 25, 2016 12:59 am
martinayotte wrote:Hi @GrumpyOldPizza,

Why would you not expose the second Alarm ?

On F1, if I remember, there is only 1, but on F4, I’ve implemented the lib with both available.


ahull
Wed May 25, 2016 3:13 pm
Are you sure there is only one on the F1, the only info I could find suggests that there may be two.

Overview of the STM32 advanced RTC
AN3371
8/42
Doc ID 018624 Rev 2
1.2 RTC alarms
1.2.1
RTC Alarm configuration
STM32 RTC embeds two alarms, Alarm A and Alarm B, which are similar. An alarm can be
generated at a given time or/and date programmed by the user.
The STM32 RTC provides a rich combination of alarms settings, and offers many features to
make it easy to configure and display these alarms settings.

I cannot find anything specific to the F10x that says there is only one, however you may well be correct.On the other hand, even if the STM documentation claims only one for the F10x, this may be marketing spec rather than anything to do with the silicon, and the 2nd alarm may actually work any way.


martinayotte
Wed May 25, 2016 3:35 pm
The document STM32F1xxx-RM0008-CD00171190.pdf is stating in chapter 18 that only 1 RTCAlarm is present for the F1xx.
For the F4xx, the document STM32F4xxx-RM0090-DM00031020.pdf (chap.26) is showing that there are 2 Alarms, A and B, and also WakeUp timer, which I’ve implemented in RTClock for F4 as setPeriodicWakeup() awhile ago.

EDIT : Also, on a side note, the RTC of F1 is “epoch” based while the F4 is BCD based.


GrumpyOldPizza
Wed May 25, 2016 3:52 pm
martinayotte wrote:The document STM32F1xxx-RM0008-CD00171190.pdf is stating in chapter 18 that only 1 RTCAlarm is present for the F1xx.
For the F4xx, the document STM32F4xxx-RM0090-DM00031020.pdf (chap.26) is showing that there are 2 Alarms, A and B, and also WakeUp timer, which I’ve implemented in RTClock for F4 as setPeriodicWakeup() awhile ago.

EDIT : Also, on a side note, the RTC of F1 is “epoch” based while the F4 is BCD based.


ahull
Wed May 25, 2016 4:44 pm
martinayotte wrote:The document STM32F1xxx-RM0008-CD00171190.pdf is stating in chapter 18 that only 1 RTCAlarm is present for the F1xx.
For the F4xx, the document STM32F4xxx-RM0090-DM00031020.pdf (chap.26) is showing that there are 2 Alarms, A and B, and also WakeUp timer, which I’ve implemented in RTClock for F4 as setPeriodicWakeup() awhile ago.

EDIT : Also, on a side note, the RTC of F1 is “epoch” based while the F4 is BCD based.


martinayotte
Wed May 25, 2016 6:30 pm
Yes, it is down to silicon level, but the main goal is that BCD Alarms can be triggered in lot of different ways, such “per minute”, “per hour”, “per days”, etc., things that can not be achieve in hardware with “epoch” based.

martinayotte
Wed May 25, 2016 6:32 pm
GrumpyOldPizza wrote:Is there any advantage splitting the attach/detach of the wakeup callback from the configuration of the wakeup timeout ? The normal usage of the wakeup (given it’s low precision) seems to be more to wakeup from STOP mode periodically. In that case a callback would be rather pointless …

GrumpyOldPizza
Sun Oct 23, 2016 2:01 pm
Ok, finally got around implementing all of this for the STM32L4 core. Could somebody review && || provide feedback whether I got the API and functionality correct ?

The API is compatible with RTCZero (the code on github has a “RTCZero.h” wrapper). Couple of caveats. The wakeup timer is not exposed. This is reserved for “STM32.sleep(timeout)” and “STM32.deepsleep(timeout)”. The 2nd alarm for L0 and L4 is not exposed at the moment to support a future “RTCAlarm” class.

Some notes. RTC.getCalibration/setCalibration allows to speed-up/slow-down the clock. One uses RTC.pinMode(OUTPUT_1HZ) for example to output a 1Hz signal on PC13 which can be compared to a more precise reference clock. RTC.adjustTicks() can be used together with RTC.pinMode(INPUT_SYNC) to aligned the RTC with an external clock. Say one connects the PPS of a GPS to PC13, and uses RTC.onSync(). Each time there is a rising edge on PPS, the onSync() callback will be called, and with RTC.getSyncTicks() the offset (or adjustment factor) can be determinted. The sync facility itself can be used also to measure the exact time of an external event, say a button press (which is the default for Dragonfly).

N.b that “ticks” are similar to “subseconds” in the STM documentation, except that they are always scaled to [0..32767].

Thanx for looking.

class RTCClass {
public:

enum AlarmMatch: uint8_t {
MATCH_ANY = 0, // Every Second
MATCH_SS = 1, // Every Minute
MATCH_MMSS = 3, // Every Hour
MATCH_HHMMSS = 7, // Every Day
MATCH_DHHMMSS = 15, // Every Month
MATCH_MMDDHHMMSS = 31, // Every Year
MATCH_YYMMDDHHMMSS = 64 // Once, on a specific date and a specific time
};

enum PinMode: uint8_t {
NONE = 0,
INPUT_SYNC = 1,
OUTPUT_512HZ = 2,
OUTPUT_1HZ = 3,
};

void enableAlarm(AlarmMatch match);
void disableAlarm();

void attachInterrupt(void(*callback)(void));
void detachInterrupt();

// Get Functions
uint8_t getSeconds();
uint8_t getMinutes();
uint8_t getHours();

uint8_t getDay();
uint8_t getMonth();
uint8_t getYear();

uint8_t getAlarmSeconds();
uint8_t getAlarmMinutes();
uint8_t getAlarmHours();

uint8_t getAlarmDay();
uint8_t getAlarmMonth();
uint8_t getAlarmYear();

// Set Functions
void setSeconds(uint8_t seconds);
void setMinutes(uint8_t minutes);
void setHours(uint8_t hours);
void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds);

void setDay(uint8_t day);
void setMonth(uint8_t month);
void setYear(uint8_t year);
void setDate(uint8_t day, uint8_t month, uint8_t year);

void setAlarmSeconds(uint8_t seconds);
void setAlarmMinutes(uint8_t minutes);
void setAlarmHours(uint8_t hours);
void setAlarmTime(uint8_t hours, uint8_t minutes, uint8_t seconds);

void setAlarmDay(uint8_t day);
void setAlarmMonth(uint8_t month);
void setAlarmYear(uint8_t year);
void setAlarmDate(uint8_t day, uint8_t month, uint8_t year);

// Epoch Functions
uint32_t getEpoch();
uint32_t getY2kEpoch();
void setEpoch(uint32_t ts);
void setY2kEpoch(uint32_t ts);

// STM32L4 EXTENSION: atomic set time/date
void setCalendar(uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t day, uint8_t month, uint8_t year);

// STM32L4 EXTENSION: ticks [0..32767] uint16_t getTicks();

// STM32L4 EXTENSION: clock calibration [-511..512] int32_t getCalibration();
void setCalibration(int32_t calibration);

// STM32L4 EXTENSION: clock fine tuning [-32767..32768] void adjustTicks(int32_t ticks);

// STM32L4 EXTENSION: external sync pulse
bool syncOccured();
uint16_t getSyncTicks();
uint8_t getSyncSeconds();
uint8_t getSyncMinutes();
uint8_t getSyncHours();
uint8_t getSyncDay();
uint8_t getSyncMonth();
void onSync(void(*callback)(void));

// STM32L4 EXTENSION: PC13 control
void pinMode(PinMode mode);
};

extern RTCClass RTC;


Nutsy
Sun Mar 26, 2017 12:43 pm
ok iim intrigued… I would like a RTC on my speedo project… i was going to use one of those external RTC modules… But I remembered some one saying there is one built in.

I guess you supply power to vbat, to keep the rtc powered when the rest of the MCU is unpowered?
How much voltage? 1.5? 3v?

And im assuming there isnt already a functioning library?

Hence this thread? :D

I guess a little guide would be useful… or if you know of any documentation I can read even better :D

Sorry for the dumb post, im fairly tired and backs in pain………… (crippled)


martinayotte
Sun Mar 26, 2017 1:02 pm
The specs mentioned Vbat should be between 1.8V and 3.6V.
I’m personally using a SuperCapacitor instead of a battery.
The library on github is working fine.

Nutsy
Sun Mar 26, 2017 2:12 pm
Oh which github? Rogers STM32?

martinayotte
Sun Mar 26, 2017 2:25 pm
Yes !
https://github.com/rogerclarkmelbourne/ … es/RTClock

Nutsy
Sun Mar 26, 2017 2:53 pm
thankies

Nutsy
Mon Mar 27, 2017 11:29 am
Only asking as I cant play with it for a few days……

Does the built in rtc work off unix time? So you can derive a date from the number? Or is it simple 24 hour clock and nothing else?

i see the gettime function seems to be call to check the time. But I dont see any get date or anything else…


ahull
Mon Mar 27, 2017 11:47 am
Nutsy wrote:Only asking as I cant play with it for a few days……

Does the built in rtc work off unix time? So you can derive a date from the number? Or is it simple 24 hour clock and nothing else?

i see the gettime function seems to be call to check the time. But I dont see any get date or anything else…


HutTheNut
Tue Apr 03, 2018 3:54 pm
Hi,

Having search for “RTC STM32L4” and reading the thread.

I’m wondering why the link is for F1
https://github.com/rogerclarkmelbourne/ … es/RTClock

And I is see no L4 section at all at the basic link, only F1/F3/F4.
https://github.com/rogerclarkmelbourne/Arduino_STM32

Does anyone know where I can find the L4 libraries..

Best regards,
Frank


victor_pv
Tue Apr 03, 2018 4:08 pm
viewtopic.php?f=42&t=1092

HutTheNut
Tue Apr 03, 2018 4:31 pm
thanks

electrobling
Mon Apr 09, 2018 6:00 pm
[GrumpyOldPizza – Sun Oct 23, 2016 2:01 pm] –
Ok, finally got around implementing all of this for the STM32L4 core. Could somebody review && || provide feedback whether I got the API and functionality correct ?
[…] Some notes. RTC.getCalibration/setCalibration allows to speed-up/slow-down the clock. One uses RTC.pinMode(OUTPUT_1HZ) for example to output a 1Hz signal on PC13 which can be compared to a more precise reference clock. RTC.adjustTicks() can be used together with RTC.pinMode(INPUT_SYNC) to aligned the RTC with an external clock. Say one connects the PPS of a GPS to PC13, and uses RTC.onSync(). Each time there is a rising edge on PPS, the onSync() callback will be called, and with RTC.getSyncTicks() the offset (or adjustment factor) can be determinted. The sync facility itself can be used also to measure the exact time of an external event, say a button press (which is the default for Dragonfly).

I’m just curious about the sync method. I admit I haven’t yet looked at the F4 calibration circuit to see if there are any major differences from the F1. But on the F1, it takes more than one second to obtain a measurement equal to the register calibration steps, it takes at least 32 seconds. What I did is sample the 32kHz ticks twice, at least 32 seconds apart. That is because N pulses are removed in one 32S interval. Then some math to scale it to calibration steps. Is that close to what you are doing with the sync method in your RTC library?

Also have you considered the possibly intermittent nature of the incoming sync? For example, a device might only get PPS when it is near a window and it would be desirable to automatically retain the resulting cal, and continue to operate normally, even if the whole thing is moved to a place were GPS is dark.

Or, if the device lacks GPS hardware, and it is applied to external terminals for the purpose of an initial or a periodic calibration.


GrumpyOldPizza
Tue Apr 10, 2018 3:03 pm
[electrobling – Mon Apr 09, 2018 6:00 pm] –

[GrumpyOldPizza – Sun Oct 23, 2016 2:01 pm] –
Ok, finally got around implementing all of this for the STM32L4 core. Could somebody review && || provide feedback whether I got the API and functionality correct ?
[…] Some notes. RTC.getCalibration/setCalibration allows to speed-up/slow-down the clock. One uses RTC.pinMode(OUTPUT_1HZ) for example to output a 1Hz signal on PC13 which can be compared to a more precise reference clock. RTC.adjustTicks() can be used together with RTC.pinMode(INPUT_SYNC) to aligned the RTC with an external clock. Say one connects the PPS of a GPS to PC13, and uses RTC.onSync(). Each time there is a rising edge on PPS, the onSync() callback will be called, and with RTC.getSyncTicks() the offset (or adjustment factor) can be determinted. The sync facility itself can be used also to measure the exact time of an external event, say a button press (which is the default for Dragonfly).

I’m just curious about the sync method. I admit I haven’t yet looked at the F4 calibration circuit to see if there are any major differences from the F1. But on the F1, it takes more than one second to obtain a measurement equal to the register calibration steps, it takes at least 32 seconds. What I did is sample the 32kHz ticks twice, at least 32 seconds apart. That is because N pulses are removed in one 32S interval. Then some math to scale it to calibration steps. Is that close to what you are doing with the sync method in your RTC library?

Also have you considered the possibly intermittent nature of the incoming sync? For example, a device might only get PPS when it is near a window and it would be desirable to automatically retain the resulting cal, and continue to operate normally, even if the whole thing is moved to a place were GPS is dark.

Or, if the device lacks GPS hardware, and it is applied to external terminals for the purpose of an initial or a periodic calibration.

A loaded topic. I am starting to use a slightly different technique now, mainly because the SYNC input might not be always available. The idea in general is to qualify the PPS input with a valid fix. I.e. it’s only armed after a valid fix (or sequence thereof). If you have a valid fix, then you have everything down to the second essentially. So you need to align the subsecond as a first step. With a PPS interrupt that is half way easy. If the getSubSeconds() read back is say between 1 and 16383, then you need to subtract from the subseconds, i.e. RTC.adjustSubSeconds(-offset). If your subseconds are between 16384 and 32767, then you need to add to the subseconds. Obviously you want to apply a filter, so that the steps close to the right alignment are smaller than the ones from far out.

If you have 2 back to back PPS measurements you also can derive from the uncompensated subseconds the period, and hence do fine calibration. Again, the issue is jitter, which requires a filter.

Have only really looked into that with regards to a GNSS …


electrobling
Tue Apr 10, 2018 3:39 pm
All good. I looked at the manual yesterday. You definitely have your work cut out for you, the F4 RTC calibration options are more complex than the F1. Of course, there are multiple options and use cases so it’s sometimes difficult to decide how to extend the basic framework into an interface. I see what you mean about the single back to back PPS, but if I recall correctly, some modules provide it with only a +/- 10uS accuracy. That wouldn’t be sufficient for a 1PPS or finer calibration. I am also a bit lost about how you could measure the 32kHz clock accurately in only only one second. But if you have this all in hand, it will become evident when you publish.

Indeed, when I experimented with some GPS modules, they sometimes provided PPS pulses before a fix and I wasn’t too sure about that. I implemented a gate based on the NMEA sentences, as you suggested, to wait until the fix to sample it. But this time around, I’ve been lazy and wait 5 minutes after the light starts flashing (serial not connected). I also check for missing pulses. If one is missed, I stop the calibration and start all over.

I have some F4 boards on order, they have an onboard battery circuit so I may get a chance to try out whatever you come up with.


Leave a Reply

Your email address will not be published. Required fields are marked *