rshell & Raspberry Pi Pico - date & time sync

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Post Reply
DWiskow
Posts: 11
Joined: Sun Apr 24, 2016 1:23 pm

rshell & Raspberry Pi Pico - date & time sync

Post by DWiskow » Mon Feb 01, 2021 6:07 pm

A user on the Raspberry Pi forum posted this https://www.raspberrypi.org/forums/view ... 6#p1810426, which appears to set the Pico RTC from within MicroPython.

Code: Select all

import machine
import utime
print()
print("                           YYYY MM DD HH MM SS")
dateTime = (input ("Enter current date & time: "))+' 0 0'
givenTime = utime.mktime(list(map(int, tuple(dateTime.split(' ')))))

ctime=utime.localtime(givenTime)

# ok insert data into the rtc

setup_0 = (ctime[0] << 12) | (ctime[1] << 8) | ctime[2]

def weekDay(year, month, day):
    offset = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
    afterFeb = 1
    if month > 2: afterFeb = 0
    aux = year - 1700 - afterFeb
    # dayOfWeek for 1700/1/1 = 5, Friday
    dayOfWeek  = 5
    # partial sum of days betweem current date and 1700/1/1
    dayOfWeek += (aux + afterFeb) * 365                  
    # leap year correction    
    dayOfWeek += aux // 4 - aux // 100 + (aux + 100) // 400     
    # sum monthly and day offsets
    dayOfWeek += offset[month - 1] + (day - 1)               
    dayOfWeek %= 7
    return int(dayOfWeek)

setup_1 =  (ctime[3] << 16) | (ctime[4] << 8) | ctime[5]
setup_1 =  setup_1 |  (weekDay(ctime[0],ctime[1],ctime[2]) << 24)
# Be aware that RTC start at sunday=0
# and utime start dayofweek monday=0

# set rtc
machine.mem32[0x4005c004]= setup_0
machine.mem32[0x4005c008]= setup_1
machine.mem8[0x4005c00c] = machine.mem8[0x4005c00c] | 0x10
Could this be of help in getting rshell to synchronise date & time on connection ? :D
Last edited by DWiskow on Tue Feb 02, 2021 10:32 am, edited 1 time in total.

DWiskow
Posts: 11
Joined: Sun Apr 24, 2016 1:23 pm

Re: rshell & Raspberry Pi Pico - date & time sync

Post by DWiskow » Tue Feb 02, 2021 10:31 am

more detail and a working example of how to synchronise the Raspberry Pi Pico to a host computer . . . can this now be incorporated into rshell?

Code: Select all

#!/usr/bin/env python3
#
# Vendor:Product ID for Raspberry Pi Pico is 2E8A:0005
#
# see section 4.8 RTC of https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf and in particular section 4.8.6 
# for the RTC_BASE address (0x4005C000) and details of the RD2040 setup registers used to program the RTC
#
from serial.tools import list_ports
import serial, time

picoPorts = list(list_ports.grep("2E8A:0005"))

utcTime = str( int(time.time()) )
pythonInject = [
    'import machine\r\n',
    'import utime\r\n',
    'rtc_base_mem = 0x4005c000\r\n',
    'atomic_bitmask_set = 0x2000\r\n',
    'led_onboard = machine.Pin(25, machine.Pin.OUT)\r\n',
    '(year,month,day,hour,minute,second,wday,yday)=utime.localtime('+utcTime+')'+'\r\n',
    'machine.mem32[rtc_base_mem + 4] = (year << 12) | (month  << 8) | day\r\n',
    'machine.mem32[rtc_base_mem + 8] = ((hour << 16) | (minute << 8) | second) | (((wday + 1) % 7) << 24)\r\n',
    'machine.mem32[rtc_base_mem + atomic_bitmask_set + 0xc] = 0x10\r\n',
    'for i in range(5):\r\n',
    '    led_onboard.toggle()\r\n',
    '    utime.sleep(0.03)\r\n',
    'led_onboard.value(0)\r\n'
    ]

if not picoPorts:
    print("No Raspberry Pi Pico found")
else:
    picoSerialPort = picoPorts[0].device
    with serial.Serial(picoSerialPort) as s:
        s.write(b'\x03')
        s.write(b'\x03')
        s.write(b'\x01')       
        for n in range(len(pythonInject)):
            s.write(bytes(pythonInject[n], 'ascii'))
        time.sleep(0.1) 
        s.write(b'\x04')
        s.write(b'\x02')
    print( 'Raspberry Pi Pico found at '+str(picoSerialPort)+'\r' )
    print( 'Host computer epoch synchronised over USB serial: '+utcTime+'\r' )

The above code is designed to be executed on a host computer (Windows, Mac or Linux) and will automagically find your connected Pico and then synchronise its date and time (this code requires that python3 and pyserial are installed on the host computer).

No MicroPython code needs be added or running on the Pico for this to work, but Thonny does need to closed (so as not to block the USB serial port) whilst it does it's magic

It works by injecting a small MicroPython script, which it modifies on the fly with the host computers UTC, into the Pico over the USB serial link using the RAW REPL functionality of MicroPython (kudos to rshell for some of the ideas/techniques used https://github.com/dhylands/rshell)

Oh, and the injected code generates a short pulse of the Pico on-board LED to let the user know the RTC has been synchronised :D

More information can be found on pyserial here https://pyserial.readthedocs.io/en/latest/pyserial.html. To install pyserial enter the following on the host computer command line.

Code: Select all

python -m pip install pyserial

NOTE: if code is running on the Pico, the synchronisation process will interrupt it. You can restart the code running on your Pico board using Thonny, provided you don't disconnect it from power (effectively reseting it). If you do reset the Pico, or disconnect it from power, you will need to re-sync your Pico board with a host computer again to have an accurate RTC (by default, at startup, the MicroPython interpreter running on the Pico initialises the Pico system clock to 1609459201 - Thursday, 1st January 2021 00:00:01)

This post https://www.raspberrypi.org/forums/view ... 6&t=300676 provides some more information regarding how to achieve a ‘RTC battery backup’ by attaching a battery to VSYS and GND, but it does have the disadvantage of powering the whole Pico (~ 19mA) rather than just the RTC.
Last edited by DWiskow on Wed Feb 03, 2021 6:46 am, edited 1 time in total.

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

Re: rshell & Raspberry Pi Pico - date & time sync

Post by dhylands » Tue Feb 02, 2021 10:40 pm

rshell already tries to synchronize the time on the connected device when you launch rshell.

I see that the Pico doesn't work. I'll take a look and see if I can incorporate this.

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

Re: rshell & Raspberry Pi Pico - date & time sync

Post by dhylands » Tue Feb 02, 2021 11:57 pm

The rshell pico branch: https://github.com/dhylands/rshell/tree/pico now sets the RTC on the Pico properly.

You can use rshell's date command to get the date on the host and add the -b BOARDNAME (use a BOARDNAME of pyboard by default).

So you should now see something like this:

Code: Select all

/Users/davehylands/micropython/rshell> date; date -b pyboard
Host: Tue Feb  2 15:59:20 2021
pyboard: Tue Feb  2 15:59:20 2021

DWiskow
Posts: 11
Joined: Sun Apr 24, 2016 1:23 pm

Re: rshell & Raspberry Pi Pico - date & time sync

Post by DWiskow » Wed Feb 03, 2021 6:50 am

Fantastic, thanks

minor tweak, I think line 1008 should use ‘mem32’ rather than ‘mem8’ as it is a 32bit register [this was an error in the original code I supplied, but it seemed to work irrespective]

JumpZero
Posts: 38
Joined: Mon Oct 30, 2017 5:54 am
Location: Arcachon - France

Re: rshell & Raspberry Pi Pico - date & time sync

Post by JumpZero » Wed Feb 03, 2021 12:48 pm

Excellent! Thank you

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

Re: rshell & Raspberry Pi Pico - date & time sync

Post by dhylands » Wed Feb 03, 2021 8:01 pm

DWiskow wrote:
Wed Feb 03, 2021 6:50 am
Fantastic, thanks

minor tweak, I think line 1008 should use ‘mem32’ rather than ‘mem8’ as it is a 32bit register [this was an error in the original code I supplied, but it seemed to work irrespective]
Yes - it turns out on the the pico that all registers should be accessed as 32-bits. I found this in the datasheet (2.1.4. Narrow IO Register Writes):
Memory-mapped IO registers on RP2040 ignore the width of bus read/write accesses. They treat all writes as though they
were 32 bits in size. This means software can not use byte or halfword writes to modify part of an IO register: any write to
an address where the 30 address MSBs match the register address will affect the contents of the entire register.
I've updated the rshell pico branch.

It turns out that the CTRL register is only 9 bits wide which makes the mem8 happen to work in this particular scenario. machine.mem8[addr] = 0x12 winds up being the same as machine.mem32[addr] = 0x12121212

Post Reply