Skip to content

stm32: Support static soft timer instances (v2) #7170

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

Closed
Closed
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
7 changes: 4 additions & 3 deletions ports/stm32/machine_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar
self->expiry_ms = mp_hal_ticks_ms() + self->delta_ms;

if (args[ARG_callback].u_obj != MP_OBJ_NULL) {
self->callback = args[ARG_callback].u_obj;
self->py_callback = args[ARG_callback].u_obj;
}

if (self->callback != mp_const_none) {
if (self->py_callback != mp_const_none) {
soft_timer_insert(self);
}

Expand All @@ -89,8 +89,9 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar
STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);
self->pairheap.base.type = &machine_timer_type;
self->flags = SOFT_TIMER_FLAG_PY_CALLBACK;
self->delta_ms = 1000;
self->callback = mp_const_none;
self->py_callback = mp_const_none;

// Get timer id (only soft timer (-1) supported at the moment)
mp_int_t id = -1;
Expand Down
69 changes: 56 additions & 13 deletions ports/stm32/softtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <stdint.h>
#include "py/runtime.h"
#include "py/mphal.h"
#include "irq.h"
#include "softtimer.h"

Expand All @@ -36,6 +37,10 @@ extern __IO uint32_t uwTick;

volatile uint32_t soft_timer_next;

// Soft-timer pairing heap for statically allocated (ie not via GC ) entries.
STATIC soft_timer_entry_t *soft_timer_static_heap;

// Clears out the GC-allocated soft-timer heap.
void soft_timer_deinit(void) {
MP_STATE_PORT(soft_timer_heap) = NULL;
}
Expand All @@ -58,41 +63,79 @@ STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) {
}

