diff options
-rw-r--r-- | docs/esp32/quickref.rst | 15 | ||||
-rw-r--r-- | ports/esp32/adc.c | 94 | ||||
-rw-r--r-- | ports/esp32/adc.h | 47 | ||||
-rw-r--r-- | ports/esp32/boards/sdkconfig.base | 1 | ||||
-rw-r--r-- | ports/esp32/machine_adc.c | 95 | ||||
-rw-r--r-- | ports/esp32/machine_adc_block.c | 14 | ||||
-rw-r--r-- | ports/esp32/modesp32.c | 1 | ||||
-rw-r--r-- | ports/esp32/mpconfigport.h | 1 |
8 files changed, 155 insertions, 113 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/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) |