From d7f722e98f252385403ff75e4becd800dcac1850 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 29 Feb 2020 01:52:38 +0100 Subject: [PATCH 1/3] cpu/cc2538: rtt: implement rtt_set_counter() We can't set the hardware counter directly, so always add an offset. --- cpu/cc2538/periph/rtt.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/cpu/cc2538/periph/rtt.c b/cpu/cc2538/periph/rtt.c index a393e2258a..3220176acf 100644 --- a/cpu/cc2538/periph/rtt.c +++ b/cpu/cc2538/periph/rtt.c @@ -32,6 +32,8 @@ static void *alarm_arg; static rtt_cb_t overflow_cb = NULL; static void *overflow_arg; +static uint32_t rtt_offset = 0; + static inline void _rtt_irq_enable(void) { NVIC_SetPriority(SM_TIMER_ALT_IRQn, RTT_IRQ_PRIO); @@ -60,12 +62,22 @@ void rtt_init(void) rtt_poweron(); } +static inline uint32_t _rtt_get_counter(void) +{ + return ((SMWDTHROSC_ST0 & 0xFF) + | ((SMWDTHROSC_ST1 & 0xFF) << 8) + | ((SMWDTHROSC_ST2 & 0xFF) << 16) + | ((SMWDTHROSC_ST3 & 0xFF) << 24)); +} + uint32_t rtt_get_counter(void) { - return ((SMWDTHROSC_ST0 & 0xFF) | - ((SMWDTHROSC_ST1 & 0xFF) << 8) | - ((SMWDTHROSC_ST2 & 0xFF) << 16) | - ((SMWDTHROSC_ST3 & 0xFF) << 24)); + return _rtt_get_counter() - rtt_offset; +} + +void rtt_set_counter(uint32_t counter) +{ + rtt_offset = _rtt_get_counter() + counter; } void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) @@ -74,6 +86,8 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) unsigned irq = irq_disable(); + alarm += rtt_offset; + /* set alarm value */ while (!(SMWDTHROSC_STLOAD & SMWDTHROSC_STLOAD_STLOAD_MASK)) {} SMWDTHROSC_ST3 = (alarm >> 24) & 0xFF; @@ -103,10 +117,10 @@ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) /* set threshold to RTT_MAX_VALUE */ while (!(SMWDTHROSC_STLOAD & SMWDTHROSC_STLOAD_STLOAD_MASK)) {} - SMWDTHROSC_ST3 = (RTT_MAX_VALUE >> 24) & 0xFF; - SMWDTHROSC_ST2 = (RTT_MAX_VALUE >> 16) & 0xFF; - SMWDTHROSC_ST1 = (RTT_MAX_VALUE >> 8) & 0xFF; - SMWDTHROSC_ST0 = RTT_MAX_VALUE & 0xFF; + SMWDTHROSC_ST3 = (rtt_offset >> 24) & 0xFF; + SMWDTHROSC_ST2 = (rtt_offset >> 16) & 0xFF; + SMWDTHROSC_ST1 = (rtt_offset >> 8) & 0xFF; + SMWDTHROSC_ST0 = rtt_offset & 0xFF; /* set callback*/ overflow_cb = cb; From 852fd7f531fc65297fc22dfbb1753a678480eb9a Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 29 Feb 2020 02:28:54 +0100 Subject: [PATCH 2/3] cpu/cc2538: rtt: implement rtt_get_alarm() We can't read back the alarm, so just store it in a variable. --- cpu/cc2538/periph/rtt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpu/cc2538/periph/rtt.c b/cpu/cc2538/periph/rtt.c index 3220176acf..4d897e6a6c 100644 --- a/cpu/cc2538/periph/rtt.c +++ b/cpu/cc2538/periph/rtt.c @@ -32,7 +32,8 @@ static void *alarm_arg; static rtt_cb_t overflow_cb = NULL; static void *overflow_arg; -static uint32_t rtt_offset = 0; +static uint32_t rtt_alarm; +static uint32_t rtt_offset; static inline void _rtt_irq_enable(void) { @@ -95,6 +96,8 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) SMWDTHROSC_ST1 = (alarm >> 8) & 0xFF; SMWDTHROSC_ST0 = alarm & 0xFF; + rtt_alarm = alarm; + /* set callback*/ alarm_cb = cb; alarm_arg = arg; @@ -102,6 +105,11 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) irq_restore(irq); } +uint32_t rtt_get_alarm(void) +{ + return rtt_alarm - rtt_offset; +} + void rtt_clear_alarm(void) { unsigned irq = irq_disable(); From a8d5f13ad99ba10e26087d467831a1cacf3195ac Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 29 Feb 2020 13:43:59 +0100 Subject: [PATCH 3/3] cpu/cc2538: rtt: allow to set alarm and overflow cb independently Previously the setting the alarm would overwrite the overflow callback and vice versa. Since we can only set one alarm in hardware, always set the alarm to the closest event of the two. --- cpu/cc2538/periph/rtt.c | 92 ++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/cpu/cc2538/periph/rtt.c b/cpu/cc2538/periph/rtt.c index 4d897e6a6c..8fc7a9f3de 100644 --- a/cpu/cc2538/periph/rtt.c +++ b/cpu/cc2538/periph/rtt.c @@ -24,6 +24,9 @@ #include "cpu.h" #include "periph/rtt.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + #define SMWDTHROSC_STLOAD_STLOAD_MASK (0x00000001) /* allocate memory for alarm and overflow callbacks + args */ @@ -35,6 +38,11 @@ static void *overflow_arg; static uint32_t rtt_alarm; static uint32_t rtt_offset; +static enum { + RTT_ALARM, + RTT_OVERFLOW +} rtt_next_alarm; + static inline void _rtt_irq_enable(void) { NVIC_SetPriority(SM_TIMER_ALT_IRQn, RTT_IRQ_PRIO); @@ -78,7 +86,23 @@ uint32_t rtt_get_counter(void) void rtt_set_counter(uint32_t counter) { + rtt_alarm -= rtt_offset; rtt_offset = _rtt_get_counter() + counter; + rtt_alarm += rtt_offset; + + /* re-set the overflow callback */ + if (overflow_cb) { + rtt_set_overflow_cb(overflow_cb, overflow_arg); + } +} + +static void _set_alarm(uint32_t alarm) +{ + while (!(SMWDTHROSC_STLOAD & SMWDTHROSC_STLOAD_STLOAD_MASK)) {} + SMWDTHROSC_ST3 = (alarm >> 24) & 0xFF; + SMWDTHROSC_ST2 = (alarm >> 16) & 0xFF; + SMWDTHROSC_ST1 = (alarm >> 8) & 0xFF; + SMWDTHROSC_ST0 = alarm & 0xFF; } void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) @@ -86,22 +110,22 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) assert(cb && !(alarm & ~RTT_MAX_VALUE)); unsigned irq = irq_disable(); - - alarm += rtt_offset; - - /* set alarm value */ - while (!(SMWDTHROSC_STLOAD & SMWDTHROSC_STLOAD_STLOAD_MASK)) {} - SMWDTHROSC_ST3 = (alarm >> 24) & 0xFF; - SMWDTHROSC_ST2 = (alarm >> 16) & 0xFF; - SMWDTHROSC_ST1 = (alarm >> 8) & 0xFF; - SMWDTHROSC_ST0 = alarm & 0xFF; - - rtt_alarm = alarm; + rtt_alarm = alarm + rtt_offset; /* set callback*/ alarm_cb = cb; alarm_arg = arg; + DEBUG("rtt_set_alarm(%lu), alarm in %lu ticks, overflow in %lu ticks\n", + alarm, rtt_alarm - _rtt_get_counter(), + rtt_offset - _rtt_get_counter()); + + /* only set overflow alarm if it happens before the scheduled alarm */ + if (overflow_cb == NULL || (rtt_offset >= rtt_alarm )) { + rtt_next_alarm = RTT_ALARM; + _set_alarm(rtt_alarm); + } + irq_restore(irq); } @@ -123,17 +147,16 @@ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) { unsigned irq = irq_disable(); - /* set threshold to RTT_MAX_VALUE */ - while (!(SMWDTHROSC_STLOAD & SMWDTHROSC_STLOAD_STLOAD_MASK)) {} - SMWDTHROSC_ST3 = (rtt_offset >> 24) & 0xFF; - SMWDTHROSC_ST2 = (rtt_offset >> 16) & 0xFF; - SMWDTHROSC_ST1 = (rtt_offset >> 8) & 0xFF; - SMWDTHROSC_ST0 = rtt_offset & 0xFF; - /* set callback*/ overflow_cb = cb; overflow_arg = arg; + /* only set overflow alarm if it happens before the scheduled alarm */ + if (alarm_cb == NULL || (rtt_alarm > rtt_offset)) { + rtt_next_alarm = RTT_OVERFLOW; + _set_alarm(rtt_offset); + } + irq_restore(irq); } @@ -148,17 +171,40 @@ void rtt_clear_overflow_cb(void) void isr_sleepmode(void) { - if (alarm_cb) { + rtt_cb_t tmp; + bool both = (rtt_alarm == rtt_offset); + + switch (rtt_next_alarm) { + case RTT_ALARM: /* 'consume' the callback (as it might be set again in the cb) */ - rtt_cb_t tmp = alarm_cb; + tmp = alarm_cb; alarm_cb = NULL; tmp(alarm_arg); - } - else if (overflow_cb) { + + if (!both) { + break; + } /* fall-through */ + case RTT_OVERFLOW: /* 'consume' the callback (as it might be set again in the cb) */ - rtt_cb_t tmp = overflow_cb; + tmp = overflow_cb; overflow_cb = NULL; tmp(overflow_arg); + break; } + + if (alarm_cb && (rtt_offset >= rtt_alarm)) { + DEBUG("rtt: next alarm in %lu ticks (RTT)\n", + rtt_alarm - _rtt_get_counter()); + + rtt_next_alarm = RTT_ALARM; + _set_alarm(rtt_alarm); + } else if (overflow_cb && (rtt_alarm > rtt_offset)) { + DEBUG("rtt: next alarm in %lu ticks (OVERFLOW)\n", + rtt_offset - _rtt_get_counter()); + + rtt_next_alarm = RTT_OVERFLOW; + _set_alarm(rtt_offset); + } + cortexm_isr_end(); }