// Must be executed at IRQ_PRI_PENDSV
void soft_timer_handler(void) {
STATIC void soft_timer_handler_helper(soft_timer_entry_t **heap_in, bool *expiry_ms_set, uint32_t *expiry_ms) {
uint32_t ticks_ms = uwTick;
soft_timer_entry_t *heap = MP_STATE_PORT(soft_timer_heap);
soft_timer_entry_t *heap = *heap_in;
while (heap != NULL && TICKS_DIFF(heap->expiry_ms, ticks_ms) <= 0) {
soft_timer_entry_t *entry = heap;
heap = (soft_timer_entry_t *)mp_pairheap_pop(soft_timer_lt, &heap->pairheap);
mp_sched_schedule(entry->callback, MP_OBJ_FROM_PTR(entry));
if (entry->flags & SOFT_TIMER_FLAG_PY_CALLBACK) {
mp_sched_schedule(entry->py_callback, MP_OBJ_FROM_PTR(entry));
} else {
entry->c_callback(entry);
}
if (entry->mode == SOFT_TIMER_MODE_PERIODIC) {
entry->expiry_ms += entry->delta_ms;
heap = (soft_timer_entry_t *)mp_pairheap_push(soft_timer_lt, &heap->pairheap, &entry->pairheap);
}
}
MP_STATE_PORT(soft_timer_heap) = heap;
if (heap == NULL) {
if (heap != NULL) {
if (!*expiry_ms_set || TICKS_DIFF(heap->expiry_ms, *expiry_ms) <= 0) {
*expiry_ms_set = true;
*expiry_ms = heap->expiry_ms;
}
}
*heap_in = heap;
}

// Must be executed at IRQ_PRI_PENDSV
void soft_timer_handler(void) {
bool expiry_ms_set = false;
uint32_t expiry_ms;
soft_timer_handler_helper(&soft_timer_static_heap, &expiry_ms_set, &expiry_ms);
soft_timer_handler_helper(&MP_STATE_PORT(soft_timer_heap), &expiry_ms_set, &expiry_ms);
if (!expiry_ms_set) {
// No more timers left, set largest delay possible
soft_timer_next = uwTick;
} else {
// Set soft_timer_next so SysTick calls us back at the correct time
soft_timer_schedule_systick(heap->expiry_ms);
soft_timer_schedule_systick(expiry_ms);
}
}

void soft_timer_insert(soft_timer_entry_t *entry) {
STATIC void soft_timer_insert_to(soft_timer_entry_t **heap, soft_timer_entry_t *other_heap, soft_timer_entry_t *entry) {
mp_pairheap_init_node(soft_timer_lt, &entry->pairheap);
uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV);
MP_STATE_PORT(soft_timer_heap) = (soft_timer_entry_t *)mp_pairheap_push(soft_timer_lt, &MP_STATE_PORT(soft_timer_heap)->pairheap, &entry->pairheap);
if (entry == MP_STATE_PORT(soft_timer_heap)) {
// This new timer became the earliest one so set soft_timer_next
soft_timer_schedule_systick(entry->expiry_ms);
*heap = (soft_timer_entry_t *)mp_pairheap_push(soft_timer_lt, &(*heap)->pairheap, &entry->pairheap);
if (entry == *heap) {
// This new timer became the earliest on this heap.
if (other_heap == NULL || TICKS_DIFF(entry->expiry_ms, other_heap->expiry_ms) < 0) {
// This new timer became the earliest of all, so set soft_timer_next.
soft_timer_schedule_systick(entry->expiry_ms);
}
}
restore_irq_pri(irq_state);
}

void soft_timer_remove(soft_timer_entry_t *entry) {
STATIC void soft_timer_remove_from(soft_timer_entry_t **heap, soft_timer_entry_t *entry) {
uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV);
MP_STATE_PORT(soft_timer_heap) = (soft_timer_entry_t *)mp_pairheap_delete(soft_timer_lt, &MP_STATE_PORT(soft_timer_heap)->pairheap, &entry->pairheap);
*heap = (soft_timer_entry_t *)mp_pairheap_delete(soft_timer_lt, &(*heap)->pairheap, &entry->pairheap);
restore_irq_pri(irq_state);
}

void soft_timer_static_init(soft_timer_entry_t *entry, uint16_t mode, uint32_t delta_ms, void (*cb)(soft_timer_entry_t *)) {
entry->flags = 0;
entry->mode = mode;
entry->expiry_ms = mp_hal_ticks_ms() + delta_ms;
entry->delta_ms = delta_ms;
entry->c_callback = cb;
soft_timer_insert_to(&soft_timer_static_heap, MP_STATE_VM(soft_timer_heap), entry);
}

void soft_timer_insert(soft_timer_entry_t *entry) {
soft_timer_insert_to(&MP_STATE_VM(soft_timer_heap), soft_timer_static_heap, entry);
}

void soft_timer_remove(soft_timer_entry_t *entry) {
soft_timer_remove_from(&MP_STATE_VM(soft_timer_heap), entry);
}
12 changes: 10 additions & 2 deletions ports/stm32/softtimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,29 @@

#include "py/pairheap.h"

#define SOFT_TIMER_FLAG_PY_CALLBACK (1)

#define SOFT_TIMER_MODE_ONE_SHOT (1)
#define SOFT_TIMER_MODE_PERIODIC (2)

typedef struct _soft_timer_entry_t {
mp_pairheap_t pairheap;
uint32_t mode;
uint16_t flags;
uint16_t mode;
uint32_t expiry_ms;
uint32_t delta_ms; // for periodic mode
mp_obj_t callback;
union {
void (*c_callback)(struct _soft_timer_entry_t *);
mp_obj_t py_callback;
};
} soft_timer_entry_t;

extern volatile uint32_t soft_timer_next;

void soft_timer_deinit(void);
void soft_timer_handler(void);

void soft_timer_static_init(soft_timer_entry_t *entry, uint16_t mode, uint32_t delta_ms, void (*cb)(soft_timer_entry_t *));
void soft_timer_insert(soft_timer_entry_t *entry);
void soft_timer_remove(soft_timer_entry_t *entry);

Expand Down