Verified Commit db390227 authored by Rahix's avatar Rahix
Browse files

feat(rtc): Add RTC alarm interrupt



Signed-off-by: Rahix's avatarRahix <rahix@rahix.de>
parent d66db156
......@@ -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 */
#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;
}
......@@ -13,6 +13,7 @@ Q(TOP_RIGHT)
/* utime */
Q(utime)
Q(alarm)
Q(sleep)
Q(sleep_ms)
Q(sleep_us)
......
#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)},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment