RTC (Where / How is it working)

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
cnmcdee
Posts: 12
Joined: Sat Sep 11, 2021 10:41 pm

RTC (Where / How is it working)

Post by cnmcdee » Sun Sep 12, 2021 3:02 pm

I have no idea how this little board is doing this:

Code: Select all

import machine
import utime
import time

rtc = machine.RTC()
print("Current time:" + str(rtc.datetime()))
Gives : Current time:(2021, 9, 12, 6, 15, 50, 5, 0)

However that is not the time on the Raspberry Pi that it is connected to. Is Thonny doing an automatic pass?

Unplugging it and re-plugging it in showed it was still keeping time.

Gives : Current time:(2021, 9, 12, 6, 15, 58, 32, 0)

Does this thing have some type of tiny RTC that runs off a micro-capacitor even when it's unplugged - or is it getting passed a value from an IDE when it is powered?

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: RTC (Where / How is it working)

Post by Roberthh » Sun Sep 12, 2021 3:17 pm

Thonny sets the time. To rule out an IDE, connect to the board with a dumb terminal emulator like putty or screen.

hippy
Posts: 130
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: RTC (Where / How is it working)

Post by hippy » Mon Sep 13, 2021 10:26 pm

Somewhat related; there seems to be a bug with 'weekday' for 'RTC' which then impacts upon 'time' ...

Code: Select all

from machine import RTC
rtc = RTC()
print("rtc.datetime()   =>", rtc.datetime(),   "\t", "y m d | weekday | h m s | sub-seconds")

import time
print("time.gmtime()    =>", time.gmtime(),    "\t", "y m d | h m s | weekday | yearday")
print("time.localtime() =>", time.localtime(), "\t", "y m d | h m s | weekday | yearday")

Code: Select all

rtc.datetime()   => (2021, 9, 13, 0, 23, 24, 12, 0) 	 y m d | weekday | h m s | sub-seconds
time.gmtime()    => (2021, 9, 13, 23, 24, 12, 6, 256) 	 y m d | h m s | weekday | yearday
time.localtime() => (2021, 9, 13, 23, 24, 12, 6, 256) 	 y m d | h m s | weekday | yearday
'machine_rtc.c' appears to exclude Thonny from setting 'weekday' wrong so not sure where the issue actually lies.

Calculating the actual weekday whenever it needs to be returned is the way I normally do it to ensure there can be no inconsistency and makes it independent of whatever has been set or is held.

ex_piro
Posts: 5
Joined: Thu Sep 09, 2021 11:46 pm

Re: RTC (Where / How is it working)

Post by ex_piro » Tue Sep 14, 2021 12:16 am

I recently used this code to set the pico clock from my PC.
viewtopic.php?t=9706#p54302

This works fine.

Code: Select all

pythonInject = [
    'import machine',
    'import utime',
    'rtc_base_mem = 0x4005c000',
    'atomic_bitmask_set = 0x2000',
    'led_onboard = machine.Pin(25, machine.Pin.OUT)',
    '(year,month,day,hour,minute,second,wday,yday)=utime.localtime('+utcTime+')',
    'machine.mem32[rtc_base_mem + 4] = (year << 12) | (month  << 8) | day',
    'machine.mem32[rtc_base_mem + 8] = ((hour << 16) | (minute << 8) | second) | (((wday + 1) % 7) << 24)',
    'machine.mem32[rtc_base_mem + atomic_bitmask_set + 0xc] = 0x10',
I tried using the alternate method in that thread
viewtopic.php?t=9706#p59053
This sets the weekday incorrectly and I was not able to do anything to force it to any value. It was always set to 4 even though it was Saturday (5).

Code: Select all

pythonInject = [
    'from machine import RTC',
    'import utime',
    'led_onboard = machine.Pin(25, machine.Pin.OUT)',
    '(year,month,day,hour,minute,second,wday,yday)=utime.localtime('+utcTime+')',
    'rtc=RTC()',
    'rtc.datetime((year, month, day, (wday + 1) % 7, hour, minute, second, 0))',

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: RTC (Where / How is it working)

Post by dhylands » Tue Sep 14, 2021 4:10 pm

time.gmtime() returns the weekday with Monday = 0 https://docs.python.org/3/library/time. ... truct_time

RTC.datetime doesn't necessarily do this. These docs say Monday = 1 https://docs.micropython.org/en/latest/ ... C.datetime

Given the number of other inconsistencies with RTC between ports, it wouldn't surprise me to find out that they aren't all consistent with each other.

hippy
Posts: 130
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: RTC (Where / How is it working)

Post by hippy » Wed Sep 15, 2021 2:06 pm

Looking at 'main.c' it appears the RP2 RTC uses 0=Monday, 6=Sunday

Code: Select all

    // Start and initialise the RTC
    datetime_t t = {
        .year = 2021,
        .month = 1,
        .day = 1,
        .dotw = 4, // 0 is Monday, so 4 is Friday
        .hour = 0,
        .min = 0,
        .sec = 0,
    };
Within 'machine_rtc.c' setting the RTC calculates the weekday, which also appears to use 0=Monday, 6=Sunday -

Code: Select all

        // Deliberately ignore the weekday argument and compute the proper value
        t.dotw = timeutils_calc_weekday(t.year, t.month, t.day);
Reading 'RTC.datetime' simply returns 't.dotw'.

So far so good, and that means what was seen by the OP and myself was correct -

OP : (2021, 9, 12, 6, 15, 50, 5, 0) - 2021-09-12 with 6=Sunday being correct
Me : (2021, 9, 13, 0, 23, 24, 12, 0) - 2021-09-13 with 0=Monday being correct

My earlier assertion that RTC.datetime was buggy rests not on that, but whether it's what should have been seen; 'RTC.datetime' should be using 1=Monday which it does not.

That it should be 1=Monday comes from looking at 'modutime.c' which returns its 'gmtime' weekday as -

Code: Select all

            mp_obj_new_int((t.dotw + 6) % 7), // convert 0=Sunday to 6=Sunday
[s]That doesn't work because 't.dotw' uses 0=Monday, not 0=Sunday[/s]
Sort of, but it's 1=Monday, 0=Sunday - See later posts

The problem is we have six things which could use different enumerations -

What's held in a physical RTC chip if there is one
What's held in 'datetime_t'
What's held in 'timeutils_struct_time_t' - 0=Monday, 6=Sunday (according to shared code)
What's returned by timeutils_calc_weekday - 0=Monday, 6=Sunday (according to shared code)
What's set and read by 'RTC.datetime'
What's set and read by 'time.gtime' - 0=Monday, 6=Sunday (according to Python docs)

The issue does appears to come down to 'RTC.datetime' -

It should be 1=Monday according to https://docs.micropython.org/en/latest/ ... e.RTC.html
It should be 1=Monday, 7=Sunday according to https://docs.micropython.org/en/latest/ ... b.RTC.html
It is 1=Monday on a PyBoard
It is treated as 1=Monday when converting to 'time.gtime'
[s]It is 0=Monday, 6=Sunday for RP2040[/s]
It is 1=Monday, 0=Sunday for RP2040

For 'RTC.datetime' on the RP2 to be consistent with that of the PyBoard and documentation, the values read and returned need to be adjusted with respect to what is stored in 'datetime_t'. Then every thing should just work. The fixes should probably be -

Reading 'RTC.datetime'' -

Code: Select all

// Convert calc 0=Monday, 6=Sunday to RTC.datetime 1=Monday, 7=Sunday
mp_obj_new_int(timeutils_calc_weekday(t.year, t.month, t.day) + 1),
Setting 'RTC.datetime' - Updated - see later posts

Code: Select all

// Convert calc 0=Monday, 6=Sunday to datetime_t 1=Monday, 0=Sunday
t.dotw = (timeutils_calc_weekday(t.year, t.month, t.day) + 1) % 7;
Reading 'time.gmtime' / 'time.localtime' -

Code: Select all

// Convert calc 0=Monday, 6=Sunday to time.gmtime 0=Monday, 6=Sunday
mp_obj_new_int(timeutils_calc_weekday(t.year, t.month, t.day)),
Setting 'time.gmtime' / 'time.localtime' -

Code: Select all

// Convert calc 0=Monday, 6=Sunday to timeutils_struct_time_t 0=Monday, 6=Sunday
tuple[6] = mp_obj_new_int(timeutils_calc_weekday(tm.tm_year, tm.tm_mon, tm.tm_mday)),
'time.mktime' might need a fix but is probably correct.
Last edited by hippy on Thu Sep 16, 2021 11:44 am, edited 1 time in total.

fdufnews
Posts: 76
Joined: Mon Jul 25, 2016 11:31 am

Re: RTC (Where / How is it working)

Post by fdufnews » Wed Sep 15, 2021 3:29 pm

Why is ISO 8601 standard not used?

User avatar
scruss
Posts: 360
Joined: Sat Aug 12, 2017 2:27 pm
Location: Toronto, Canada
Contact:

Re: RTC (Where / How is it working)

Post by scruss » Thu Sep 16, 2021 12:54 am

fdufnews wrote:
Wed Sep 15, 2021 3:29 pm
Why is ISO 8601 standard not used?
No RTC that I know of uses ISO standard times. They're usually packed BCD fields and have limited range.

The RP2040's RTC is weird even by RTC standards

hippy
Posts: 130
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: RTC (Where / How is it working)

Post by hippy » Thu Sep 16, 2021 10:59 am

scruss wrote:
Thu Sep 16, 2021 12:54 am
fdufnews wrote:
Wed Sep 15, 2021 3:29 pm
Why is ISO 8601 standard not used?
No RTC that I know of uses ISO standard times. They're usually packed BCD fields and have limited range.
ISO8601 is mostly a presentation format so it doesn't really matter how the data is stored internally but it does provide a definition of 'day of week' aka 'weekday'; 1=Monday, 7=Sunday.

Many physical RTC chips comply with that definition, for example the DS1307, DS3231/2/4.

'RTC.datetime' is also defined and documented as using that definition. Though my guess is it was defined to comply with what RTC chips used rather than ISO8601 definition.

As to why 'time.gmtime' and friends don't comply; I would guess that was an arbitrary decision of the past which, being documented and used, is something we are stuck with.
scruss wrote:
Thu Sep 16, 2021 12:54 am
The RP2040's RTC is weird even by RTC standards
You are right. Checking the RP2040 I discovered -

"Day of the week is encoded as Sun 0, Mon 1, …, Sat 6 (i.e. ISO8601 mod 7)"

That is probably where the conversion issues have crept in; effectively subtracting/adding 1 rather than modulo and fixing 0.

How it's defined is largely irrelevant if returned values are always calculated from Y-M-D, but one should set it correctly. I will update my earlier proposed fixes. It also means 'main.c' is wrong, as are all places where the presumption is it uses 0=Monday -

Code: Select all

    // Start and initialise the RTC
    datetime_t t = {
        .year = 2021,
        .month = 1,
        .day = 1,
        .dotw = 4, // 0 is Monday, so 4 is Friday
Someone really needs to do a complete audit of MicroPython to find where 'datetime_t' is used and correct any conversion errors.

hippy
Posts: 130
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: RTC (Where / How is it working)

Post by hippy » Thu Sep 16, 2021 11:03 am

On the issue of the RTC class I have found an anomaly -

https://docs.micropython.org/en/latest/ ... b.RTC.html -

"class pyb.RTC - Create an RTC object"

https://docs.micropython.org/en/latest/ ... e.RTC.html -

"class machine.RTC(id=0, ...) - Create an RTC object. See init for parameters of initialization"

That's fine but 'id' isn't described, isn't defined by 'init' and, at least using the RP2 port, such an 'id' parameter cannot be provided. In fact it doesn't accept any parameters.

Post Reply