Skip to content

ports/nrf: Add RTC support to NRF ports. #14198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ports/nrf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ DRIVERS_SRC_C += $(addprefix modules/,\
machine/pin.c \
machine/timer.c \
machine/rtcounter.c \
machine/rtc.c \
machine/temp.c \
os/microbitfs.c \
board/modboard.c \
Expand Down
51 changes: 51 additions & 0 deletions ports/nrf/modtime.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Damien P. George
*
* 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/obj.h"
#include "shared/timeutils/timeutils.h"
#include "ports/nrf/modules/machine/rtc.h"

// Return the localtime as an 8-tuple.
static mp_obj_t mp_time_localtime_get(void) {
mp_int_t seconds = ticks_ms_64() / 1000;
timeutils_struct_time_t tm;
timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
tuple[0] = mp_obj_new_int(tm.tm_year),
tuple[1] = mp_obj_new_int(tm.tm_mon),
tuple[2] = mp_obj_new_int(tm.tm_mday),
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),
};
return mp_obj_new_tuple(8, tuple);
}

static mp_obj_t mp_time_time_get(void) {
return mp_obj_new_int((ticks_ms_64() + rtc_offset[1]) / 1000);
}
6 changes: 6 additions & 0 deletions ports/nrf/modules/machine/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
#define MICROPY_PY_MACHINE_RTCOUNTER_ENTRY
#endif

#if MICROPY_PY_MACHINE_RTC
#define MICROPY_PY_MACHINE_RTC_ENTRY { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
#else
#define MICROPY_PY_MACHINE_RTC_ENTRY
#endif

#if MICROPY_PY_MACHINE_TIMER_NRF
#define MICROPY_PY_MACHINE_TIMER_ENTRY { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
#else
Expand Down
4 changes: 4 additions & 0 deletions ports/nrf/modules/machine/modmachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@

#include "py/obj.h"

#if MICROPY_PY_MACHINE_RTC
extern const mp_obj_type_t machine_rtc_type;
#endif

void machine_init(void);

#endif // __MICROPY_INCLUDED_NRF5_MODMACHINE_H__
144 changes: 144 additions & 0 deletions ports/nrf/modules/machine/rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Nick Moore for Adafruit Industries
* Copyright (c) 2021 "Krzysztof Adamski" <k@japko.eu>
*
* 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 "modmachine.h"

#if MICROPY_PY_MACHINE_RTC

#include "py/mphal.h"
#include "shared/timeutils/timeutils.h"
#include "rtc.h"


// These values are placed before and after the current RTC count. They are
// used to determine if the RTC count is valid. These randomly-generated values
// will be set when the RTC value is set in order to mark the RTC as valid. If
// the system crashes or reboots, these values will remain undisturbed and the
// RTC offset will remain valid.
//
// If MicroPython is updated or these symbols shift around, the prefix and
// suffix will no longer match, and the time will no longer be valid.
#define RTC_OFFSET_CHECK_PREFIX 0x25ea7e2a
#define RTC_OFFSET_CHECK_SUFFIX 0x2b80b69e

void rtc_offset_check(void) {
// If the prefix and suffix are not valid, zero-initialize the RTC offset.
if ((rtc_offset[0] != RTC_OFFSET_CHECK_PREFIX) || (rtc_offset[2] != RTC_OFFSET_CHECK_SUFFIX)) {
rtc_offset[1] = 0;
}
}

void rtc_get_time(timeutils_struct_time_t *tm) {
uint64_t ticks_s = ticks_ms_64() / 1000;
timeutils_seconds_since_2000_to_struct_time(rtc_offset[1] + ticks_s, tm);
}

void rtc_set_time(timeutils_struct_time_t *tm) {
uint64_t ticks_s = ticks_ms_64() / 1000;
uint32_t epoch_s = timeutils_seconds_since_2000(
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec
);
rtc_offset[1] = epoch_s - ticks_s;

// Set the prefix and suffix in order to indicate the time is valid. This
// must be done after the offset is updated, in case there is a crash or
// power failure.
rtc_offset[0] = RTC_OFFSET_CHECK_PREFIX;
rtc_offset[2] = RTC_OFFSET_CHECK_SUFFIX;
}

typedef struct _machine_rtc_obj_t {
mp_obj_base_t base;
} machine_rtc_obj_t;

// singleton RTC object
static const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};

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);

// return constant object
return (mp_obj_t)&machine_rtc_obj;
}

static mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
timeutils_struct_time_t t;

rtc_get_time(&t);

mp_obj_t tuple[8] = {
mp_obj_new_int(t.tm_year),
mp_obj_new_int(t.tm_mon),
mp_obj_new_int(t.tm_mday),
mp_obj_new_int(t.tm_wday),
mp_obj_new_int(t.tm_hour),
mp_obj_new_int(t.tm_min),
mp_obj_new_int(t.tm_sec),
mp_obj_new_int(0)
};

return mp_obj_new_tuple(8, tuple);
} else {
mp_obj_t *items;

mp_obj_get_array_fixed_n(args[1], 8, &items);

timeutils_struct_time_t t = {
.tm_year = mp_obj_get_int(items[0]),
.tm_mon = mp_obj_get_int(items[1]),
.tm_mday = mp_obj_get_int(items[2]),
.tm_hour = mp_obj_get_int(items[4]),
.tm_min = mp_obj_get_int(items[5]),
.tm_sec = mp_obj_get_int(items[6]),
};
// Deliberately ignore the weekday argument and compute the proper value
t.tm_wday = timeutils_calc_weekday(t.tm_year, t.tm_mon, t.tm_mday);

rtc_set_time(&t);

}
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);

static const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_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
4 changes: 4 additions & 0 deletions ports/nrf/modules/machine/rtc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extern uint64_t ticks_ms_64(void);

// This is the time in seconds since 2000 that the RTC was started.
__attribute__((section(".uninitialized"))) static uint32_t rtc_offset[3];
16 changes: 16 additions & 0 deletions ports/nrf/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,26 @@
#define MICROPY_PY_MACHINE_RTCOUNTER (0)
#endif

#ifndef MICROPY_PY_MACHINE_RTC
#define MICROPY_PY_MACHINE_RTC (1)
#endif

#ifndef MICROPY_PY_TIME_TICKS
#define MICROPY_PY_TIME_TICKS (1)
#endif

#ifndef MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME
#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
#endif

#ifndef MICROPY_PY_TIME_TIME_TIME_NS
#define MICROPY_PY_TIME_TIME_TIME_NS (1)
#endif

#ifndef MICROPY_PY_TIME_INCLUDEFILE
#define MICROPY_PY_TIME_INCLUDEFILE "ports/nrf/modtime.c"
#endif

#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)

Expand Down
10 changes: 7 additions & 3 deletions ports/nrf/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void mp_nrf_start_lfclk(void) {
}
#endif
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
rtc_offset_check();
}
}

Expand Down Expand Up @@ -138,8 +139,7 @@ void rtc1_init_time_ticks(void) {
nrfx_rtc_enable(&rtc1);
}

mp_uint_t mp_hal_ticks_ms(void) {
// Compute: (rtc_overflows << 24 + COUNTER) * 1000 / 32768
uint64_t ticks_ms_64(void) { // Compute: (rtc_overflows << 24 + COUNTER) * 1000 / 32768
//
// Note that COUNTER * 1000 / 32768 would overflow during calculation, so use
// the less obvious * 125 / 4096 calculation (overflow secure).
Expand All @@ -151,7 +151,11 @@ mp_uint_t mp_hal_ticks_ms(void) {
uint32_t counter;
// guard against overflow irq
RTC1_GET_TICKS_ATOMIC(rtc1, overflows, counter)
return (overflows << 9) * 1000 + (counter * 125 / 4096);
return ((uint64_t)overflows << 9) * 1000 + (counter * 125 / 4096);
}

mp_uint_t mp_hal_ticks_ms(void) {
return ticks_ms_64();
}

mp_uint_t mp_hal_ticks_us(void) {
Expand Down
1 change: 1 addition & 0 deletions ports/nrf/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ void rtc1_init_time_ticks();
mp_uint_t mp_hal_ticks_ms(void);
#define mp_hal_ticks_us() (0)
#endif
extern void rtc_offset_check(void);

// TODO: empty implementation for now. Used by machine_spi.c:69
#define mp_hal_delay_us_fast(p)
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy