stm32/softtimer: Change linear linked list to a pairing heap.

pull/5525/head
Damien George 2020-01-13 17:12:50 +11:00
rodzic fe203bb3e2
commit f70373c7b2
4 zmienionych plików z 26 dodań i 42 usunięć

Wyświetl plik

@ -77,7 +77,7 @@ 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->base.type = &machine_timer_type;
self->pairheap.base.type = &machine_timer_type;
// Get timer id (only soft timer (-1) supported at the moment)
mp_int_t id = -1;

Wyświetl plik

@ -281,7 +281,7 @@ struct _mp_bluetooth_nimble_root_pointers_t;
\
mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \
\
struct _soft_timer_entry_t *soft_timer_head; \
struct _soft_timer_entry_t *soft_timer_heap; \
\
/* pointers to all Timer objects (if they have been created) */ \
struct _pyb_timer_obj_t *pyb_timer_obj_all[MICROPY_HW_MAX_TIMER]; \

Wyświetl plik

@ -37,7 +37,13 @@ extern __IO uint32_t uwTick;
volatile uint32_t soft_timer_next;
void soft_timer_deinit(void) {
MP_STATE_PORT(soft_timer_head) = NULL;
MP_STATE_PORT(soft_timer_heap) = NULL;
}
STATIC int soft_timer_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
soft_timer_entry_t *e1 = (soft_timer_entry_t*)n1;
soft_timer_entry_t *e2 = (soft_timer_entry_t*)n2;
return TICKS_DIFF(e1->expiry_ms, e2->expiry_ms) < 0;
}
STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) {
@ -54,59 +60,38 @@ STATIC void soft_timer_schedule_systick(uint32_t ticks_ms) {
// Must be executed at IRQ_PRI_PENDSV
void soft_timer_handler(void) {
uint32_t ticks_ms = uwTick;
soft_timer_entry_t *head = MP_STATE_PORT(soft_timer_head);
while (head != NULL && TICKS_DIFF(head->expiry_ms, ticks_ms) <= 0) {
mp_sched_schedule(head->callback, MP_OBJ_FROM_PTR(head));
if (head->mode == SOFT_TIMER_MODE_PERIODIC) {
head->expiry_ms += head->delta_ms;
// Shift this node along to its new position
soft_timer_entry_t *cur = head;
while (cur->next != NULL && TICKS_DIFF(head->expiry_ms, cur->next->expiry_ms) >= 0) {
cur = cur->next;
}
if (cur != head) {
soft_timer_entry_t *next = head->next;
head->next = cur->next;
cur->next = head;
head = next;
}
} else {
head = head->next;
soft_timer_entry_t *heap = MP_STATE_PORT(soft_timer_heap);
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->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_head) = head;
if (head == NULL) {
MP_STATE_PORT(soft_timer_heap) = heap;
if (heap == NULL) {
// 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(head->expiry_ms);
soft_timer_schedule_systick(heap->expiry_ms);
}
}
void soft_timer_insert(soft_timer_entry_t *entry) {
uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV);
soft_timer_entry_t **head_ptr = &MP_STATE_PORT(soft_timer_head);
while (*head_ptr != NULL && TICKS_DIFF(entry->expiry_ms, (*head_ptr)->expiry_ms) >= 0) {
head_ptr = &(*head_ptr)->next;
}
entry->next = *head_ptr;
*head_ptr = entry;
if (head_ptr == &MP_STATE_PORT(soft_timer_head)) {
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((*head_ptr)->expiry_ms);
soft_timer_schedule_systick(entry->expiry_ms);
}
restore_irq_pri(irq_state);
}
void soft_timer_remove(soft_timer_entry_t *entry) {
uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV);
soft_timer_entry_t **cur = &MP_STATE_PORT(soft_timer_head);
while (*cur != NULL) {
if (*cur == entry) {
*cur = entry->next;
break;
}
}
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);
restore_irq_pri(irq_state);
}

Wyświetl plik

@ -26,14 +26,13 @@
#ifndef MICROPY_INCLUDED_STM32_SOFTTIMER_H
#define MICROPY_INCLUDED_STM32_SOFTTIMER_H
#include "py/obj.h"
#include "py/pairheap.h"
#define SOFT_TIMER_MODE_ONE_SHOT (1)
#define SOFT_TIMER_MODE_PERIODIC (2)
typedef struct _soft_timer_entry_t {
mp_obj_base_t base; // so struct can be used as an object and still be traced by GC
struct _soft_timer_entry_t *next;
mp_pairheap_t pairheap;
uint32_t mode;
uint32_t expiry_ms;
uint32_t delta_ms; // for periodic mode