From 3d2205e4cde75f23a8ec77dd29cbef14f5d3fcd3 Mon Sep 17 00:00:00 2001 From: philip Date: Sat, 22 Sep 2018 21:54:17 -0400 Subject: [PATCH 1/3] Initial version of code to support multiple hardware timers --- app/modules/gpio_pulse.c | 2 +- app/platform/hw_timer.c | 294 +++++++++++++++++++++++++++++++++------ 2 files changed, 249 insertions(+), 47 deletions(-) diff --git a/app/modules/gpio_pulse.c b/app/modules/gpio_pulse.c index 64fe84f3f6..c73ab8b876 100644 --- a/app/modules/gpio_pulse.c +++ b/app/modules/gpio_pulse.c @@ -10,7 +10,7 @@ #include "pin_map.h" #include "driver/gpio16.h" -#define TIMER_OWNER 'P' +#define TIMER_OWNER (('P' << 8) + 'U') #define xstr(s) str(s) #define str(s) #s diff --git a/app/platform/hw_timer.c b/app/platform/hw_timer.c index 959d1b289f..7cc8d1c81d 100644 --- a/app/platform/hw_timer.c +++ b/app/platform/hw_timer.c @@ -16,6 +16,9 @@ * where module_init is a function. For builtin modules, it might be * a small numeric value that is known not to clash. *******************************************************************************/ +#include "platform.h" +#include "c_stdio.h" +#include "c_stdlib.h" #include "ets_sys.h" #include "os_type.h" #include "osapi.h" @@ -37,11 +40,154 @@ typedef enum { //timer interrupt mode TM_EDGE_INT = 0, //edge interrupt } TIMER_INT_MODE; -static os_param_t the_owner; -static os_param_t callback_arg; -static void (* user_hw_timer_cb)(os_param_t); +typedef struct _timer_user { + struct _timer_user *next; + bool autoload; + int32_t delay; + int32_t autoload_delay; + os_param_t owner; + os_param_t callback_arg; + void (* user_hw_timer_cb)(os_param_t); + int cb_count; +} timer_user; -#define VERIFY_OWNER(owner) if (owner != the_owner) { if (the_owner) { return 0; } the_owner = owner; } +static timer_user *active; +static timer_user *inactive; +static uint8_t lock_count; +static uint8_t timer_running; + +#define LOCK() do { ets_intr_lock(); lock_count++; } while (0) +#define UNLOCK() if (--lock_count == 0) ets_intr_unlock() + +#if 0 +void hw_timer_debug() { + dbg_printf("timer_running=%d\n", timer_running); + timer_user *tu; + for (tu = active; tu; tu = tu->next) { + dbg_printf("Owner: 0x%x, delay=%d, autoload=%d, autoload_delay=%d, cb_count=%d\n", + tu->owner, tu->delay, tu->autoload, tu->autoload_delay, tu->cb_count); + } +} +#endif + +static void adjust_root() { + // Can only ge called with interrupts disabled + // change the initial active delay so that relative stuff still works + if (active && timer_running) { + int32_t time_left = (RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); + if (time_left > active->delay) { + // We have missed the interrupt + time_left -= 1 << 23; + } + active->delay = time_left; + } +} + +static timer_user *find_tu(os_param_t owner) { + // Try the inactive chain first + timer_user **p; + + LOCK(); + + for (p = &inactive; *p; p = &((*p)->next)) { + if ((*p)->owner == owner) { + timer_user *result = *p; + + UNLOCK(); + + return result; + } + } + + for (p = &active; *p; p = &((*p)->next)) { + if ((*p)->owner == owner) { + timer_user *result = *p; + + UNLOCK(); + + return result; + } + } + + UNLOCK(); + return NULL; +} + +static timer_user *find_tu_and_remove(os_param_t owner) { + // Try the inactive chain first + timer_user **p; + + LOCK(); + + for (p = &inactive; *p; p = &((*p)->next)) { + if ((*p)->owner == owner) { + timer_user *result = *p; + *p = result->next; + result->next = NULL; + + UNLOCK(); + + return result; + } + } + + for (p = &active; *p; p = &((*p)->next)) { + if ((*p)->owner == owner) { + timer_user *result = *p; + + bool need_to_reset = (result == active) && result->next; + + if (need_to_reset) { + adjust_root(); + } + + // Increase the delay on the next element + if (result->next) { + result->next->delay += result->delay; + } + + // Cut out of chain + *p = result->next; + result->next = NULL; + + if (need_to_reset) { + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay); + timer_running = 1; + } + + UNLOCK(); + return result; + } + } + + UNLOCK(); + return NULL; +} + +static void insert_active_tu(timer_user *tu) { + timer_user **p; + + LOCK(); + for (p = &active; *p; p = &((*p)->next)) { + if ((*p)->delay >= tu->delay) { + break; + } + tu->delay -= (*p)->delay; + } + + if (*p) { + (*p)->delay -= tu->delay; + } + tu->next = *p; + *p = tu; + + if (*p == active) { + // We have a new leader + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay > 0 ? active->delay : 1); + timer_running = 1; + } + UNLOCK(); +} /****************************************************************************** * FunctionName : platform_hw_timer_arm_ticks @@ -52,10 +198,21 @@ static void (* user_hw_timer_cb)(os_param_t); *******************************************************************************/ bool ICACHE_RAM_ATTR platform_hw_timer_arm_ticks(os_param_t owner, uint32_t ticks) { - VERIFY_OWNER(owner); - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, ticks); + timer_user *tu = find_tu_and_remove(owner); + + if (!tu) { + return false; + } + + tu->delay = ticks; + tu->autoload_delay = ticks; - return 1; + LOCK(); + adjust_root(); + insert_active_tu(tu); + UNLOCK(); + + return true; } /****************************************************************************** @@ -72,10 +229,7 @@ bool ICACHE_RAM_ATTR platform_hw_timer_arm_ticks(os_param_t owner, uint32_t tick *******************************************************************************/ bool ICACHE_RAM_ATTR platform_hw_timer_arm_us(os_param_t owner, uint32_t microseconds) { - VERIFY_OWNER(owner); - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(microseconds)); - - return 1; + return platform_hw_timer_arm_ticks(owner, US_TO_RTC_TIMER_TICKS(microseconds)); } /****************************************************************************** @@ -89,24 +243,56 @@ bool ICACHE_RAM_ATTR platform_hw_timer_arm_us(os_param_t owner, uint32_t microse *******************************************************************************/ bool platform_hw_timer_set_func(os_param_t owner, void (* user_hw_timer_cb_set)(os_param_t), os_param_t arg) { - VERIFY_OWNER(owner); - callback_arg = arg; - user_hw_timer_cb = user_hw_timer_cb_set; - return 1; + timer_user *tu = find_tu(owner); + if (!tu) { + return false; + } + tu->callback_arg = arg; + tu->user_hw_timer_cb = user_hw_timer_cb_set; + return true; } static void ICACHE_RAM_ATTR hw_timer_isr_cb(void *arg) { - if (user_hw_timer_cb != NULL) { - (*(user_hw_timer_cb))(callback_arg); + bool keep_going = true; + adjust_root(); + timer_running = 0; + + while (keep_going && active) { + keep_going = false; + + timer_user *fired = active; + active = fired->next; + if (fired->autoload) { + fired->delay = fired->autoload_delay; + insert_active_tu(fired); + if (active->delay <= 0) { + keep_going = true; + } + } else { + fired->next = inactive; + inactive = fired; + if (active) { + active->delay += fired->delay; + if (active->delay <= 0) { + keep_going = true; + } + } + } + if (fired->user_hw_timer_cb) { + fired->cb_count++; + (*(fired->user_hw_timer_cb))(fired->callback_arg); + } + } + if (active && !timer_running) { + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay); + timer_running = 1; } } static void ICACHE_RAM_ATTR hw_timer_nmi_cb(void) { - if (user_hw_timer_cb != NULL) { - (*(user_hw_timer_cb))(callback_arg); - } + hw_timer_isr_cb(NULL); } /****************************************************************************** @@ -114,12 +300,13 @@ static void ICACHE_RAM_ATTR hw_timer_nmi_cb(void) * Description : figure out how long since th last timer interrupt * Parameters : os_param_t owner * Returns : the number of ticks +* This is actually the last timer interrupt and not the interrupt for your +* timer. This may cause problems. *******************************************************************************/ uint32_t ICACHE_RAM_ATTR platform_hw_timer_get_delay_ticks(os_param_t owner) { - VERIFY_OWNER(owner); - - return (- RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); + return 0; + //return (- RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); } /****************************************************************************** @@ -136,25 +323,34 @@ uint32_t ICACHE_RAM_ATTR platform_hw_timer_get_delay_ticks(os_param_t owner) *******************************************************************************/ bool platform_hw_timer_init(os_param_t owner, FRC1_TIMER_SOURCE_TYPE source_type, bool autoload) { - VERIFY_OWNER(owner); - if (autoload) { - RTC_REG_WRITE(FRC1_CTRL_ADDRESS, - FRC1_AUTO_LOAD | DIVIDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT); - } else { - RTC_REG_WRITE(FRC1_CTRL_ADDRESS, - DIVIDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT); + timer_user *tu = find_tu_and_remove(owner); + + if (!tu) { + tu = (timer_user *) c_malloc(sizeof(*tu)); + if (!tu) { + return false; + } + memset(tu, 0, sizeof(*tu)); + tu->owner = owner; } - if (source_type == NMI_SOURCE) { - ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_nmi_cb); - } else { + tu->autoload = autoload; + + if (!active && !inactive) { + RTC_REG_WRITE(FRC1_CTRL_ADDRESS, + DIVIDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT); ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL); + + TM1_EDGE_INT_ENABLE(); + ETS_FRC1_INTR_ENABLE(); } - TM1_EDGE_INT_ENABLE(); - ETS_FRC1_INTR_ENABLE(); + LOCK(); + tu->next = inactive; + inactive = tu; + UNLOCK(); - return 1; + return true; } /****************************************************************************** @@ -165,19 +361,25 @@ bool platform_hw_timer_init(os_param_t owner, FRC1_TIMER_SOURCE_TYPE source_type *******************************************************************************/ bool ICACHE_RAM_ATTR platform_hw_timer_close(os_param_t owner) { - VERIFY_OWNER(owner); + timer_user *tu = find_tu_and_remove(owner); - /* Set no reload mode */ - RTC_REG_WRITE(FRC1_CTRL_ADDRESS, - DIVIDED_BY_16 | TM_EDGE_INT); - - TM1_EDGE_INT_DISABLE(); - ETS_FRC1_INTR_DISABLE(); + if (tu) { + LOCK(); + tu->next = inactive; + inactive = tu; + UNLOCK(); + } - user_hw_timer_cb = NULL; + // This will never actually run.... + if (!active && !inactive) { + /* Set no reload mode */ + RTC_REG_WRITE(FRC1_CTRL_ADDRESS, + DIVIDED_BY_16 | TM_EDGE_INT); - the_owner = 0; + TM1_EDGE_INT_DISABLE(); + ETS_FRC1_INTR_DISABLE(); + } - return 1; + return true; } From ce83f9722c3d70a9aab32ffa7d43197aa41f3e93 Mon Sep 17 00:00:00 2001 From: philip Date: Sun, 23 Sep 2018 10:38:29 -0400 Subject: [PATCH 2/3] MAde the time sinca last tick work again --- app/modules/gpio_pulse.c | 2 +- app/platform/hw_timer.c | 101 ++++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/app/modules/gpio_pulse.c b/app/modules/gpio_pulse.c index c73ab8b876..170d837385 100644 --- a/app/modules/gpio_pulse.c +++ b/app/modules/gpio_pulse.c @@ -434,7 +434,7 @@ static int gpio_pulse_start(lua_State *L) { pulser->next_adjust = initial_adjust; // Now start things up - if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) { + if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, FALSE)) { // Failed to init the timer luaL_error(L, "Unable to initialize timer"); } diff --git a/app/platform/hw_timer.c b/app/platform/hw_timer.c index 7cc8d1c81d..6ee38bbce8 100644 --- a/app/platform/hw_timer.c +++ b/app/platform/hw_timer.c @@ -25,6 +25,10 @@ #include "hw_timer.h" +//#define DEBUG_HW_TIMER +//#undef NODE_DBG +//#define NODE_DBG dbg_printf + #define FRC1_ENABLE_TIMER BIT7 #define FRC1_AUTO_LOAD BIT6 @@ -45,22 +49,27 @@ typedef struct _timer_user { bool autoload; int32_t delay; int32_t autoload_delay; + uint32_t expected_interrupt_time; os_param_t owner; os_param_t callback_arg; void (* user_hw_timer_cb)(os_param_t); +#ifdef DEBUG_HW_TIMER int cb_count; +#endif } timer_user; static timer_user *active; static timer_user *inactive; static uint8_t lock_count; static uint8_t timer_running; +static uint32_t time_next_expiry; +static int32_t last_timer_load; #define LOCK() do { ets_intr_lock(); lock_count++; } while (0) #define UNLOCK() if (--lock_count == 0) ets_intr_unlock() -#if 0 -void hw_timer_debug() { +#ifdef DEBUG_HW_TIMER +void ICACHE_RAM_ATTR hw_timer_debug() { dbg_printf("timer_running=%d\n", timer_running); timer_user *tu; for (tu = active; tu; tu = tu->next) { @@ -70,20 +79,48 @@ void hw_timer_debug() { } #endif -static void adjust_root() { +static void ICACHE_RAM_ATTR set_timer(int delay, const char *caller) { + if (delay < 1) { + delay = 1; + } + int32_t time_left = (RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, delay); + + if (time_left > last_timer_load) { + // We have missed the interrupt + time_left -= 1 << 23; + } + NODE_DBG("%s(%x): time_next=%d, left=%d (load=%d), delay=%d => %d\n", caller, active->owner, time_next_expiry, time_left, last_timer_load, delay, time_next_expiry - time_left + delay); + time_next_expiry = time_next_expiry - time_left + delay; + last_timer_load = delay; + + timer_running = 1; +} + +static void ICACHE_RAM_ATTR adjust_root() { // Can only ge called with interrupts disabled // change the initial active delay so that relative stuff still works + // Also, set the last_timer_load to be now + int32_t time_left = (RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); + if (time_left > last_timer_load) { + // We have missed the interrupt + time_left -= 1 << 23; + } + if (active && timer_running) { - int32_t time_left = (RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); - if (time_left > active->delay) { - // We have missed the interrupt - time_left -= 1 << 23; - } active->delay = time_left; } + + if (active) { + NODE_DBG("adjust(%x): time_left=%d (last_load=%d)\n", active->owner, time_left, last_timer_load); + } else { + NODE_DBG("adjust: time_left=%d (last_load=%d)\n", time_left, last_timer_load); + } + + last_timer_load = time_left; } -static timer_user *find_tu(os_param_t owner) { +static timer_user * ICACHE_RAM_ATTR find_tu(os_param_t owner) { // Try the inactive chain first timer_user **p; @@ -113,7 +150,7 @@ static timer_user *find_tu(os_param_t owner) { return NULL; } -static timer_user *find_tu_and_remove(os_param_t owner) { +static timer_user * ICACHE_RAM_ATTR find_tu_and_remove(os_param_t owner) { // Try the inactive chain first timer_user **p; @@ -151,8 +188,7 @@ static timer_user *find_tu_and_remove(os_param_t owner) { result->next = NULL; if (need_to_reset) { - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay); - timer_running = 1; + set_timer(active->delay, "find_tu"); } UNLOCK(); @@ -164,10 +200,13 @@ static timer_user *find_tu_and_remove(os_param_t owner) { return NULL; } -static void insert_active_tu(timer_user *tu) { +static void ICACHE_RAM_ATTR insert_active_tu(timer_user *tu) { timer_user **p; LOCK(); + + tu->expected_interrupt_time = time_next_expiry - last_timer_load + tu->delay; + for (p = &active; *p; p = &((*p)->next)) { if ((*p)->delay >= tu->delay) { break; @@ -181,10 +220,9 @@ static void insert_active_tu(timer_user *tu) { tu->next = *p; *p = tu; - if (*p == active) { + if (tu == active) { // We have a new leader - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay > 0 ? active->delay : 1); - timer_running = 1; + set_timer(active->delay, "insert_active"); } UNLOCK(); } @@ -207,6 +245,8 @@ bool ICACHE_RAM_ATTR platform_hw_timer_arm_ticks(os_param_t owner, uint32_t tick tu->delay = ticks; tu->autoload_delay = ticks; + NODE_DBG("arm(%x): ticks=%d\n", owner, ticks); + LOCK(); adjust_root(); insert_active_tu(tu); @@ -249,6 +289,7 @@ bool platform_hw_timer_set_func(os_param_t owner, void (* user_hw_timer_cb_set)( } tu->callback_arg = arg; tu->user_hw_timer_cb = user_hw_timer_cb_set; + NODE_DBG("set-CB(%x): %x, %x\n", tu->owner, tu->user_hw_timer_cb, tu->callback_arg); return true; } @@ -264,7 +305,8 @@ static void ICACHE_RAM_ATTR hw_timer_isr_cb(void *arg) timer_user *fired = active; active = fired->next; if (fired->autoload) { - fired->delay = fired->autoload_delay; + fired->expected_interrupt_time += fired->autoload_delay; + fired->delay = fired->expected_interrupt_time - (time_next_expiry - last_timer_load); insert_active_tu(fired); if (active->delay <= 0) { keep_going = true; @@ -280,13 +322,15 @@ static void ICACHE_RAM_ATTR hw_timer_isr_cb(void *arg) } } if (fired->user_hw_timer_cb) { +#ifdef DEBUG_HW_TIMER fired->cb_count++; +#endif + NODE_DBG("CB(%x): %x, %x\n", fired->owner, fired->user_hw_timer_cb, fired->callback_arg); (*(fired->user_hw_timer_cb))(fired->callback_arg); } } if (active && !timer_running) { - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, active->delay); - timer_running = 1; + set_timer(active->delay, "isr"); } } @@ -300,13 +344,24 @@ static void ICACHE_RAM_ATTR hw_timer_nmi_cb(void) * Description : figure out how long since th last timer interrupt * Parameters : os_param_t owner * Returns : the number of ticks -* This is actually the last timer interrupt and not the interrupt for your -* timer. This may cause problems. *******************************************************************************/ uint32_t ICACHE_RAM_ATTR platform_hw_timer_get_delay_ticks(os_param_t owner) { - return 0; - //return (- RTC_REG_READ(FRC1_COUNT_ADDRESS)) & ((1 << 23) - 1); + timer_user *tu = find_tu(owner); + if (!tu) { + return 0; + } + + LOCK(); + adjust_root(); + UNLOCK(); + int ret = (time_next_expiry - last_timer_load) - tu->expected_interrupt_time; + + if (ret < 0) { + NODE_DBG("delay ticks = %d, last_timer_load=%d, tu->expected_int=%d, next_exp=%d\n", ret, last_timer_load, tu->expected_interrupt_time, time_next_expiry); + } + + return ret < 0 ? 0 : ret; } /****************************************************************************** From b1726fc04ef94b1f4f934a90d0af3c7585bdbd41 Mon Sep 17 00:00:00 2001 From: philip Date: Sun, 23 Sep 2018 20:29:43 -0400 Subject: [PATCH 3/3] Add some documentation to the code --- app/platform/hw_timer.c | 60 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/app/platform/hw_timer.c b/app/platform/hw_timer.c index 6ee38bbce8..0a0e45db08 100644 --- a/app/platform/hw_timer.c +++ b/app/platform/hw_timer.c @@ -7,13 +7,13 @@ * * Modification history: * 2014/5/1, v1.0 create this file. -* +* * Adapted for NodeMCU 2016 -* +* * The owner parameter should be a unique value per module using this API -* It could be a pointer to a bit of data or code -* e.g. #define OWNER ((os_param_t) module_init) -* where module_init is a function. For builtin modules, it might be +* It could be a pointer to a bit of data or code +* e.g. #define OWNER ((os_param_t) module_init) +* where module_init is a function. For builtin modules, it might be * a small numeric value that is known not to clash. *******************************************************************************/ #include "platform.h" @@ -44,10 +44,14 @@ typedef enum { //timer interrupt mode TM_EDGE_INT = 0, //edge interrupt } TIMER_INT_MODE; +/* + * This represents a single user of the timer functionality. It is keyed by the owner + * field. + */ typedef struct _timer_user { struct _timer_user *next; bool autoload; - int32_t delay; + int32_t delay; // once on the active list, this is difference in delay from the preceding element int32_t autoload_delay; uint32_t expected_interrupt_time; os_param_t owner; @@ -58,16 +62,38 @@ typedef struct _timer_user { #endif } timer_user; +/* + * There are two lists of timer_user blocks. The active list are those which are waiting + * for timeouts to happen, and the inactive list contains idle blocks. Unfortunately + * there isn't a way to clean up the inactive blocks as some modules call the + * close method from interrupt level. + */ static timer_user *active; static timer_user *inactive; + +/* + * There are a fair number of places when interrupts need to be disabled as many of + * the methods can be called from interrupt level. The lock/unlock calls support + * multiple LOCKs and then the same number of UNLOCKs are required to re-enable + * interrupts. This is imolemeted by counting the number of times that lock is called. + */ static uint8_t lock_count; static uint8_t timer_running; + static uint32_t time_next_expiry; static int32_t last_timer_load; #define LOCK() do { ets_intr_lock(); lock_count++; } while (0) #define UNLOCK() if (--lock_count == 0) ets_intr_unlock() +/* + * To start a timer, you write to FRCI_LOAD_ADDRESS, and that starts the counting + * down. When it reaches zero, the interrupt fires -- but the counting continues. + * The counter is 23 bits wide. The current value of the counter can be read + * at FRC1_COUNT_ADDRESS. The unit is 200ns, and so it takes somewhat over a second + * to wrap the counter. + */ + #ifdef DEBUG_HW_TIMER void ICACHE_RAM_ATTR hw_timer_debug() { dbg_printf("timer_running=%d\n", timer_running); @@ -119,7 +145,10 @@ static void ICACHE_RAM_ATTR adjust_root() { last_timer_load = time_left; } - +/* + * Find the timer_user block for this owner. This just returns + * a pointer to the block, or NULL. + */ static timer_user * ICACHE_RAM_ATTR find_tu(os_param_t owner) { // Try the inactive chain first timer_user **p; @@ -150,6 +179,12 @@ static timer_user * ICACHE_RAM_ATTR find_tu(os_param_t owner) { return NULL; } +/* + * Find the timer_user block for this owner. This just returns + * a pointer to the block, or NULL. If it finds the block, then it is + * removed from whichever chain it is on. Note that this may require + * triggering a timer. + */ static timer_user * ICACHE_RAM_ATTR find_tu_and_remove(os_param_t owner) { // Try the inactive chain first timer_user **p; @@ -200,6 +235,10 @@ static timer_user * ICACHE_RAM_ATTR find_tu_and_remove(os_param_t owner) { return NULL; } +/* + * This inserts a timer_user block into the active chain. This is a sightly + * complex process as it can involve triggering a timer load. + */ static void ICACHE_RAM_ATTR insert_active_tu(timer_user *tu) { timer_user **p; @@ -293,6 +332,13 @@ bool platform_hw_timer_set_func(os_param_t owner, void (* user_hw_timer_cb_set)( return true; } +/* + * This is the timer ISR. It has to find the timer that was running and trigger the callback + * for that timer. By this stage, the next timer may have expired as well, and so the process + * iterates. Note that if there is an autoload timer, then it should be restarted immediately. + * Also, the callbacks typically do re-arm the timer, so we have to be careful not to + * assume that nothing changes during the callback. + */ static void ICACHE_RAM_ATTR hw_timer_isr_cb(void *arg) { bool keep_going = true;