diff options
-rw-r--r-- | ports/esp8266/modmachine.c | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 58368b8f0..ccde1e5ed 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -167,12 +167,49 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep); +// These values are from the datasheet +#define ESP_TIMER_US_MIN (100) +#define ESP_TIMER_US_MAX (0xfffffff) +#define ESP_TIMER_MS_MAX (0x689d0) + typedef struct _esp_timer_obj_t { mp_obj_base_t base; os_timer_t timer; + uint32_t remain_ms; // if non-zero, remaining time to handle large periods + uint32_t period_ms; // if non-zero, periodic timer with a large period mp_obj_t callback; } esp_timer_obj_t; +STATIC void esp_timer_arm_ms(esp_timer_obj_t *self, uint32_t ms, bool repeat) { + if (ms <= ESP_TIMER_MS_MAX) { + self->remain_ms = 0; + self->period_ms = 0; + } else { + self->remain_ms = ms - ESP_TIMER_MS_MAX; + if (repeat) { + repeat = false; + self->period_ms = ms; + } else { + self->period_ms = 0; + } + ms = ESP_TIMER_MS_MAX; + } + os_timer_arm(&self->timer, ms, repeat); +} + +STATIC void esp_timer_arm_us(esp_timer_obj_t *self, uint32_t us, bool repeat) { + if (us < ESP_TIMER_US_MIN) { + us = ESP_TIMER_US_MIN; + } + if (us <= ESP_TIMER_US_MAX) { + self->remain_ms = 0; + self->period_ms = 0; + os_timer_arm_us(&self->timer, us, repeat); + } else { + esp_timer_arm_ms(self, us / 1000, repeat); + } +} + const mp_obj_type_t esp_timer_type; STATIC void esp_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -189,7 +226,21 @@ STATIC mp_obj_t esp_timer_make_new(const mp_obj_type_t *type, size_t n_args, siz STATIC void esp_timer_cb(void *arg) { esp_timer_obj_t *self = arg; - mp_sched_schedule(self->callback, self); + if (self->remain_ms != 0) { + // Handle periods larger than the maximum system period + uint32_t next_period_ms = self->remain_ms; + if (next_period_ms > ESP_TIMER_MS_MAX) { + next_period_ms = ESP_TIMER_MS_MAX; + } + self->remain_ms -= next_period_ms; + os_timer_arm(&self->timer, next_period_ms, false); + } else { + mp_sched_schedule(self->callback, self); + if (self->period_ms != 0) { + // A periodic timer with a larger period: reschedule it + esp_timer_arm_ms(self, self->period_ms, true); + } + } } STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -225,30 +276,30 @@ STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_t n_args, cons if (args[ARG_freq].u_obj != mp_const_none) { mp_float_t freq = mp_obj_get_float(args[ARG_freq].u_obj); if (freq < 0.001) { - os_timer_arm(&self->timer, (mp_int_t)(1000 / freq), args[ARG_mode].u_int); + esp_timer_arm_ms(self, (mp_int_t)(1000 / freq), args[ARG_mode].u_int); } else { - os_timer_arm_us(&self->timer, (mp_int_t)(1000000 / freq), args[ARG_mode].u_int); + esp_timer_arm_us(self, (mp_int_t)(1000000 / freq), args[ARG_mode].u_int); } } #else if (args[ARG_freq].u_int != 0xffffffff) { - os_timer_arm_us(&self->timer, 1000000 / args[ARG_freq].u_int, args[ARG_mode].u_int); + esp_timer_arm_us(self, 1000000 / args[ARG_freq].u_int, args[ARG_mode].u_int); } #endif else { mp_int_t period = args[ARG_period].u_int; mp_int_t hz = args[ARG_tick_hz].u_int; if (hz == 1000) { - os_timer_arm(&self->timer, period, args[ARG_mode].u_int); + esp_timer_arm_ms(self, period, args[ARG_mode].u_int); } else if (hz == 1000000) { - os_timer_arm_us(&self->timer, period, args[ARG_mode].u_int); + esp_timer_arm_us(self, period, args[ARG_mode].u_int); } else { // Use a long long to ensure that we don't either overflow or loose accuracy uint64_t period_us = (((uint64_t)period) * 1000000) / hz; if (period_us < 0x80000000ull) { - os_timer_arm_us(&self->timer, (mp_int_t)period_us, args[ARG_mode].u_int); + esp_timer_arm_us(self, (mp_int_t)period_us, args[ARG_mode].u_int); } else { - os_timer_arm(&self->timer, (mp_int_t)(period_us / 1000), args[ARG_mode].u_int); + esp_timer_arm_ms(self, (mp_int_t)(period_us / 1000), args[ARG_mode].u_int); } } } |