diff options
-rw-r--r-- | docs/mimxrt/quickref.rst | 9 | ||||
-rw-r--r-- | ports/mimxrt/Makefile | 1 | ||||
-rw-r--r-- | ports/mimxrt/board_init.c | 3 | ||||
-rw-r--r-- | ports/mimxrt/machine_timer.c | 158 | ||||
-rw-r--r-- | ports/mimxrt/main.c | 2 | ||||
-rw-r--r-- | ports/mimxrt/mphalport.h | 4 | ||||
-rw-r--r-- | ports/mimxrt/systick.c | 7 |
7 files changed, 58 insertions, 126 deletions
diff --git a/docs/mimxrt/quickref.rst b/docs/mimxrt/quickref.rst index c75fe60c8d..06f91f7f50 100644 --- a/docs/mimxrt/quickref.rst +++ b/docs/mimxrt/quickref.rst @@ -56,21 +56,18 @@ Use the :mod:`time <time>` module:: Timers ------ -The i.MXRT port has three hardware timers. Use the :ref:`machine.Timer <machine.Timer>` class -with a timer ID from 0 to 2 (inclusive):: +The i.MXRT port supports virtual Timers. Example of usage:: from machine import Timer - tim0 = Timer(0) + tim0 = Timer(-1) tim0.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(0)) - tim1 = Timer(1) + tim1 = Timer(-1) tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1)) The period is in milliseconds. -Virtual timers are not currently supported on this port. - .. _mimxrt_Pins_and_GPIO: Pins and GPIO diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 2119e027ef..db03b7bef2 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -193,6 +193,7 @@ SHARED_SRC_C += \ shared/runtime/interrupt_char.c \ shared/runtime/mpirq.c \ shared/runtime/pyexec.c \ + shared/runtime/softtimer.c \ shared/runtime/stdout_helpers.c \ shared/runtime/sys_stdio_mphal.c \ shared/timeutils/timeutils.c \ diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 12496890ac..d0625aac37 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -89,9 +89,6 @@ void board_init(void) { // ADC machine_adc_init(); - // PIT - machine_timer_init_PIT(); - // SDCard #if MICROPY_PY_MACHINE_SDCARD machine_sdcard_init0(); diff --git a/ports/mimxrt/machine_timer.c b/ports/mimxrt/machine_timer.c index a237272390..54ae06b6b3 100644 --- a/ports/mimxrt/machine_timer.c +++ b/ports/mimxrt/machine_timer.c @@ -26,66 +26,24 @@ */ #include "py/runtime.h" -#include "py/mperrno.h" #include "py/mphal.h" -#include "fsl_pit.h" -#include "modmachine.h" -#include CLOCK_CONFIG_H - -#define TIMER_MODE_ONE_SHOT (0) -#define TIMER_MODE_PERIODIC (1) -#define TIMER_MIN_PERIOD 1 - -#define alarm_callback PIT_IRQHandler -#define PIT_IRQ_ID PIT_IRQn - -typedef struct _machine_timer_obj_t { - mp_obj_base_t base; - int8_t id; - int8_t channel; - uint32_t mode; - uint32_t tick_hz; - uint32_t delta_us; // for periodic mode - mp_obj_t callback; -} machine_timer_obj_t; - -static const int8_t channel_no[MICROPY_HW_PIT_NUM_CHANNELS] = {0, 2, 3}; // no channel 1 -static pit_config_t pit_config; - -// This is the interrupt handler -// To tell which channel fired one has to poll the flags -void alarm_callback(void) { - for (uint8_t index = 0; index < MICROPY_HW_PIT_NUM_CHANNELS; index++) { - uint32_t flag; - machine_timer_obj_t *self = MP_STATE_PORT(timer_table)[index]; - if (self != NULL) { - flag = PIT_GetStatusFlags(PIT, self->channel); - if (flag & kPIT_TimerFlag) { // channel fired - PIT_ClearStatusFlags(PIT, self->channel, kPIT_TimerFlag); - __DSB(); - - mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self)); - - if (self->mode == TIMER_MODE_ONE_SHOT) { - PIT_StopTimer(PIT, self->channel); - } - } - } - } -} +#include "shared/runtime/softtimer.h" + +typedef soft_timer_entry_t machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); - qstr mode = self->mode == TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC; - mp_printf(print, "Timer(channel=%d, mode=%q, period=%d, tick_hz=%d)", - self->id, mode, self->delta_us / self->tick_hz, self->tick_hz); + qstr mode = self->mode == SOFT_TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC; + mp_printf(print, "Timer(mode=%q, period=%u)", mode, self->delta_ms); } STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC} }, - { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOFT_TIMER_MODE_PERIODIC} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, @@ -96,67 +54,56 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_ar mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); self->mode = args[ARG_mode].u_int; + + uint64_t delta_ms = self->delta_ms; if (args[ARG_freq].u_obj != mp_const_none) { // Frequency specified in Hz #if MICROPY_PY_BUILTINS_FLOAT - self->delta_us = (uint32_t)(MICROPY_FLOAT_CONST(1000000.0) / mp_obj_get_float(args[ARG_freq].u_obj)); + delta_ms = (uint32_t)(MICROPY_FLOAT_CONST(1000.0) / mp_obj_get_float(args[ARG_freq].u_obj)); #else - self->delta_us = 1000000 / mp_obj_get_int(args[ARG_freq].u_obj); + delta_ms = 1000 / mp_obj_get_int(args[ARG_freq].u_obj); #endif - } else { + } else if (args[ARG_period].u_int != 0xffffffff) { // Period specified - self->tick_hz = args[ARG_tick_hz].u_int; - self->delta_us = (uint64_t)args[ARG_period].u_int * 1000000 / self->tick_hz; - } - if (self->delta_us < TIMER_MIN_PERIOD) { - self->delta_us = TIMER_MIN_PERIOD; + delta_ms = (uint64_t)args[ARG_period].u_int * 1000 / args[ARG_tick_hz].u_int; } - self->callback = args[ARG_callback].u_obj; - - // Set timer period for channel id - PIT_SetTimerPeriod(PIT, self->channel, USEC_TO_COUNT(self->delta_us, BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT)); - - // Enable timer interrupts for the channel - PIT_EnableInterrupts(PIT, self->channel, kPIT_TimerInterruptEnable); + if (delta_ms < 1) { + delta_ms = 1; + } else if (delta_ms >= 0x40000000) { + mp_raise_ValueError(MP_ERROR_TEXT("period too large")); + } + self->delta_ms = (uint32_t)delta_ms; - // Enable at the NVIC - EnableIRQ(PIT_IRQ_ID); + if (args[ARG_callback].u_obj != MP_OBJ_NULL) { + self->py_callback = args[ARG_callback].u_obj; + } - // Start channel 0 - PIT_StartTimer(PIT, self->channel); + if (self->py_callback != mp_const_none) { + soft_timer_insert(self, self->delta_ms); + } return mp_const_none; } 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; - - // Get timer id in the range of 0..2 - mp_int_t id = 0; + 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 | SOFT_TIMER_FLAG_GC_ALLOCATED; + self->delta_ms = 1000; + self->py_callback = mp_const_none; + + // Get timer id (only soft timer (-1) supported at the moment) + mp_int_t id = -1; if (n_args > 0) { id = mp_obj_get_int(args[0]); --n_args; ++args; } - if (id < 0 || id >= MICROPY_HW_PIT_NUM_CHANNELS) { - mp_raise_ValueError(MP_ERROR_TEXT("Timer does not exist")); + if (id != -1) { + mp_raise_ValueError(MP_ERROR_TEXT("Timer doesn't exist")); } - // check, if a timer exists at that channel and stop it first - if (MP_STATE_PORT(timer_table)[id] != NULL) { - PIT_StopTimer(PIT, channel_no[id]); - self = MP_STATE_PORT(timer_table)[id]; - } else { - self = m_new_obj_with_finaliser(machine_timer_obj_t); - self->base.type = &machine_timer_type; - MP_STATE_PORT(timer_table)[id] = self; - } - - // Set initial values - self->id = id; - self->channel = channel_no[id]; - if (n_args > 0 || n_kw > 0) { // Start the timer mp_map_t kw_args; @@ -167,47 +114,26 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t machine_timer___del__(mp_obj_t self_in) { - machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); - PIT_StopTimer(PIT, self->channel); - MP_STATE_PORT(timer_table)[self->id] = NULL; - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer___del___obj, machine_timer___del__); - STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { machine_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); - PIT_StopTimer(PIT, self->channel); + soft_timer_remove(self); return machine_timer_init_helper(self, n_args - 1, args + 1, kw_args); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init); STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); - PIT_StopTimer(PIT, self->channel); + soft_timer_remove(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); -// Initialize clock an first config -void machine_timer_init_PIT(void) { - // PIT timer - // Enable clock gate for GPIO1 - CLOCK_EnableClock(kCLOCK_Gpio1); // ? - // Set PERCLK_CLK divider to 1 - CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U); - - PIT_GetDefaultConfig(&pit_config); - PIT_Init(PIT, &pit_config); -} - STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer___del___obj) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_MODE_ONE_SHOT) }, - { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(SOFT_TIMER_MODE_ONE_SHOT) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(SOFT_TIMER_MODE_PERIODIC) }, }; STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); @@ -219,5 +145,3 @@ MP_DEFINE_CONST_OBJ_TYPE( print, machine_timer_print, locals_dict, &machine_timer_locals_dict ); - -MP_REGISTER_ROOT_POINTER(struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]); diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 82e07868a1..b81a44e278 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -33,6 +33,7 @@ #include "shared/readline/readline.h" #include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" +#include "shared/runtime/softtimer.h" #include "ticks.h" #include "tusb.h" #include "led.h" @@ -120,6 +121,7 @@ int main(void) { mod_network_deinit(); #endif machine_pwm_deinit_all(); + soft_timer_deinit(); gc_sweep_all(); mp_deinit(); } diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index 124b905604..30390a4a4c 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -38,6 +38,10 @@ #define MP_HAL_PIN_FMT "%q" extern ringbuf_t stdin_ringbuf; +// Define an alias fo systick_ms, because the shared softtimer.c uses +// the symbol uwTick for the systick ms counter. +#define uwTick systick_ms + #define mp_hal_pin_obj_t const machine_pin_obj_t * #define mp_hal_get_pin_obj(o) pin_find(o) #define mp_hal_pin_name(p) ((p)->name) diff --git a/ports/mimxrt/systick.c b/ports/mimxrt/systick.c index 086bf16701..8b0f5eb7b2 100644 --- a/ports/mimxrt/systick.c +++ b/ports/mimxrt/systick.c @@ -28,6 +28,9 @@ #include "py/mphal.h" #include "systick.h" +#include "pendsv.h" +#include "shared/runtime/softtimer.h" + volatile uint32_t systick_ms = 0; systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS]; @@ -44,6 +47,10 @@ void SysTick_Handler(void) { if (f != NULL) { f(uw_tick); } + + if (soft_timer_next == uw_tick) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler); + } } bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) { |