AceTimeClock  1.3.0
Clock classes for Arduino that can synchronize from an NTP server or an RTC chip
Public Member Functions | List of all members
ace_time::clock::Stm32F1Clock Class Reference

An implementation of Clock that is specialized for the LSE_CLOCK (Low Speed External clock) on the STM32F1 RTC chip. More...

#include <Stm32F1Clock.h>

Inheritance diagram for ace_time::clock::Stm32F1Clock:
Inheritance graph
[legend]
Collaboration diagram for ace_time::clock::Stm32F1Clock:
Collaboration graph
[legend]

Public Member Functions

void setup ()
 Configure the clock.
 
acetime_t getNow () const override
 Return the number of seconds since the AceTime epoch (2000-01-01T00:00:00Z). More...
 
void setNow (acetime_t epochSeconds) override
 Set the time to the indicated seconds. More...
 
- Public Member Functions inherited from ace_time::clock::Clock
 Clock ()=default
 Default constructor.
 
 ~Clock ()=default
 We deliberately avoid using a virtual destructor. More...
 
virtual void sendRequest () const
 Send a time request asynchronously.
 
virtual bool isResponseReady () const
 Return true if a response is ready.
 
virtual acetime_t readResponse () const
 Returns number of seconds since AceTime epoch (2000-01-01). More...
 

Additional Inherited Members

- Static Public Attributes inherited from ace_time::clock::Clock
static const acetime_t kInvalidSeconds = LocalTime::kInvalidSeconds
 Error value returned by getNow() and other methods when this object is not yet initialized.
 

Detailed Description

An implementation of Clock that is specialized for the LSE_CLOCK (Low Speed External clock) on the STM32F1 RTC chip.

Normally, the LSE_CLOCK requires an additional external 32.768 kHz crystal, but the popular "Blue Pill" dev board already includes this extenal crystal on pins C14 and C15. Warning: For the highest clock accuracy, those pins should not be attached anything else, not even the male header pins. The header pins will add too much stray capacitance to the oscillator circuit, and cause the clock to run too slow. I have seen the clock run as much as 10% too slow with the male header pins attached. If you hold a finger to those pins, it adds so much capacitance that the LSE_CLOCK will appear to just stop.

There are 3 possible RTC clocks on the STM32F1 (HSI_CLOCK, LSI_CLOCK, and LSE_CLOCK). But the LSE_CLOCK is special because it keeps updating the RTC on the STM32F1 through a reset or power loss, as long as a battery is attached to VBat. The battery could be a 3V CR2032 coin battery, or 2AA rechargeable or non-rechargeable battery, or it could be a super capacitor.

This class uses the Stm32F1Rtc helper class to write directly to the RTC registers on the STM32F1, bypassing the generic STM32RTC library (https://github.com/stm32duino/STM32RTC) which would normally be used for other STM32 microcontrollers. The generic STM32RTC library has a bug on the STM32F1 where it preserves only the time fields in the RTC registers, saving the date fields on SRAM which is lost upon reset (See https://github.com/stm32duino/STM32RTC/issues/29 and https://github.com/stm32duino/STM32RTC/issues/32). The problem is caused in the low-level HAL (hardware abstraction layer) of the STM32F1 chip, because unlike other STM32 processors which stores the time and date fields as separate fields, the RTC on the STM32F1 is just a simple 32-bit counter (split across 2 registeres, RTC_CNTH and RTC_CNTL) that increments once a second.

It turns out that for the purposes of AceTime and the SystemClock, a 32-bit counter is sufficient to support all of its functionality. In particular, the 32-bit counter is sufficient to allow AceTime to retain both date and time fields through a power reset. So the Stm32F1Rtc class is a narrowly targeted HAL whose only purpose is to read from and write to the 32-bit RTC counter on the STM32F1 chip. It bypasses the entire generic RTC and HAL layers provided by the STM32duino framework.

AceTime v2 allows the epoch year of the library to be adjustable by the client application, from the year 2000 until the year 10000. The use of a simple 32-bit counter in the STM32F1 works to its advantage because it makes it allows it work for any the epoch year selected in the AceTime library. This is in contrast to the other STM32 processors which use a 2-digit year offset from the year 2000. The RTC of those processors will break in the year 2100 unless a software fix can be created to work around that limitation.

The Stm32F1Rtc class uses one additional register, the Backup DR1 register, which holds a single status bit to indicate whether or not the underlying RTC counter has been initialized to a valid time. The selection of the DR1 register, instead of any of the other 9-10 backup registers, is currently hardcoded in the RTC_INIT_REG macro in Stm32F1Rtc.h. If that causes a conflict with something else, let me know, because this is fixable. We can make that a configurable parameter in the Stm32F1Rtc::begin() method.

Definition at line 77 of file Stm32F1Clock.h.

Member Function Documentation

◆ getNow()

acetime_t ace_time::clock::Stm32F1Clock::getNow ( ) const
inlineoverridevirtual

Return the number of seconds since the AceTime epoch (2000-01-01T00:00:00Z).

Returns kInvalidSeconds if an error has occured.

This is a blocking call. Some clocks (e.g. NTP client) this may take many seconds. On those clocks, use the asynchronous methods (sendRequest(), isResponseReady(), and readResponse()) instead.

Implements ace_time::clock::Clock.

Definition at line 88 of file Stm32F1Clock.h.

◆ setNow()

void ace_time::clock::Stm32F1Clock::setNow ( acetime_t  )
inlineoverridevirtual

Set the time to the indicated seconds.

Calling with a value of kInvalidSeconds indicates an error condition, so the method should do nothing. Some clocks do not support this feature, for example, NTP or GPS clocks and this method will be a no-op.

Reimplemented from ace_time::clock::Clock.

Definition at line 96 of file Stm32F1Clock.h.


The documentation for this class was generated from the following file: