esp8266/modmachine: Handle overflow of timer to get longer periods.
Can now handle up to about 298 days maximum for millisecond periods. Fixes issue #4664.
This commit is contained in:
parent
c0a1de3c21
commit
99a8fa7940
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue