DS3231 reset to 01-01-2021 00:00:00

I have loaded a program (time.py) in Thonny showing the right current time got from a time module DS3231. This module is connected on a Pimoroni Explorer Base with a Pi Pico W
Then I have uploaded this program from Thonny to the Pi Pico W as main.py.
Then I disconnect the USB cable out of the Pimoroni Explorer Base and connected the cable again. Then the time was showed as 01-01-2021 00:00:00 (h,m,s).
Then I closed time.py in Thonny and opened main.py from the Pi Pico in Thonny.
USB cable still connected.
Then I clicked on the green start button in Thonny to execute main.py and now the showed time is the right current time.
The battery in the DS3231 is a rechargeable LIR2032. It’s voltage is 4.1V. The Vcc of the DS3231 is connected to the 3.3 V on the explorer base module.
I hoped to run the explorer base with a usb cable connected to a Solar Power Bank. But as written, the time then starts at 01-01-2021 00:00:00 after a disconnect..
Is there a solution for this issue?

Could you post your time.py code? Use the Preformatted Text option </> to wrap it in code tags. It sounds like your time.py is reading the time from the Pico’s onboard RTC, not the DS3231. The Pico’s RTC gets reset any time it looses power or you reset the Pico. Keep in mind that Thonny will sync the time from the host machine to the Pico’s RTC in the background when you connect to the Pico.

I use RV3028’s on my Pico’s. For me it goes something like this.

from pimoroni_i2c import PimoroniI2C
i2c = PimoroniI2C(sda=(0), scl=(1)) # this varies depending on the pack used etc
from breakout_rtc import BreakoutRTC
from machine import RTC
RV3028 = BreakoutRTC(i2c)
rtc = BreakoutRTC(i2c)

Another option is to sync the Pico’s RTC to the DS3231. The following is what I would use for my RV3028. I won’t normally go this route, it’s easier to just use the RV3028 as my RTC and ignore the one on the Pico.

"""
Drop this function into your code to set your board's time/date from your RV3028 RTC breakout!
"""


def set_pico_time():
    # the function sets the Pico's RTC from a RV3028 RTC breakout
    # to setup breakout (and set the time) run this first:
    # https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/breakout_rtc/set-time.py
    from pimoroni_i2c import PimoroniI2C
    from breakout_rtc import BreakoutRTC
    from machine import RTC

    # set up I2C
    PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}  # i2c pins 4, 5 for Breakout Garden
    # for boards that use the alternate I2C pins use the line below instead
    # PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}  # Default i2c pins for Pico Explorer

    i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
    # for boards that use the alternate I2C pins use the line below instead
    # i2c = PimoroniI2C(**PINS_PICO_EXPLORER)

    # set up the RTC breakout
    RV3028 = BreakoutRTC(i2c)

    # set the Pico's RTC from the RTC breakout
    RV3028.update_time()
    RTC().datetime([RV3028.get_year(), RV3028.get_month(), RV3028.get_date(),
                    RV3028.get_weekday(), RV3028.get_hours(), RV3028.get_minutes(),
                    RV3028.get_seconds(), 0])
    print(f"Pico RTC set to breakout time: {RV3028.string_date()} {RV3028.string_time()}")


# call the function
set_pico_time()

Regarding the RTC, @alphanumeric has given all the relevant information. One addition though: AFAIK Thonny automagically updates the device RTC. I think this is not really helpful in your context, since you can be fooled that everything is ok. Maybe Thonny has an option to disable this feature (worth a try). Otherwise, connect with a dumb terminal program to make sure everything runs as expected.

This is off-topic, but maybe you could also post an image (or link) of your solar power bank. This might not be the solution you really want/need, but it depends on what you have.

The project time.py is printed below:


# The original project is from https://RandomNerdTutorials.com/raspberry-pi-pico-ds3231-rtc-micropython/
# In that project the Pi Pico stays connected to the pc and is executed from Thonny and
# the date and time are printed in the shell.
# Only the urtc.py library is uploaded to the Pi Pico (W)
# Now the original project is modified such that it runs on a Pimoroni Explorer Base with the possibility
# to show the date and time on the Pimoroni display.
# The next step is to upload this modified project as main.py to the Pi Pico
# to run it as a stand alone module with external power (e.g. Solar Power Bank)

import time
import urtc
from machine import I2C, Pin, SPI
from picographics import PicoGraphics, DISPLAY_PICO_EXPLORER, PEN_P4

display = PicoGraphics(display=DISPLAY_PICO_EXPLORER, pen_type=PEN_P4)

WHITE = display.create_pen(255, 255, 255)
BLACK = display.create_pen(0, 0, 0)

# Clear display
display.set_pen(BLACK)
display.clear()
display.update()

my_pen = display.create_pen(255, 0, 0) # RED color
display.set_pen(my_pen)

days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

# Initialize RTC (connected to I2C)
i2c = I2C(0, scl=Pin(21), sda=Pin(20))
rtc = urtc.DS3231(i2c)

# Set the current time using a specified time tuple
# Time tuple: (year, month, day, day of week, hour, minute, seconds, milliseconds)
#initial_time = (2024, 1, 30, 1, 12, 30, 0, 0)

# Or get the local time from the system
initial_time_tuple = time.localtime()  # tuple (microPython)
initial_time_seconds = time.mktime(initial_time_tuple)  # local time in seconds

# Convert to tuple compatible with the library
initial_time = urtc.seconds2tuple(initial_time_seconds)

# Sync the RTC
rtc.datetime(initial_time)

while True:
    current_datetime = rtc.datetime()
    
    # Erase area before new data is written to display
    display.set_pen(BLACK)                
    display.rectangle(50, 50, 80, 120)
 
    # Display time details
    display.set_pen(WHITE)
    display.text(str(current_datetime.year), 50, 50, scale=2)
    display.text(str(current_datetime.month), 50, 70, scale=2)
    display.text(str(current_datetime.day), 50, 90, scale=2)
    display.text(str(current_datetime.hour), 50, 110, scale=2)
    display.text(str(current_datetime.minute), 50, 130, scale=2)
    display.text(str(current_datetime.second), 50, 150, scale=2)
    display.update()
    
    # Format the date and time
    formatted_datetime = (
        f"{days_of_week[current_datetime.weekday]}, " +
        f"{current_datetime.year:04d}-{current_datetime.month:02d}-{current_datetime.day:02d} " +
        f"{current_datetime.hour:02d}:{current_datetime.minute:02d}:{current_datetime.second:02d} "
    )
    print(f"Current date and time: {formatted_datetime}")
    
    print(" \n");
    time.sleep(1)

I am wondering what the usefulness of the back up battery is.
I thought if the right time is written into the DS3231 time module from the system and you disconnect the PI Pico with the DS3231 time module and connect it to a separate supply that the battery ensures that the current time in the DS3231 is not lost.

Your logic error: on every start you sync the time of the Pico to the DS3231. You can only do this when running within Thonny.

The DS3231 will retain the time due to the battery. I think you have some code in the run once section that doesn’t need to be there.

# Or get the local time from the system
initial_time_tuple = time.localtime()  # tuple (microPython)
initial_time_seconds = time.mktime(initial_time_tuple)  # local time in seconds

# Convert to tuple compatible with the library
initial_time = urtc.seconds2tuple(initial_time_seconds)

# Sync the RTC
rtc.datetime(initial_time)

Once the DS3231 is set it’s set, you don’t need to keep doing it over and over.
Local time from the system is going to be the Pico RTC which is going to be 01-01-2021 00:00:00 after a disconnect. Near as I can tell your code is writing that back into the DS3231.
Once the DS3231 is set, you read it and only it in your code for time reference. I think I got that right, 5:30 AM here, only just got up and had 1 cup of Java. ;)

I usually read the RTC (in this case the DS3231) and check if the time is “ok” using a heuristic. If not, I first try to update the device RTC from a time-source (e.g. NTP or worldtimeapi.org) and then update the RTC from the device RTC.

Most of my setups aren’t time critical. I show the local time and don’t display the seconds. The only time I go in and reset them is when the clocks go back or forward due to Daylight Savings Time. They aren’t connected to my WIFI. I’m just too lazy to take it to the next level and have them all auto correct on the fly.

It’s this line that I have to comment as soon as the right time is in the DS3231.
Then I save that time.py as main.py in the PI Pico.
When that is done and I remove the supply from the Explorer Base and reconnect then the right time is still there.

Your sentence:
“I think you have some code in the run once section that doesn’t need to be there.” gave me this idea.
Learned something again.
Problem solved.

1 Like

Nice, now you can move on to the next problem. :)
I say that tongue in cheek, as that’s the way it usually goes for me. =)