Skip to content

esp32/machine_rtc: Preserve RTC user memory over most reset causes. - #7298

Merged
dpgeorge merged 1 commit into
micropython:masterfrom
karfas:pr_rtc_noinit
Dec 6, 2023
Merged

dpgeorge merged 1 commit into
micropython:masterfrom
karfas:pr_rtc_noinit

Conversation

@karfas

@karfas karfas commented May 22, 2021

Copy link
Copy Markdown

ESP32: New compile-time #define allowing to preserve the RTC slow memory during most resets.

Usage:

#define MICROPY_HW_RTC_USER_MEM_NOINIT

e.g. in port/esp32/board/XXX/mpconfigboard.h

When above is defined, the user memory area - accessible by machine.RTC.memory() will survive most reboot causes. A power-on reset (also caused by the EN pin on some boards) will clean the memory. When this happens, the magic number not found in the user memory will cause initialization.

After other resets (triggered by watchdogs, machine.reset(), ...), the user is responsible to check and validate the contents of the user area.

@robert-hh

Copy link
Copy Markdown
Contributor

Obviously RTC memory will survive a power cycle only if the RTC domain is supplied by a battery. And pulling the EN pin causes a power cycle.

@karfas

karfas commented Apr 26, 2022

Copy link
Copy Markdown
Author

@dpgeorge: This is now almost a year old.
It's a very small change and doesn't change anything in the absence of the #define above.
Maybe you find time for a review ?

@mzakharo

mzakharo commented May 2, 2022 •

Copy link
Copy Markdown
Contributor

This change crashes the microcontroller for me when MICROPY_HW_RTC_USER_MEM_NOINIT is defined and RTC().memory() is accessed. I noticed that init() is not called when RTC() object is created. To avoid the crash on uninitialized memory, RTC().init(datetime) must be called first. Maybe 'MAGIC' check should be moved to new()/ojbect creation instead?

@karfas

karfas commented May 11, 2022 •

Copy link
Copy Markdown
Author

This change crashes the microcontroller for me when MICROPY_HW_RTC_USER_MEM_NOINIT is defined and RTC().memory() is accessed. I noticed that init() is not called when RTC() object is created. To avoid the crash on uninitialized memory, RTC().init(datetime) must be called first. Maybe 'MAGIC' check should be moved to new()/ojbect creation instead?

You are right. Obviously this is a bug coming to light when the user memory is not initialized.
The magic number in the memory is also not set without MICROPY_HW_RTC_USER_MEM_NOINIT, but there it doesn't cause any harm as the memory gets cleaned at startup.

@karfas
karfas force-pushed the pr_rtc_noinit branch 2 times, most recently from 8439a9f to 1598de5 Compare May 14, 2022 19:46
@karfas

karfas commented May 14, 2022

Copy link
Copy Markdown
Author

This is fixed by now.
My Program to test:

import machine
import time
from machine import RTC
from machine import WDT

text = {
    machine.DEEPSLEEP_RESET: "DEEP_SLEEP_RESET",
    machine.PWRON_RESET: "PWRON_RESET",
    machine.HARD_RESET: "HARD_RESET",
    machine.WDT_RESET: "WDT_RESET",
    machine.SOFT_RESET: "SOFT_RESET"
    }
print("Reset cause: {}".format(text.get(machine.reset_cause(), "???")) )

if machine.reset_cause() == machine.PWRON_RESET:
    RTC().memory('Hello, World')
    print("set RTC.memory(): {}".format(RTC().memory()) )
    machine.reset()
if machine.reset_cause() == machine.HARD_RESET:
    print("RTC.memory(): {}".format(RTC().memory()) )
    wdt = WDT(timeout=1000)  # enable it with a timeout of 1s
if machine.reset_cause() == machine.WDT_RESET:
    print("RTC.memory(): {}".format(RTC().memory()) )

gives me the output (edited for clarity)

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
...
Reset cause: PWRON_RESET
set RTC.memory(): b'Hello, World'
...
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
...
Reset cause: HARD_RESET
RTC.memory(): b'Hello, World'
MicroPython v1.18 ... 
Type "help()" for more information.
>>> E (6611) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
....
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
...
Reset cause: WDT_RESET
RTC.memory(): b'Hello, World'
MicroPython v1.18 ...
Type "help()" for more information.

tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Dec 6, 2022
…n-main

Translations update from Hosted Weblate
@karfas

karfas commented Apr 23, 2023

Copy link
Copy Markdown
Author

@jimmo, @dpgeorge: This is now almost two years old.
It's a very small change and doesn't change anything in the absence of the #define above.
Maybe you find time for a review ?

@dpgeorge

dpgeorge commented Dec 4, 2023

Copy link
Copy Markdown
Member

Sorry that this didn't get any attention for so long.

It looks good! But how about just enabling this new behaviour by default? Ie no need for the new config option MICROPY_HW_RTC_USER_MEM_NOINIT, just always use the RTC_NOINIT_ATTR attribute.

@karfas

karfas commented Dec 4, 2023

Copy link
Copy Markdown
Author

But how about just enabling this new behaviour by default?

As far as I remember was the idea to allow the (compiling) user to enable this feature when required, so all applications relying on an empty RTC.memory() regardless of the reset cause will work like before.

However, in the next 2-3 daysI I could add a MICROPY_HW_RTC_USER_MEM_BOOT_CLEAN option or similar (defaulting to false), so the user can at least disable this feature.

@karfas
karfas force-pushed the pr_rtc_noinit branch 2 times, most recently from 2d47cab to 5cf1eeb Compare December 5, 2023 21:59
@karfas

karfas commented Dec 5, 2023

Copy link
Copy Markdown
Author

Now we have a new (optional) #define MICROPY_HW_RTC_MEM_INIT_ALWAYS to clean the RTC memory on boot (like before this PR).

The user memory area - accessible by machine.RTC.memory() -- will now
survive most reboot causes.  A power-on reset (also caused by the EN pin on
some boards) will clean the memory.  When this happens, the magic number
not found in the user memory will cause initialization.

After other resets (triggered by watchdogs, machine.reset(), ...), the user
is responsible to check and validate the contents of the user area.

This new behaviour can be changed by enabling
MICROPY_HW_RTC_MEM_INIT_ALWAYS: in that case the RTC memory is always
cleared on boot.

Signed-off-by: Thomas Wenrich <[email protected]>
@dpgeorge
dpgeorge merged commit 78b3fe5 into micropython:master Dec 6, 2023
@dpgeorge

dpgeorge commented Dec 6, 2023

Copy link
Copy Markdown
Member

Thanks for updating. I tested this and it works well.

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants