summaryrefslogtreecommitdiff
path: root/libhw/rp2040_hwtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhw/rp2040_hwtimer.c')
-rw-r--r--libhw/rp2040_hwtimer.c153
1 files changed, 0 insertions, 153 deletions
diff --git a/libhw/rp2040_hwtimer.c b/libhw/rp2040_hwtimer.c
deleted file mode 100644
index ada6246..0000000
--- a/libhw/rp2040_hwtimer.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/* libhw/rp2040_hwtimer.c - <libhw/generic/alarmclock.h> implementation for the RP2040's hardware timer
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <hardware/irq.h> /* pico-sdk:hardware_irq */
-#include <hardware/timer.h> /* pico-sdk:hardware_timer */
-
-#include <libcr/coroutine.h>
-#include <libmisc/assert.h>
-
-#define IMPLEMENTATION_FOR_LIBHW_GENERIC_ALARMCLOCK_H YES
-#include <libhw/generic/alarmclock.h>
-
-#include <libhw/rp2040_hwtimer.h>
-
-/******************************************************************************/
-
-/** Conflict with pico-sdk:pico_time:!PICO_TIME_DEFAULT_ALARM_POOL_DISABLED. */
-void add_alarm_at(void) {};
-
-/* Types **********************************************************************/
-
-struct rp2040_hwtimer {
- enum rp2040_hwalarm_instance alarm_num;
- bool initialized;
- struct alarmclock_trigger *queue;
-};
-LO_IMPLEMENTATION_H(alarmclock, struct rp2040_hwtimer, rp2040_hwtimer);
-LO_IMPLEMENTATION_C(alarmclock, struct rp2040_hwtimer, rp2040_hwtimer, static);
-
-/* Globals ********************************************************************/
-
-static struct rp2040_hwtimer hwtimers[] = {
- { .alarm_num = 0 },
- { .alarm_num = 1 },
- { .alarm_num = 2 },
- { .alarm_num = 3 },
-};
-static_assert(sizeof(hwtimers)/sizeof(hwtimers[0]) == _RP2040_HWALARM_NUM);
-
-/* Main implementation ********************************************************/
-
-lo_interface alarmclock rp2040_hwtimer(enum rp2040_hwalarm_instance alarm_num) {
- assert(alarm_num < _RP2040_HWALARM_NUM);
- return lo_box_rp2040_hwtimer_as_alarmclock(&hwtimers[alarm_num]);
-}
-
-
-static uint64_t rp2040_hwtimer_get_time_ns(struct rp2040_hwtimer *) {
- return timer_time_us_64(timer_hw) * (NS_PER_S/US_PER_S);
-}
-
-#define NS_TO_US_ROUNDUP(x) LM_CEILDIV(x, NS_PER_S/US_PER_S)
-
-static void rp2040_hwtimer_intrhandler(void) {
- uint irq_num = __get_current_exception() - VTABLE_FIRST_IRQ;
- enum rp2040_hwalarm_instance alarm_num = TIMER_ALARM_NUM_FROM_IRQ(irq_num);
- assert(alarm_num < _RP2040_HWALARM_NUM);
-
- struct rp2040_hwtimer *alarmclock = &hwtimers[alarm_num];
-
- while (alarmclock->queue &&
- NS_TO_US_ROUNDUP(alarmclock->queue->fire_at_ns) <= timer_time_us_64(timer_hw)) {
- struct alarmclock_trigger *trigger = alarmclock->queue;
- trigger->cb(trigger->cb_arg);
- alarmclock->queue = trigger->next;
- trigger->alarmclock = NULL;
- trigger->next = NULL;
- trigger->prev = NULL;
- }
-
- hw_clear_bits(&timer_hw->intf, 1 << alarm_num); /* Clear "force"ing the interrupt. */
- hw_clear_bits(&timer_hw->intr, 1 << alarm_num); /* Clear natural firing of the alarm. */
- if (alarmclock->queue)
- timer_hw->alarm[alarm_num] = (uint32_t)NS_TO_US_ROUNDUP(alarmclock->queue->fire_at_ns);
-}
-
-static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
- struct alarmclock_trigger *trigger,
- uint64_t fire_at_ns,
- void (*cb)(void *),
- void *cb_arg) {
- assert(alarmclock);
- assert(trigger);
- assert(fire_at_ns);
- assert(cb);
-
- uint64_t now_us = timer_time_us_64(timer_hw);
- if (NS_TO_US_ROUNDUP(fire_at_ns) > now_us &&
- (NS_TO_US_ROUNDUP(fire_at_ns) - now_us) > UINT32_MAX)
- /* Too far in the future. */
- return true;
-
- trigger->alarmclock = alarmclock;
- trigger->fire_at_ns = fire_at_ns;
- trigger->cb = cb;
- trigger->cb_arg = cb_arg;
-
- bool saved = cr_save_and_disable_interrupts();
- struct alarmclock_trigger **dst = &alarmclock->queue;
- while (*dst && fire_at_ns >= (*dst)->fire_at_ns)
- dst = &(*dst)->next;
- trigger->next = *dst;
- trigger->prev = *dst ? (*dst)->prev : NULL;
- if (*dst)
- (*dst)->prev = trigger;
- *dst = trigger;
- if (!alarmclock->initialized) {
- hw_set_bits(&timer_hw->inte, 1 << alarmclock->alarm_num);
- irq_set_exclusive_handler(TIMER_ALARM_IRQ_NUM(timer_hw, alarmclock->alarm_num),
- rp2040_hwtimer_intrhandler);
- irq_set_enabled(TIMER_ALARM_IRQ_NUM(timer_hw, alarmclock->alarm_num), true);
- alarmclock->initialized = true;
- }
- if (alarmclock->queue == trigger) {
- /* "Force" the interrupt handler to trigger as soon as
- * we enable interrupts. This handles the case of
- * when fire_at_ns is before when we called
- * cr_save_and_disable_interrupts(). We could check
- * timer_time_us_64() again after calling
- * cr_save_and_disable_interrupts() and do this
- * conditionally, but I don't think that would be any
- * more efficient than just letting the interrupt
- * fire. */
- hw_set_bits(&timer_hw->intf, 1 << alarmclock->alarm_num);
- }
- cr_restore_interrupts(saved);
-
- return false;
-}
-
-static void rp2040_hwtimer_del_trigger(struct rp2040_hwtimer *alarmclock,
- struct alarmclock_trigger *trigger) {
- assert(alarmclock);
- assert(trigger);
-
- bool saved = cr_save_and_disable_interrupts();
- if (trigger->alarmclock == alarmclock) {
- if (!trigger->prev)
- alarmclock->queue = trigger->next;
- else
- trigger->prev->next = trigger->next;
- if (trigger->next)
- trigger->next->prev = trigger->prev;
- trigger->alarmclock = NULL;
- trigger->prev = NULL;
- trigger->next = NULL;
- } else
- assert(!trigger->alarmclock);
- cr_restore_interrupts(saved);
-}