summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/esp8266/modmachine.c67
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);
}
}
}