summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/samd/Makefile1
-rw-r--r--ports/samd/fatfs_port.c6
-rw-r--r--ports/samd/machine_rtc.c181
-rw-r--r--ports/samd/mcu/samd21/clock_config.c17
-rw-r--r--ports/samd/mcu/samd21/mpconfigmcu.h6
-rw-r--r--ports/samd/mcu/samd51/clock_config.c20
-rw-r--r--ports/samd/mcu/samd51/mpconfigmcu.h6
-rw-r--r--ports/samd/modmachine.c3
-rw-r--r--ports/samd/modmachine.h3
-rw-r--r--ports/samd/modutime.c30
-rw-r--r--ports/samd/samd_soc.c7
11 files changed, 263 insertions, 17 deletions
diff --git a/ports/samd/Makefile b/ports/samd/Makefile
index abec4e83a..e6e592a03 100644
--- a/ports/samd/Makefile
+++ b/ports/samd/Makefile
@@ -94,6 +94,7 @@ SRC_C += \
machine_i2c.c \
machine_led.c \
machine_pin.c \
+ machine_rtc.c \
machine_spi.c \
machine_timer.c \
machine_uart.c \
diff --git a/ports/samd/fatfs_port.c b/ports/samd/fatfs_port.c
index 9ee1764eb..a3e3f1b67 100644
--- a/ports/samd/fatfs_port.c
+++ b/ports/samd/fatfs_port.c
@@ -33,9 +33,13 @@
extern uint32_t time_offset;
MP_WEAK DWORD get_fattime(void) {
+ #if MICROPY_PY_MACHINE_RTC
+ return (RTC->MODE2.CLOCK.reg >> 1) + (20 << 25);
+ #else
+ extern void rtc_gettime(timeutils_struct_time_t *tm);
timeutils_struct_time_t tm;
-
timeutils_seconds_since_epoch_to_struct_time(mp_hal_ticks_ms_64() / 1000 + time_offset, &tm);
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) | ((tm.tm_mday) << 16) |
((tm.tm_hour) << 11) | ((tm.tm_min) << 5) | (tm.tm_sec / 2);
+ #endif
}
diff --git a/ports/samd/machine_rtc.c b/ports/samd/machine_rtc.c
new file mode 100644
index 000000000..57bfa998e
--- /dev/null
+++ b/ports/samd/machine_rtc.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Damien P. George
+ * Copyright (c) 2022 "Robert Hammelrath" <robert@hammelrath.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "shared/timeutils/timeutils.h"
+#include "modmachine.h"
+#include "py/mphal.h"
+#include "sam.h"
+
+#if MICROPY_PY_MACHINE_RTC
+
+typedef struct _machine_rtc_obj_t {
+ mp_obj_base_t base;
+ mp_obj_t callback;
+} machine_rtc_obj_t;
+
+// Singleton RTC object.
+STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
+
+// Start the RTC Timer.
+void machine_rtc_start(bool force) {
+ #if defined(MCU_SAMD21)
+
+ if (RTC->MODE2.CTRL.bit.ENABLE == 0 || force) {
+ // Enable the 1k Clock
+ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK8 | GCLK_CLKCTRL_ID_RTC;
+
+ RTC->MODE2.CTRL.reg = RTC_MODE2_CTRL_SWRST;
+ while (RTC->MODE2.STATUS.bit.SYNCBUSY) {
+ }
+ RTC->MODE2.CTRL.reg =
+ RTC_MODE2_CTRL_MODE_CLOCK |
+ RTC_MODE2_CTRL_PRESCALER_DIV1024 |
+ RTC_MODE2_CTRL_ENABLE;
+ while (RTC->MODE2.STATUS.bit.SYNCBUSY) {
+ }
+ }
+
+ #elif defined(MCU_SAMD51)
+
+ if (RTC->MODE2.CTRLA.bit.ENABLE == 0 || force) {
+ RTC->MODE2.CTRLA.reg = RTC_MODE2_CTRLA_SWRST;
+ while (RTC->MODE2.SYNCBUSY.bit.SWRST) {
+ }
+ RTC->MODE2.CTRLA.reg =
+ RTC_MODE2_CTRLA_MODE_CLOCK |
+ RTC_MODE2_CTRLA_CLOCKSYNC |
+ RTC_MODE2_CTRLA_PRESCALER_DIV1024 |
+ RTC_MODE2_CTRLA_ENABLE;
+ while (RTC->MODE2.SYNCBUSY.bit.ENABLE) {
+ }
+ }
+ #endif
+}
+
+// Get the time from the RTC and put it into a tm struct.
+void rtc_gettime(timeutils_struct_time_t *tm) {
+ tm->tm_year = RTC->MODE2.CLOCK.bit.YEAR + 2000;
+ tm->tm_mon = RTC->MODE2.CLOCK.bit.MONTH;
+ tm->tm_mday = RTC->MODE2.CLOCK.bit.DAY;
+ tm->tm_hour = RTC->MODE2.CLOCK.bit.HOUR;
+ tm->tm_min = RTC->MODE2.CLOCK.bit.MINUTE;
+ tm->tm_sec = RTC->MODE2.CLOCK.bit.SECOND;
+}
+
+STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // Check arguments.
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ // RTC was already started at boot time. So nothing to do here.
+ // Return constant object.
+ return (mp_obj_t)&machine_rtc_obj;
+}
+
+STATIC mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args) {
+ // Rtc *rtc = RTC;
+ if (n_args == 1) {
+ // Get date and time.
+ timeutils_struct_time_t tm;
+ rtc_gettime(&tm);
+
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(tm.tm_year),
+ mp_obj_new_int(tm.tm_mon),
+ mp_obj_new_int(tm.tm_mday),
+ mp_obj_new_int(timeutils_calc_weekday(tm.tm_year, tm.tm_mon, tm.tm_mday)),
+ mp_obj_new_int(tm.tm_hour),
+ mp_obj_new_int(tm.tm_min),
+ mp_obj_new_int(tm.tm_sec),
+ mp_obj_new_int(0),
+ };
+ return mp_obj_new_tuple(8, tuple);
+ } else {
+ // Set date and time.
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 8, &items);
+
+ uint32_t date =
+ RTC_MODE2_CLOCK_YEAR(mp_obj_get_int(items[0]) % 100) |
+ RTC_MODE2_CLOCK_MONTH(mp_obj_get_int(items[1])) |
+ RTC_MODE2_CLOCK_DAY(mp_obj_get_int(items[2])) |
+ RTC_MODE2_CLOCK_HOUR(mp_obj_get_int(items[4])) |
+ RTC_MODE2_CLOCK_MINUTE(mp_obj_get_int(items[5])) |
+ RTC_MODE2_CLOCK_SECOND(mp_obj_get_int(items[6]));
+
+ RTC->MODE2.CLOCK.reg = date;
+ #if defined(MCU_SAMD21)
+ while (RTC->MODE2.STATUS.bit.SYNCBUSY) {
+ }
+ #elif defined(MCU_SAMD51)
+ while (RTC->MODE2.SYNCBUSY.bit.CLOCKSYNC) {
+ }
+ #endif
+
+ return mp_const_none;
+ }
+}
+
+STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
+ return machine_rtc_datetime_helper(n_args, args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
+
+STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
+ mp_obj_t args[2] = {self_in, date};
+ machine_rtc_datetime_helper(2, args);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
+
+// calibration(cal)
+// When the argument is a number in the range [-16 to 15], set the calibration value.
+STATIC mp_obj_t machine_rtc_calibration(mp_obj_t self_in, mp_obj_t cal_in) {
+ int8_t cal = 0;
+ // Make it negative for a "natural" behavior:
+ // value > 0: faster, value < 0: slower
+ cal = -mp_obj_get_int(cal_in);
+ RTC->MODE2.FREQCORR.reg = (uint8_t)cal;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_calibration_obj, machine_rtc_calibration);
+
+STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&machine_rtc_calibration_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ machine_rtc_type,
+ MP_QSTR_RTC,
+ MP_TYPE_FLAG_NONE,
+ make_new, machine_rtc_make_new,
+ locals_dict, &machine_rtc_locals_dict
+ );
+
+#endif // MICROPY_PY_MACHINE_RTC
diff --git a/ports/samd/mcu/samd21/clock_config.c b/ports/samd/mcu/samd21/clock_config.c
index a195cb692..00f743cc4 100644
--- a/ports/samd/mcu/samd21/clock_config.c
+++ b/ports/samd/mcu/samd21/clock_config.c
@@ -141,7 +141,7 @@ void init_clocks(uint32_t cpu_freq) {
// GCLK3: 1Mhz for the us-counter (TC4/TC5)
// GCLK4: 32kHz from crystal, if present
// GCLK5: 48MHz from DFLL for USB
- // GCLK8: 1kHz clock for WDT
+ // GCLK8: 1kHz clock for WDT and RTC
NVMCTRL->CTRLB.bit.MANW = 1; // errata "Spurious Writes"
NVMCTRL->CTRLB.bit.RWS = 1; // 1 read wait state for 48MHz
@@ -203,6 +203,11 @@ void init_clocks(uint32_t cpu_freq) {
SYSCTRL_DFLLCTRL_BPLCKC | SYSCTRL_DFLLCTRL_ENABLE;
while (SYSCTRL->PCLKSR.bit.DFLLLCKF == 0) {
}
+ // Set GCLK8 to 1 kHz.
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(8);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
#else // MICROPY_HW_XOSC32K
@@ -242,6 +247,11 @@ void init_clocks(uint32_t cpu_freq) {
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(1);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
+ // Set GCLK8 to 1 kHz.
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
#endif // MICROPY_HW_XOSC32K
@@ -252,11 +262,6 @@ void init_clocks(uint32_t cpu_freq) {
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(3);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
- // Set GCLK8 to 1 kHz.
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
- GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);
- while (GCLK->STATUS.bit.SYNCBUSY) {
- }
}
void enable_sercom_clock(int id) {
diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h
index 8d155f93a..331df8e21 100644
--- a/ports/samd/mcu/samd21/mpconfigmcu.h
+++ b/ports/samd/mcu/samd21/mpconfigmcu.h
@@ -28,6 +28,12 @@
#define MICROPY_HW_UART_TXBUF (1)
#endif
+#ifndef MICROPY_PY_MACHINE_RTC
+#if MICROPY_HW_XOSC32K
+#define MICROPY_PY_MACHINE_RTC (1)
+#endif
+#endif
+
#define CPU_FREQ (48000000)
#define DFLL48M_FREQ (48000000)
#define MAX_CPU_FREQ (48000000)
diff --git a/ports/samd/mcu/samd51/clock_config.c b/ports/samd/mcu/samd51/clock_config.c
index 3bc4616de..c5f508cae 100644
--- a/ports/samd/mcu/samd51/clock_config.c
+++ b/ports/samd/mcu/samd51/clock_config.c
@@ -215,16 +215,19 @@ void init_clocks(uint32_t cpu_freq) {
#if MICROPY_HW_XOSC32K
// OSCILLATOR CONTROL
+ // Enable the clock for RTC
+ OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K;
// Setup XOSC32K
OSC32KCTRL->INTFLAG.reg = OSC32KCTRL_INTFLAG_XOSC32KRDY | OSC32KCTRL_INTFLAG_XOSC32KFAIL;
- OSC32KCTRL->XOSC32K.bit.CGM = OSC32KCTRL_XOSC32K_CGM_HS_Val;
- OSC32KCTRL->XOSC32K.bit.XTALEN = 1; // 0: Generator 1: Crystal
- OSC32KCTRL->XOSC32K.bit.EN32K = 1;
- OSC32KCTRL->XOSC32K.bit.ONDEMAND = 0;
- OSC32KCTRL->XOSC32K.bit.RUNSTDBY = 1;
- OSC32KCTRL->XOSC32K.bit.STARTUP = 4;
OSC32KCTRL->CFDCTRL.bit.CFDEN = 1; // Fall back to internal Osc on crystal fail
- OSC32KCTRL->XOSC32K.bit.ENABLE = 1;
+ OSC32KCTRL->XOSC32K.reg =
+ OSC32KCTRL_XOSC32K_CGM_HS |
+ OSC32KCTRL_XOSC32K_XTALEN |
+ OSC32KCTRL_XOSC32K_EN32K |
+ OSC32KCTRL_XOSC32K_EN1K |
+ OSC32KCTRL_XOSC32K_RUNSTDBY |
+ OSC32KCTRL_XOSC32K_STARTUP(4) |
+ OSC32KCTRL_XOSC32K_ENABLE;
// make sure osc32kcrtl is ready
while (OSC32KCTRL->STATUS.bit.XOSC32KRDY == 0) {
}
@@ -270,6 +273,9 @@ void init_clocks(uint32_t cpu_freq) {
#else // MICROPY_HW_XOSC32K
+ // Enable the clock for RTC
+ OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K;
+
// Derive GCLK1 from DFLL48M at DPLL0_REF_FREQ as defined in mpconfigboard.h (e.g. 32768 Hz)
GCLK->GENCTRL[1].reg = ((DFLL48M_FREQ + DPLLx_REF_FREQ / 2) / DPLLx_REF_FREQ) << GCLK_GENCTRL_DIV_Pos
| GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h
index 666370c98..541fba900 100644
--- a/ports/samd/mcu/samd51/mpconfigmcu.h
+++ b/ports/samd/mcu/samd51/mpconfigmcu.h
@@ -28,6 +28,12 @@
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
unsigned long trng_random_u32(void);
+#ifndef MICROPY_PY_MACHINE_RTC
+#if MICROPY_HW_XOSC32K
+#define MICROPY_PY_MACHINE_RTC (1)
+#endif
+#endif
+
// Due to a limitation in the TC counter for us, the ticks period is 2**29
#define MICROPY_PY_UTIME_TICKS_PERIOD (0x20000000)
diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c
index ce5fef76f..12e9f7c34 100644
--- a/ports/samd/modmachine.c
+++ b/ports/samd/modmachine.c
@@ -238,6 +238,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
+ #if MICROPY_PY_MACHINE_RTC
+ { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
diff --git a/ports/samd/modmachine.h b/ports/samd/modmachine.h
index e99ca990f..8f85e1498 100644
--- a/ports/samd/modmachine.h
+++ b/ports/samd/modmachine.h
@@ -38,5 +38,8 @@ extern const mp_obj_type_t machine_spi_type;
extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_wdt_type;
+#if MICROPY_PY_MACHINE_RTC
+extern const mp_obj_type_t machine_rtc_type;
+#endif
#endif // MICROPY_INCLUDED_SAMD_MODMACHINE_H
diff --git a/ports/samd/modutime.c b/ports/samd/modutime.c
index 4169c15d9..6b0413449 100644
--- a/ports/samd/modutime.c
+++ b/ports/samd/modutime.c
@@ -29,20 +29,34 @@
#include "shared/timeutils/timeutils.h"
#include "mphalport.h"
+#if !MICROPY_PY_MACHINE_RTC
uint32_t time_offset = 0;
+#endif // !MICROPY_PY_MACHINE_RTC
// localtime([secs])
STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
timeutils_struct_time_t tm;
mp_int_t seconds;
+
+ #if MICROPY_PY_MACHINE_RTC
+ extern void rtc_gettime(timeutils_struct_time_t *tm);
+ if (n_args == 0 || args[0] == mp_const_none) {
+ rtc_gettime(&tm);
+ } else {
+ seconds = mp_obj_get_int(args[0]);
+ timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
+ }
+
+ #else
if (n_args == 0 || args[0] == mp_const_none) {
- // seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000;
seconds = mp_hal_ticks_ms_64() / 1000 + time_offset;
} else {
seconds = mp_obj_get_int(args[0]);
time_offset = seconds - mp_hal_ticks_ms_64() / 1000;
}
timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
+
+ #endif // MICROPY_PY_MACHINE_RTC
mp_obj_t tuple[8] = {
tuple[0] = mp_obj_new_int(tm.tm_year),
tuple[1] = mp_obj_new_int(tm.tm_mon),
@@ -50,8 +64,8 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
tuple[3] = mp_obj_new_int(tm.tm_hour),
tuple[4] = mp_obj_new_int(tm.tm_min),
tuple[5] = mp_obj_new_int(tm.tm_sec),
- tuple[6] = mp_obj_new_int(tm.tm_wday),
- tuple[7] = mp_obj_new_int(tm.tm_yday),
+ tuple[6] = mp_obj_new_int(timeutils_calc_weekday(tm.tm_year, tm.tm_mon, tm.tm_mday)),
+ tuple[7] = mp_obj_new_int(timeutils_year_day(tm.tm_year, tm.tm_mon, tm.tm_mday)),
};
return mp_obj_new_tuple(8, tuple);
}
@@ -76,7 +90,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
// time()
STATIC mp_obj_t time_time(void) {
+ #if MICROPY_PY_MACHINE_RTC
+ extern void rtc_gettime(timeutils_struct_time_t *tm);
+ timeutils_struct_time_t tm;
+ rtc_gettime(&tm);
+ return mp_obj_new_int_from_uint(timeutils_mktime(
+ tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec));
+
+ #else
return mp_obj_new_int_from_uint(mp_hal_ticks_ms_64() / 1000 + time_offset);
+
+ #endif // MICROPY_PY_MACHINE_RTC
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c
index 3608306e8..bd3eea536 100644
--- a/ports/samd/samd_soc.c
+++ b/ports/samd/samd_soc.c
@@ -38,6 +38,10 @@
#include "tusb.h"
#include "mphalport.h"
+#if MICROPY_PY_MACHINE_RTC
+extern void machine_rtc_start(bool force);
+#endif
+
static void usb_init(void) {
// Init USB clock
#if defined(MCU_SAMD21)
@@ -114,4 +118,7 @@ void samd_init(void) {
#if defined(MCU_SAMD51)
mp_hal_ticks_cpu_enable();
#endif
+ #if MICROPY_PY_MACHINE_RTC
+ machine_rtc_start(false);
+ #endif
}