summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--docs/esp32/quickref.rst15
-rw-r--r--ports/esp32/adc.c94
-rw-r--r--ports/esp32/adc.h47
-rw-r--r--ports/esp32/boards/sdkconfig.base1
-rw-r--r--ports/esp32/machine_adc.c95
-rw-r--r--ports/esp32/machine_adc_block.c14
-rw-r--r--ports/esp32/machine_timer.c46
-rw-r--r--ports/esp32/machine_timer.h3
-rw-r--r--ports/esp32/machine_uart.c35
-rw-r--r--ports/esp32/modesp32.c1
-rw-r--r--ports/esp32/mpconfigport.h1
-rw-r--r--tests/misc/print_exception.py2
-rwxr-xr-xtests/run-tests.py73
-rwxr-xr-xtools/ci.sh21
14 files changed, 266 insertions, 182 deletions
diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 63180b470a..c394414a76 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -544,14 +544,27 @@ Legacy methods:
Equivalent to ``ADC.block().init(bits=bits)``.
+The only chip that can switch resolution to a lower one is the normal esp32.
+The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits.
+
For compatibility, the ``ADC`` object also provides constants matching the
-supported ADC resolutions:
+supported ADC resolutions, per chip:
+ESP32:
- ``ADC.WIDTH_9BIT`` = 9
- ``ADC.WIDTH_10BIT`` = 10
- ``ADC.WIDTH_11BIT`` = 11
- ``ADC.WIDTH_12BIT`` = 12
+ESP32 C3 & S3:
+ - ``ADC.WIDTH_12BIT`` = 12
+
+ESP32 S2:
+ - ``ADC.WIDTH_13BIT`` = 13
+
+.. method:: ADC.deinit()
+
+ Provided to deinit the adc driver.
Software SPI bus
----------------
diff --git a/ports/esp32/adc.c b/ports/esp32/adc.c
index 83af6dce0b..d0e5e81330 100644
--- a/ports/esp32/adc.c
+++ b/ports/esp32/adc.c
@@ -26,83 +26,73 @@
*/
#include "py/mphal.h"
+#include "py/mperrno.h"
#include "adc.h"
-#include "driver/adc.h"
+#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali_scheme.h"
-#define DEFAULT_VREF 1100
+static esp_err_t ensure_adc_calibration(machine_adc_block_obj_t *self, adc_atten_t atten);
-void madcblock_bits_helper(machine_adc_block_obj_t *self, mp_int_t bits) {
- if (bits < SOC_ADC_RTC_MIN_BITWIDTH && bits > SOC_ADC_RTC_MAX_BITWIDTH) {
- // Invalid value for the current chip, raise exception in the switch below.
- bits = -1;
+void adc_is_init_guard(machine_adc_block_obj_t *self) {
+ if (!self->handle) {
+ mp_raise_OSError(MP_EPERM);
}
- switch (bits) {
- case 9:
- self->width = ADC_BITWIDTH_9;
- break;
- case 10:
- self->width = ADC_BITWIDTH_10;
- break;
- case 11:
- self->width = ADC_BITWIDTH_11;
- break;
- case 12:
- self->width = ADC_BITWIDTH_12;
- break;
- case 13:
- self->width = ADC_BITWIDTH_13;
- break;
- default:
- mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
- }
- self->bits = bits;
+}
- if (self->unit_id == ADC_UNIT_1) {
- adc1_config_width(self->width);
- }
+esp_err_t apply_self_adc_channel_atten(const machine_adc_obj_t *self, uint8_t atten) {
+ adc_is_init_guard(self->block);
+
+ adc_oneshot_chan_cfg_t config = {
+ .atten = atten,
+ .bitwidth = self->block->bitwidth,
+ };
+ esp_err_t ret = adc_oneshot_config_channel(self->block->handle, self->channel_id, &config);
+ return ret;
}
mp_int_t madcblock_read_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id) {
- int raw = 0;
- if (self->unit_id == ADC_UNIT_1) {
- raw = adc1_get_raw(channel_id);
- } else {
- #if (SOC_ADC_PERIPH_NUM >= 2)
- check_esp_err(adc2_get_raw(channel_id, self->width, &raw));
- #endif
- }
- return raw;
+ adc_is_init_guard(self);
+
+ int reading = 0;
+ adc_oneshot_read(self->handle, channel_id, &reading);
+ return reading;
+}
+
+/*
+During testing, it turned out that the function `adc_cali_raw_to_voltage` does not account for the lower resolution,
+instead it expects the full resolution value as an argument, hence the scaling applied here
+*/
+mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten) {
+ int raw = madcblock_read_helper(self, channel_id);
+ int uv = 0;
+
+ check_esp_err(ensure_adc_calibration(self, atten));
+ check_esp_err(adc_cali_raw_to_voltage(self->calib[atten], (raw << (ADC_WIDTH_MAX - self->bitwidth)), &uv));
+ return (mp_int_t)uv * 1000;
}
static esp_err_t ensure_adc_calibration(machine_adc_block_obj_t *self, adc_atten_t atten) {
- if (self->handle[atten] != NULL) {
+ if (self->calib[atten] != NULL) {
return ESP_OK;
}
+ esp_err_t ret = ESP_OK;
+
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = self->unit_id,
.atten = atten,
- .bitwidth = self->width,
+ .bitwidth = self->bitwidth,
};
- return adc_cali_create_scheme_curve_fitting(&cali_config, &self->handle[atten]);
+ ret = adc_cali_create_scheme_curve_fitting(&cali_config, &self->calib[atten]);
#else
adc_cali_line_fitting_config_t cali_config = {
.unit_id = self->unit_id,
.atten = atten,
- .bitwidth = self->width,
+ .bitwidth = self->bitwidth,
};
- return adc_cali_create_scheme_line_fitting(&cali_config, &self->handle[atten]);
+ ret = adc_cali_create_scheme_line_fitting(&cali_config, &self->calib[atten]);
#endif
-}
-mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten) {
- int raw = madcblock_read_helper(self, channel_id);
- int uv;
-
- check_esp_err(ensure_adc_calibration(self, atten));
- check_esp_err(adc_cali_raw_to_voltage(self->handle[atten], raw, &uv));
-
- return (mp_int_t)uv * 1000;
+ return ret;
}
diff --git a/ports/esp32/adc.h b/ports/esp32/adc.h
index 5688e0a29a..ebf7fcc21a 100644
--- a/ports/esp32/adc.h
+++ b/ports/esp32/adc.h
@@ -29,17 +29,45 @@
#define MICROPY_INCLUDED_ESP32_ADC_H
#include "py/runtime.h"
-#include "esp_adc_cal.h"
+#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali_scheme.h"
-#define ADC_ATTEN_MAX SOC_ADC_ATTEN_NUM
+#define ADC_ATTEN_COUNT SOC_ADC_ATTEN_NUM
+#define ADC_ATTEN_MIN ADC_ATTEN_DB_0
+#define ADC_ATTEN_MAX ADC_ATTEN_DB_11
+
+/*
+https://github.com/espressif/esp-idf/issues/13128
+https://github.com/espressif/esp-idf/blob/release/v5.2/components/soc/esp32s3/include/soc/soc_caps.h
+https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32s2/03-errata-description/index.html
+https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32/api-reference/peripherals/adc.html
+
+Looks like only the original esp32 is capable of bitwidth adjustment, all others are stuck at 12 bits,
+except the S2, which is locked at 13 bits, otherwise attenuation doesn't work.
+*/
+#if CONFIG_IDF_TARGET_ESP32S2
+
+#define ADC_WIDTH_MIN ADC_BITWIDTH_13
+#define ADC_WIDTH_MAX ADC_BITWIDTH_13
+
+#elif CONFIG_IDF_TARGET_ESP32
+
+#define ADC_WIDTH_MIN ADC_BITWIDTH_9
+#define ADC_WIDTH_MAX ADC_BITWIDTH_12
+
+#else
+
+#define ADC_WIDTH_MIN ADC_BITWIDTH_12
+#define ADC_WIDTH_MAX ADC_BITWIDTH_12
+
+#endif
typedef struct _machine_adc_block_obj_t {
mp_obj_base_t base;
adc_unit_t unit_id;
- mp_int_t bits;
- adc_bits_width_t width;
- adc_cali_handle_t handle[ADC_ATTEN_MAX];
+ adc_oneshot_unit_handle_t handle;
+ adc_bitwidth_t bitwidth;
+ adc_cali_handle_t calib[ADC_ATTEN_COUNT];
} machine_adc_block_obj_t;
typedef struct _machine_adc_obj_t {
@@ -51,11 +79,18 @@ typedef struct _machine_adc_obj_t {
extern machine_adc_block_obj_t madcblock_obj[];
-void madcblock_bits_helper(machine_adc_block_obj_t *self, mp_int_t bits);
+esp_err_t apply_self_adc_channel_atten(const machine_adc_obj_t *self, uint8_t atten);
+
mp_int_t madcblock_read_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id);
mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten);
const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_channel_t channel_id, gpio_num_t gpio_id);
void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
+mp_int_t mp_machine_adc_atten_get_helper(const machine_adc_obj_t *self);
+void mp_machine_adc_atten_set_helper(const machine_adc_obj_t *self, mp_int_t atten);
+
+mp_int_t mp_machine_adc_width_get_helper(const machine_adc_obj_t *self);
+void mp_machine_adc_block_width_set_helper(machine_adc_block_obj_t *self, mp_int_t width);
+
#endif // MICROPY_INCLUDED_ESP32_ADC_H
diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base
index 5595444e86..823b916d96 100644
--- a/ports/esp32/boards/sdkconfig.base
+++ b/ports/esp32/boards/sdkconfig.base
@@ -117,7 +117,6 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
CONFIG_UART_ISR_IN_IRAM=y
# IDF 5 deprecated
-CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
CONFIG_ETH_USE_SPI_ETHERNET=y
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index be1725c370..02acaa22da 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -30,7 +30,7 @@
#include "py/mphal.h"
#include "adc.h"
-#include "driver/adc.h"
+#include "esp_adc/adc_oneshot.h"
#define ADCBLOCK1 (&madcblock_obj[0])
#define ADCBLOCK2 (&madcblock_obj[1])
@@ -126,20 +126,8 @@ static const machine_adc_obj_t madc_obj[] = {
#endif
};
-// These values are initialised to 0, which means the corresponding ADC channel is not initialised.
-// The madc_atten_get/madc_atten_set functions store (atten+1) here so that the uninitialised state
-// can be distinguished from the initialised state.
static uint8_t madc_obj_atten[MP_ARRAY_SIZE(madc_obj)];
-static inline adc_atten_t madc_atten_get(const machine_adc_obj_t *self) {
- uint8_t value = madc_obj_atten[self - &madc_obj[0]];
- return value == 0 ? ADC_ATTEN_MAX : value - 1;
-}
-
-static inline void madc_atten_set(const machine_adc_obj_t *self, adc_atten_t atten) {
- madc_obj_atten[self - &madc_obj[0]] = atten + 1;
-}
-
const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_channel_t channel_id, gpio_num_t gpio_id) {
for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) {
const machine_adc_obj_t *adc = &madc_obj[i];
@@ -152,22 +140,7 @@ const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_
static void mp_machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
const machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "ADC(Pin(%u), atten=%u)", self->gpio_id, madc_atten_get(self));
-}
-
-static void madc_atten_helper(const machine_adc_obj_t *self, mp_int_t atten) {
- esp_err_t err = ESP_FAIL;
- if (self->block->unit_id == ADC_UNIT_1) {
- err = adc1_config_channel_atten(self->channel_id, atten);
- } else {
- #if SOC_ADC_PERIPH_NUM >= 2
- err = adc2_config_channel_atten(self->channel_id, atten);
- #endif
- }
- if (err != ESP_OK) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid atten"));
- }
- madc_atten_set(self, atten);
+ mp_printf(print, "ADC(Pin(%u), atten=%u)", self->gpio_id, mp_machine_adc_atten_get_helper(self));
}
void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@@ -182,18 +155,32 @@ void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- mp_int_t atten = args[ARG_atten].u_int;
- if (atten != -1) {
- madc_atten_helper(self, atten);
- } else if (madc_atten_get(self) == ADC_ATTEN_MAX) {
- madc_atten_helper(self, ADC_ATTEN_DB_0);
+
+ if (!self->block->handle) {
+ adc_oneshot_unit_init_cfg_t init_config = {
+ .unit_id = self->block->unit_id
+ };
+ check_esp_err(adc_oneshot_new_unit(&init_config, &self->block->handle));
}
+
+ mp_int_t atten = args[ARG_atten].u_int;
+ mp_machine_adc_atten_set_helper(self, atten != -1 ? atten : ADC_ATTEN_MAX);
+ mp_machine_adc_block_width_set_helper(self->block, ADC_WIDTH_MAX);
+ apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
+
}
static void mp_machine_adc_init_helper(machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
madc_init_helper(self, n_pos_args, pos_args, kw_args);
}
+static void mp_machine_adc_deinit(machine_adc_obj_t *self) {
+ if (self->block->handle) {
+ check_esp_err(adc_oneshot_del_unit(self->block->handle));
+ self->block->handle = NULL;
+ }
+}
+
static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
gpio_num_t gpio_id = machine_pin_get_id(args[0]);
@@ -202,10 +189,6 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_pos_
mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
}
- if (self->block->width == -1) {
- madcblock_bits_helper(self->block, self->block->bits);
- }
-
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
madc_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
@@ -225,20 +208,46 @@ static mp_int_t mp_machine_adc_read(machine_adc_obj_t *self) {
static mp_int_t mp_machine_adc_read_u16(machine_adc_obj_t *self) {
mp_uint_t raw = madcblock_read_helper(self->block, self->channel_id);
// Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16)
- mp_int_t bits = self->block->bits;
+ mp_int_t bits = mp_machine_adc_width_get_helper(self);
mp_uint_t u16 = raw << (16 - bits) | raw >> (2 * bits - 16);
return u16;
}
static mp_int_t mp_machine_adc_read_uv(machine_adc_obj_t *self) {
- adc_atten_t atten = madc_atten_get(self);
- return madcblock_read_uv_helper(self->block, self->channel_id, atten);
+ return madcblock_read_uv_helper(self->block, self->channel_id, mp_machine_adc_atten_get_helper(self));
+}
+
+mp_int_t mp_machine_adc_atten_get_helper(const machine_adc_obj_t *self) {
+ uint8_t value = madc_obj_atten[self - &madc_obj[0]];
+ return value == 0 ? ADC_ATTEN_MAX : value - 1;
+}
+
+void mp_machine_adc_atten_set_helper(const machine_adc_obj_t *self, mp_int_t atten) {
+ if (atten < ADC_ATTEN_MIN || atten > ADC_ATTEN_MAX) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid attenuation"));
+ }
+
+ madc_obj_atten[self - &madc_obj[0]] = atten + 1;
}
static void mp_machine_adc_atten_set(machine_adc_obj_t *self, mp_int_t atten) {
- madc_atten_helper(self, atten);
+ mp_machine_adc_atten_set_helper(self, atten);
+ apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
+}
+
+mp_int_t mp_machine_adc_width_get_helper(const machine_adc_obj_t *self) {
+ return self->block->bitwidth;
+}
+
+void mp_machine_adc_block_width_set_helper(machine_adc_block_obj_t *self, mp_int_t width) {
+ if (width < ADC_WIDTH_MIN || width > ADC_WIDTH_MAX) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid bit-width"));
+ }
+
+ self->bitwidth = width;
}
static void mp_machine_adc_width_set(machine_adc_obj_t *self, mp_int_t width) {
- madcblock_bits_helper(self->block, width);
+ mp_machine_adc_block_width_set_helper(self->block, width);
+ apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
}
diff --git a/ports/esp32/machine_adc_block.c b/ports/esp32/machine_adc_block.c
index a373603b7e..6b06b432c2 100644
--- a/ports/esp32/machine_adc_block.c
+++ b/ports/esp32/machine_adc_block.c
@@ -29,25 +29,21 @@
#include "py/mphal.h"
#include "adc.h"
-#include "driver/adc.h"
+#include "esp_adc/adc_oneshot.h"
machine_adc_block_obj_t madcblock_obj[] = {
- {{&machine_adc_block_type}, ADC_UNIT_1, SOC_ADC_RTC_MAX_BITWIDTH, -1, {0}},
+ {{&machine_adc_block_type}, ADC_UNIT_1, NULL, ADC_WIDTH_MAX, {0}},
#if SOC_ADC_PERIPH_NUM > 1
- {{&machine_adc_block_type}, ADC_UNIT_2, SOC_ADC_RTC_MAX_BITWIDTH, -1, {0}},
+ {{&machine_adc_block_type}, ADC_UNIT_2, NULL, ADC_WIDTH_MAX, {0}},
#endif
};
static void mp_machine_adc_block_print(const mp_print_t *print, machine_adc_block_obj_t *self) {
- mp_printf(print, "ADCBlock(%u, bits=%u)", self->unit_id, self->bits);
+ mp_printf(print, "ADCBlock(%u, bits=%u)", self->unit_id, self->bitwidth);
}
static void mp_machine_adc_block_bits_set(machine_adc_block_obj_t *self, mp_int_t bits) {
- if (bits != -1) {
- madcblock_bits_helper(self, bits);
- } else if (self->width == -1) {
- madcblock_bits_helper(self, self->bits);
- }
+ mp_machine_adc_block_width_set_helper(self, bits);
}
static machine_adc_block_obj_t *mp_machine_adc_block_get(mp_int_t unit) {
diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 34d49c79d2..a104288f6e 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -50,12 +50,13 @@
const mp_obj_type_t machine_timer_type;
static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
+static mp_obj_t machine_timer_deinit(mp_obj_t self_in);
void machine_timer_deinit_all(void) {
// Disable, deallocate and remove all timers from list
machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head);
while (*t != NULL) {
- machine_timer_disable(*t);
+ machine_timer_deinit(*t);
machine_timer_obj_t *next = (*t)->next;
m_del_obj(machine_timer_obj_t, *t);
*t = next;
@@ -96,6 +97,7 @@ machine_timer_obj_t *machine_timer_create(mp_uint_t timer) {
self = mp_obj_malloc(machine_timer_obj_t, &machine_timer_type);
self->group = group;
self->index = index;
+ self->handle = NULL;
// Add the timer to the linked-list of timers
self->next = MP_STATE_PORT(machine_timer_obj_head);
@@ -131,9 +133,8 @@ void machine_timer_disable(machine_timer_obj_t *self) {
}
if (self->handle) {
- // Free the interrupt handler.
- esp_intr_free(self->handle);
- self->handle = NULL;
+ // Disable the interrupt
+ ESP_ERROR_CHECK(esp_intr_disable(self->handle));
}
// We let the disabled timer stay in the list, as it might be
@@ -150,12 +151,16 @@ static void machine_timer_isr(void *self_in) {
if (self->repeat) {
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
}
- mp_sched_schedule(self->callback, self);
- mp_hal_wake_main_task_from_isr();
+ self->handler(self);
}
}
-void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr)) {
+static void machine_timer_isr_handler(machine_timer_obj_t *self) {
+ mp_sched_schedule(self->callback, self);
+ mp_hal_wake_main_task_from_isr();
+}
+
+void machine_timer_enable(machine_timer_obj_t *self) {
// Initialise the timer.
timer_hal_init(&self->hal_context, self->group, self->index);
timer_ll_enable_counter(self->hal_context.dev, self->index, false);
@@ -167,10 +172,17 @@ void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr)) {
// Allocate and enable the alarm interrupt.
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), false);
timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
- ESP_ERROR_CHECK(
- esp_intr_alloc(timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
- TIMER_FLAGS, timer_isr, self, &self->handle)
- );
+ if (self->handle) {
+ ESP_ERROR_CHECK(esp_intr_enable(self->handle));
+ } else {
+ ESP_ERROR_CHECK(esp_intr_alloc(
+ timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
+ TIMER_FLAGS,
+ machine_timer_isr,
+ self,
+ &self->handle
+ ));
+ }
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), true);
// Enable the alarm to trigger at the given period.
@@ -224,16 +236,22 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n
}
self->repeat = args[ARG_mode].u_int;
+ self->handler = machine_timer_isr_handler;
self->callback = args[ARG_callback].u_obj;
- self->handle = NULL;
- machine_timer_enable(self, machine_timer_isr);
+ machine_timer_enable(self);
return mp_const_none;
}
static mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
- machine_timer_disable(self_in);
+ machine_timer_obj_t *self = self_in;
+
+ machine_timer_disable(self);
+ if (self->handle) {
+ ESP_ERROR_CHECK(esp_intr_free(self->handle));
+ self->handle = NULL;
+ }
return mp_const_none;
}
diff --git a/ports/esp32/machine_timer.h b/ports/esp32/machine_timer.h
index 914bedd86b..10fe2f39c9 100644
--- a/ports/esp32/machine_timer.h
+++ b/ports/esp32/machine_timer.h
@@ -55,12 +55,13 @@ typedef struct _machine_timer_obj_t {
mp_obj_t callback;
intr_handle_t handle;
+ void (*handler)(struct _machine_timer_obj_t *timer);
struct _machine_timer_obj_t *next;
} machine_timer_obj_t;
machine_timer_obj_t *machine_timer_create(mp_uint_t timer);
-void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr));
+void machine_timer_enable(machine_timer_obj_t *self);
void machine_timer_disable(machine_timer_obj_t *self);
#endif // MICROPY_INCLUDED_ESP32_MACHINE_TIMER_H
diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c
index e5857e894b..982d9a7e27 100644
--- a/ports/esp32/machine_uart.c
+++ b/ports/esp32/machine_uart.c
@@ -110,30 +110,19 @@ static const char *_parity_name[] = {"None", "1", "0"};
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \
{ MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_IRQ_BREAK) }, \
-static void uart_timer_callback(void *self_in) {
- machine_timer_obj_t *self = self_in;
-
- uint32_t intr_status = timer_ll_get_intr_status(self->hal_context.dev);
-
- if (intr_status & TIMER_LL_EVENT_ALARM(self->index)) {
- timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
- if (self->repeat) {
- timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
- }
- }
-
+static void uart_timer_callback(machine_timer_obj_t *timer) {
// The UART object is referred here by the callback field.
- machine_uart_obj_t *uart = (machine_uart_obj_t *)self->callback;
- if (uart->rxidle_state == RXIDLE_ALERT) {
+ machine_uart_obj_t *self = (machine_uart_obj_t *)timer->callback;
+ if (self->rxidle_state == RXIDLE_ALERT) {
// At the first call, just switch the state
- uart->rxidle_state = RXIDLE_ARMED;
- } else if (uart->rxidle_state == RXIDLE_ARMED) {
+ self->rxidle_state = RXIDLE_ARMED;
+ } else if (self->rxidle_state == RXIDLE_ARMED) {
// At the second call, run the irq callback and stop the timer
- uart->rxidle_state = RXIDLE_STANDBY;
- uart->mp_irq_flags = UART_IRQ_RXIDLE;
- mp_irq_handler(uart->mp_irq_obj);
+ self->rxidle_state = RXIDLE_STANDBY;
+ self->mp_irq_flags = UART_IRQ_RXIDLE;
+ mp_irq_handler(self->mp_irq_obj);
mp_hal_wake_main_task_from_isr();
- machine_timer_disable(uart->rxidle_timer);
+ machine_timer_disable(self->rxidle_timer);
}
}
@@ -150,9 +139,7 @@ static void uart_event_task(void *self_in) {
if (self->mp_irq_trigger & UART_IRQ_RXIDLE) {
if (self->rxidle_state != RXIDLE_INACTIVE) {
if (self->rxidle_state == RXIDLE_STANDBY) {
- self->rxidle_timer->repeat = true;
- self->rxidle_timer->handle = NULL;
- machine_timer_enable(self->rxidle_timer, uart_timer_callback);
+ machine_timer_enable(self->rxidle_timer);
}
}
self->rxidle_state = RXIDLE_ALERT;
@@ -553,11 +540,11 @@ static void uart_irq_configure_timer(machine_uart_obj_t *self, mp_uint_t trigger
}
self->rxidle_period = period;
self->rxidle_timer->period = period;
+ self->rxidle_timer->handler = uart_timer_callback;
// The Python callback is not used. So use this
// data field to hold a reference to the UART object.
self->rxidle_timer->callback = self;
self->rxidle_timer->repeat = true;
- self->rxidle_timer->handle = NULL;
self->rxidle_state = RXIDLE_STANDBY;
}
}
diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c
index 0296ddf10e..4572e7b68b 100644
--- a/ports/esp32/modesp32.c
+++ b/ports/esp32/modesp32.c
@@ -30,7 +30,6 @@
#include <time.h>
#include <sys/time.h>
#include "driver/gpio.h"
-#include "driver/adc.h"
#include "esp_heap_caps.h"
#include "multi_heap.h"
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 35c8ff1831..a6f103cdef 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -124,6 +124,7 @@
#define MICROPY_PY_MACHINE_ADC_INCLUDEFILE "ports/esp32/machine_adc.c"
#define MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH (1)
#define MICROPY_PY_MACHINE_ADC_INIT (1)
+#define MICROPY_PY_MACHINE_ADC_DEINIT (1)
#define MICROPY_PY_MACHINE_ADC_READ (1)
#define MICROPY_PY_MACHINE_ADC_READ_UV (1)
#define MICROPY_PY_MACHINE_ADC_BLOCK (1)
diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py
index 1d196d6ab1..92754733b5 100644
--- a/tests/misc/print_exception.py
+++ b/tests/misc/print_exception.py
@@ -1,3 +1,5 @@
+# Test sys.print_exception (MicroPython) / traceback.print_exception (CPython).
+
try:
import io
import sys
diff --git a/tests/run-tests.py b/tests/run-tests.py
index ecd611aa5b..cb7a8b7705 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -105,14 +105,11 @@ PC_PLATFORMS = ("darwin", "linux", "win32")
# These are tests that are difficult to detect that they should not be run on the given target.
platform_tests_to_skip = {
"esp8266": (
- "micropython/viper_args.py", # too large
- "micropython/viper_binop_arith.py", # too large
- "misc/rge_sm.py", # too large
+ "misc/rge_sm.py", # incorrect values due to object representation C
),
"minimal": (
"basics/class_inplace_op.py", # all special methods not supported
"basics/subclass_native_init.py", # native subclassing corner cases not support
- "misc/rge_sm.py", # too large
"micropython/opt_level.py", # don't assume line numbers are stored
),
"nrf": (
@@ -272,22 +269,17 @@ def detect_test_platform(pyb, args):
print()
-def prepare_script_for_target(args, *, script_filename=None, script_text=None, force_plain=False):
+def prepare_script_for_target(args, *, script_text=None, force_plain=False):
if force_plain or (not args.via_mpy and args.emit == "bytecode"):
- if script_filename is not None:
- with open(script_filename, "rb") as f:
- script_text = f.read()
+ # A plain test to run as-is, no processing needed.
+ pass
elif args.via_mpy:
tempname = tempfile.mktemp(dir="")
mpy_filename = tempname + ".mpy"
- if script_filename is None:
- script_filename = tempname + ".py"
- cleanup_script_filename = True
- with open(script_filename, "wb") as f:
- f.write(script_text)
- else:
- cleanup_script_filename = False
+ script_filename = tempname + ".py"
+ with open(script_filename, "wb") as f:
+ f.write(script_text)
try:
subprocess.check_output(
@@ -303,8 +295,7 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f
script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n"
rm_f(mpy_filename)
- if cleanup_script_filename:
- rm_f(script_filename)
+ rm_f(script_filename)
script_text += bytes(injected_import_hook_code, "ascii")
else:
@@ -315,9 +306,21 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f
def run_script_on_remote_target(pyb, args, test_file, is_special):
- had_crash, script = prepare_script_for_target(
- args, script_filename=test_file, force_plain=is_special
- )
+ with open(test_file, "rb") as f:
+ script = f.read()
+
+ # If the test is not a special test, prepend it with a print to indicate that it started.
+ # If the print does not execute this means that the test did not even start, eg it was
+ # too large for the target.
+ prepend_start_test = not is_special
+ if prepend_start_test:
+ if script.startswith(b"#"):
+ script = b"print('START TEST')" + script
+ else:
+ script = b"print('START TEST')\n" + script
+
+ had_crash, script = prepare_script_for_target(args, script_text=script, force_plain=is_special)
+
if had_crash:
return True, script
@@ -328,9 +331,19 @@ def run_script_on_remote_target(pyb, args, test_file, is_special):
except pyboard.PyboardError as e:
had_crash = True
if not is_special and e.args[0] == "exception":
- output_mupy = e.args[1] + e.args[2] + b"CRASH"
+ if prepend_start_test and e.args[1] == b"" and b"MemoryError" in e.args[2]:
+ output_mupy = b"SKIP-TOO-LARGE\n"
+ else:
+ output_mupy = e.args[1] + e.args[2] + b"CRASH"
else:
output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH"
+
+ if prepend_start_test:
+ if output_mupy.startswith(b"START TEST\r\n"):
+ output_mupy = output_mupy.removeprefix(b"START TEST\r\n")
+ else:
+ had_crash = True
+
return had_crash, output_mupy
@@ -474,7 +487,7 @@ def run_micropython(pyb, args, test_file, test_file_abspath, is_special=False):
output_mupy = output_mupy.replace(b"\r\n", b"\n")
# don't try to convert the output if we should skip this test
- if had_crash or output_mupy in (b"SKIP\n", b"CRASH"):
+ if had_crash or output_mupy in (b"SKIP\n", b"SKIP-TOO-LARGE\n", b"CRASH"):
return output_mupy
# skipped special tests will output "SKIP" surrounded by other interpreter debug output
@@ -911,6 +924,10 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
print("skip ", test_file)
test_results.append((test_name, test_file, "skip", ""))
return
+ elif output_mupy == b"SKIP-TOO-LARGE\n":
+ print("lrge ", test_file)
+ test_results.append((test_name, test_file, "skip", "too large"))
+ return
# Look at the output of the test to see if unittest was used.
uses_unittest = False
@@ -1035,7 +1052,10 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
test_results = test_results.value
passed_tests = list(r for r in test_results if r[2] == "pass")
- skipped_tests = list(r for r in test_results if r[2] == "skip")
+ skipped_tests = list(r for r in test_results if r[2] == "skip" and r[3] != "too large")
+ skipped_tests_too_large = list(
+ r for r in test_results if r[2] == "skip" and r[3] == "too large"
+ )
failed_tests = list(r for r in test_results if r[2] == "fail")
print(
@@ -1052,6 +1072,13 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
)
)
+ if len(skipped_tests_too_large) > 0:
+ print(
+ "{} tests skipped because they are too large: {}".format(
+ len(skipped_tests_too_large), " ".join(test[0] for test in skipped_tests_too_large)
+ )
+ )
+
if len(failed_tests) > 0:
print(
"{} tests failed: {}".format(
diff --git a/tools/ci.sh b/tools/ci.sh
index 7de21e43b3..ea67e2c104 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -93,23 +93,30 @@ function ci_code_size_build {
function code_size_build_step {
COMMIT=$1
OUTFILE=$2
- IGNORE_ERRORS=$3
echo "Building ${COMMIT}..."
git checkout --detach $COMMIT
git submodule update --init $SUBMODULES
git show -s
tools/metrics.py clean $PORTS_TO_CHECK
- tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE || $IGNORE_ERRORS
+ tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE
+ return $?
}
+ # Allow errors from tools/metrics.py to propagate out of the pipe above.
+ set -o pipefail
+
# build reference, save to size0
# ignore any errors with this build, in case master is failing
- code_size_build_step $REFERENCE ~/size0 true
+ code_size_build_step $REFERENCE ~/size0
# build PR/branch, save to size1
- code_size_build_step $COMPARISON ~/size1 false
+ code_size_build_step $COMPARISON ~/size1
+ STATUS=$?
+ set +o pipefail
unset -f code_size_build_step
+
+ return $STATUS
}
########################################################################################
@@ -526,14 +533,14 @@ function ci_native_mpy_modules_build {
fi
for natmod in deflate features1 features3 features4 framebuf heapq random re
do
- make -C examples/natmod/$natmod clean
+ make -C examples/natmod/$natmod ARCH=$arch clean
make -C examples/natmod/$natmod ARCH=$arch
done
# features2 requires soft-float on armv7m, rv32imc, and xtensa. On armv6m
# the compiler generates absolute relocations in the object file
# referencing soft-float functions, which is not supported at the moment.
- make -C examples/natmod/features2 clean
+ make -C examples/natmod/features2 ARCH=$arch clean
if [ $arch = "rv32imc" ] || [ $arch = "armv7m" ] || [ $arch = "xtensa" ]; then
make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float
elif [ $arch != "armv6m" ]; then
@@ -542,7 +549,7 @@ function ci_native_mpy_modules_build {
# btree requires thread local storage support on rv32imc.
if [ $arch != "rv32imc" ]; then
- make -C examples/natmod/btree clean
+ make -C examples/natmod/btree ARCH=$arch clean
make -C examples/natmod/btree ARCH=$arch
fi
}