From db3902278cb5a6f6c2d08fa5bb89c3504e29a6a1 Mon Sep 17 00:00:00 2001 From: Rahix <rahix@rahix.de> Date: Wed, 31 Jul 2019 22:25:12 +0200 Subject: [PATCH] feat(rtc): Add RTC alarm interrupt Signed-off-by: Rahix <rahix@rahix.de> --- epicardium/epicardium.h | 25 ++++++++++++++++++++++++- epicardium/modules/rtc.c | 34 ++++++++++++++++++++++++++++++++++ pycardium/modules/qstrdefs.h | 1 + pycardium/modules/utime.c | 30 +++++++++++++++++++++++++++--- 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index b4b72dd5..ac1eb09a 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -60,6 +60,7 @@ typedef unsigned int size_t; #define API_FILE_STAT 0x38 #define API_RTC_GET_SECONDS 0x40 +#define API_RTC_SCHEDULE_ALARM 0x41 /* clang-format on */ typedef uint32_t api_int_id_t; @@ -100,8 +101,11 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); #define EPIC_INT_BHI160_TEST 2 API_ISR(EPIC_INT_BHI160_TEST, epic_isr_bhi160_test); +/** RTC Alarm interrupt. See :c:func:`epic_isr_rtc_alarm` */ +#define EPIC_INT_RTC_ALARM 3 + /* Number of defined interrupts. */ -#define EPIC_INT_NUM 3 +#define EPIC_INT_NUM 4 /* clang-format on */ API_ISR(EPIC_INT_RESET, epic_isr_reset); @@ -589,4 +593,23 @@ API(API_FILE_STAT, int epic_file_stat(const char* path, epic_stat_t* stat)); */ API(API_RTC_GET_SECONDS, uint32_t epic_rtc_get_seconds(void)); +/** + * Schedule the RTC alarm for the given timestamp. + * + * :param uint32_t timestamp: When to schedule the IRQ + * :return: `0` on success or a negative value if an error occured. Possible + * errors: + * + * - ``-EINVAL``: RTC is in a bad state + */ +API(API_RTC_SCHEDULE_ALARM, int epic_rtc_schedule_alarm(uint32_t timestamp)); + +/** + * **Interrupt Service Routine** + * + * ``epic_isr_rtc_alarm()`` is called when the RTC alarm triggers. The RTC alarm + * can be scheduled using :c:func:`epic_rtc_schedule_alarm`. + */ +API_ISR(EPIC_INT_RTC_ALARM, epic_isr_rtc_alarm); + #endif /* _EPICARDIUM_H */ diff --git a/epicardium/modules/rtc.c b/epicardium/modules/rtc.c index e87b1cd9..f50355e1 100644 --- a/epicardium/modules/rtc.c +++ b/epicardium/modules/rtc.c @@ -1,3 +1,7 @@ +#include "epicardium.h" +#include "modules/log.h" +#include "api/interrupt-sender.h" + #include "rtc.h" #include <stdint.h> @@ -6,3 +10,33 @@ uint32_t epic_rtc_get_seconds(void) { return RTC_GetSecond(); } + +void RTC_IRQHandler(void) +{ + int flags = RTC_GetFlags(); + + if (flags & MXC_F_RTC_CTRL_ALDF) { + RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF); + api_interrupt_trigger(EPIC_INT_RTC_ALARM); + } else { + LOG_WARN("rtc", "Unknown IRQ caught!"); + /* Disable IRQ so it does not retrigger */ + NVIC_DisableIRQ(RTC_IRQn); + } +} + +int epic_rtc_schedule_alarm(uint32_t timestamp) +{ + int res; + + NVIC_EnableIRQ(RTC_IRQn); + + while ((res = RTC_SetTimeofdayAlarm(MXC_RTC, timestamp)) == E_BUSY) + ; + + if (res != E_SUCCESS) { + return -EINVAL; + } + + return 0; +} diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h index 600543ab..ec162d21 100644 --- a/pycardium/modules/qstrdefs.h +++ b/pycardium/modules/qstrdefs.h @@ -13,6 +13,7 @@ Q(TOP_RIGHT) /* utime */ Q(utime) +Q(alarm) Q(sleep) Q(sleep_ms) Q(sleep_us) diff --git a/pycardium/modules/utime.c b/pycardium/modules/utime.c index e5f57866..15fa8167 100644 --- a/pycardium/modules/utime.c +++ b/pycardium/modules/utime.c @@ -1,3 +1,4 @@ +#include "interrupt.h" #include "epicardium.h" #include "mxc_delay.h" @@ -12,11 +13,13 @@ // Needs to be after the stdint include ... #include "lib/timeutils/timeutils.h" +/* MicroPython has its epoch at 2000-01-01. Our RTC is in UTC */ +#define EPOCH_OFFSET 946684800UL + static mp_obj_t time_time(void) { mp_int_t seconds; - /* MicroPython has its epoch at 2000-01-01. Our RTC is in UTC */ - seconds = epic_rtc_get_seconds() - 946684800UL; + seconds = epic_rtc_get_seconds() - EPOCH_OFFSET; return mp_obj_new_int(seconds); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); @@ -26,7 +29,7 @@ static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) mp_int_t seconds; if (n_args == 0 || args[0] == mp_const_none) { - seconds = epic_rtc_get_seconds() - 946684800UL; + seconds = epic_rtc_get_seconds() - EPOCH_OFFSET; } else { seconds = mp_obj_get_int(args[0]); } @@ -75,6 +78,26 @@ static mp_obj_t time_mktime(mp_obj_t tuple) } static MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); +/* Schedule an alarm */ +static mp_obj_t time_alarm(size_t n_args, const mp_obj_t *args) +{ + mp_int_t timestamp = mp_obj_get_int(args[0]) + EPOCH_OFFSET; + if (n_args == 2) { + /* If a callback was given, register it for the RTC Alarm */ + mp_obj_t callback = args[1]; + mp_obj_t irq_id = MP_OBJ_NEW_SMALL_INT(EPIC_INT_RTC_ALARM); + mp_interrupt_set_callback(irq_id, callback); + mp_interrupt_enable_callback(irq_id); + } + + int res = epic_rtc_schedule_alarm(timestamp); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_alarm_obj, 1, 2, time_alarm); + static const mp_rom_map_elem_t time_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, @@ -83,6 +106,7 @@ static const mp_rom_map_elem_t time_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm), MP_ROM_PTR(&time_alarm_obj) }, #if 0 /* TODO: Implement those */ {MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj)}, -- GitLab