diff --git a/docs/library/machine.ADCBlock.rst b/docs/library/machine.ADCBlock.rst index 56a468dd62..eb94362d55 100644 --- a/docs/library/machine.ADCBlock.rst +++ b/docs/library/machine.ADCBlock.rst @@ -39,9 +39,9 @@ Methods Configure the ADC peripheral. *bits* will set the resolution of the conversion process. -.. method:: ADCBlock.connect(channel) - ADCBlock.connect(source) - ADCBlock.connect(channel, source) +.. method:: ADCBlock.connect(channel, *, ...) + ADCBlock.connect(source, *, ...) + ADCBlock.connect(channel, source, *, ...) Connect up a channel on the ADC peripheral so it is ready for sampling, and return an :ref:`ADC ` object that represents that connection. @@ -56,3 +56,6 @@ Methods If both *channel* and *source* are given then they are connected together and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index a1a0a9f736..5bfdf65513 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -8,6 +8,7 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_DIR}/shared/libc/printf.c ${MICROPY_EXTMOD_DIR}/btstack/modbluetooth_btstack.c ${MICROPY_EXTMOD_DIR}/machine_adc.c + ${MICROPY_EXTMOD_DIR}/machine_adc_block.c ${MICROPY_EXTMOD_DIR}/machine_bitstream.c ${MICROPY_EXTMOD_DIR}/machine_i2c.c ${MICROPY_EXTMOD_DIR}/machine_i2s.c diff --git a/extmod/extmod.mk b/extmod/extmod.mk index c4b2c3d9c5..a04856bce2 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -3,6 +3,7 @@ SRC_EXTMOD_C += \ extmod/machine_adc.c \ + extmod/machine_adc_block.c \ extmod/machine_bitstream.c \ extmod/machine_i2c.c \ extmod/machine_i2s.c \ diff --git a/extmod/machine_adc_block.c b/extmod/machine_adc_block.c new file mode 100644 index 0000000000..f80e2dae4c --- /dev/null +++ b/extmod/machine_adc_block.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Jonathan Hogg + * Copyright (c) 2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#if MICROPY_PY_MACHINE_ADC_BLOCK + +#include "py/mphal.h" +#include "extmod/modmachine.h" + +// The port must provide implementations of these low-level ADCBlock functions. +STATIC void mp_machine_adc_block_print(const mp_print_t *print, machine_adc_block_obj_t *self); +STATIC machine_adc_block_obj_t *mp_machine_adc_block_get(mp_int_t unit); +STATIC void mp_machine_adc_block_bits_set(machine_adc_block_obj_t *self, mp_int_t bits); +STATIC machine_adc_obj_t *mp_machine_adc_block_connect(machine_adc_block_obj_t *self, mp_int_t channel_id, mp_hal_pin_obj_t pin, mp_map_t *kw_args); + +// The port provides implementations of the above in this file. +#include MICROPY_PY_MACHINE_ADC_BLOCK_INCLUDEFILE + +STATIC void machine_adc_block_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_adc_block_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_machine_adc_block_print(print, self); +} + +STATIC void machine_adc_block_init_helper(machine_adc_block_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_bits, + }; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + 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 bits = args[ARG_bits].u_int; + mp_machine_adc_block_bits_set(self, bits); +} + +STATIC mp_obj_t machine_adc_block_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); + mp_int_t unit = mp_obj_get_int(args[0]); + machine_adc_block_obj_t *self = mp_machine_adc_block_get(unit); + if (self == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid block id")); + } + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args); + machine_adc_block_init_helper(self, n_pos_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_adc_block_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_adc_block_obj_t *self = pos_args[0]; + machine_adc_block_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adc_block_init_obj, 1, machine_adc_block_init); + +STATIC mp_obj_t machine_adc_block_connect(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_adc_block_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_int_t channel_id = -1; + mp_hal_pin_obj_t pin = -1; + if (n_pos_args == 2) { + if (mp_obj_is_int(pos_args[1])) { + channel_id = mp_obj_get_int(pos_args[1]); + } else { + pin = mp_hal_get_pin_obj(pos_args[1]); + } + } else if (n_pos_args == 3) { + channel_id = mp_obj_get_int(pos_args[1]); + pin = mp_hal_get_pin_obj(pos_args[2]); + } else { + mp_raise_TypeError(MP_ERROR_TEXT("too many positional args")); + } + + machine_adc_obj_t *adc = mp_machine_adc_block_connect(self, channel_id, pin, kw_args); + if (adc == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("no matching ADC")); + } + + return MP_OBJ_FROM_PTR(adc); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adc_block_connect_obj, 2, machine_adc_block_connect); + +STATIC const mp_rom_map_elem_t machine_adc_block_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_adc_block_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&machine_adc_block_connect_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_adc_block_locals_dict, machine_adc_block_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + machine_adc_block_type, + MP_QSTR_ADCBlock, + MP_TYPE_FLAG_NONE, + make_new, machine_adc_block_make_new, + print, machine_adc_block_print, + locals_dict, &machine_adc_block_locals_dict + ); + +#endif // MICROPY_PY_MACHINE_ADC_BLOCK diff --git a/extmod/modmachine.h b/extmod/modmachine.h index 6cace4f851..0744ef7889 100644 --- a/extmod/modmachine.h +++ b/extmod/modmachine.h @@ -128,6 +128,7 @@ // A port must provide these types, but they are otherwise opaque. typedef struct _machine_adc_obj_t machine_adc_obj_t; +typedef struct _machine_adc_block_obj_t machine_adc_block_obj_t; typedef struct _machine_i2s_obj_t machine_i2s_obj_t; typedef struct _machine_pwm_obj_t machine_pwm_obj_t; typedef struct _machine_uart_obj_t machine_uart_obj_t; @@ -200,6 +201,7 @@ extern const machine_mem_obj_t machine_mem32_obj; // Their Python bindings are implemented in extmod, and their implementation // is provided by a port. extern const mp_obj_type_t machine_adc_type; +extern const mp_obj_type_t machine_adc_block_type; extern const mp_obj_type_t machine_i2c_type; extern const mp_obj_type_t machine_i2s_type; extern const mp_obj_type_t machine_mem_type; diff --git a/ports/esp32/adc.c b/ports/esp32/adc.c new file mode 100644 index 0000000000..c5886624ec --- /dev/null +++ b/ports/esp32/adc.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * Copyright (c) 2021 Jonathan Hogg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "adc.h" +#include "driver/adc.h" + +#define DEFAULT_VREF 1100 + +void madcblock_bits_helper(machine_adc_block_obj_t *self, mp_int_t bits) { + switch (bits) { + #if CONFIG_IDF_TARGET_ESP32 + case 9: + self->width = ADC_WIDTH_BIT_9; + break; + case 10: + self->width = ADC_WIDTH_BIT_10; + break; + case 11: + self->width = ADC_WIDTH_BIT_11; + break; + #endif + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + case 12: + self->width = ADC_WIDTH_BIT_12; + break; + #endif + #if CONFIG_IDF_TARGET_ESP32S2 + case 13: + self->width = ADC_WIDTH_BIT_13; + break; + #endif + default: + mp_raise_ValueError(MP_ERROR_TEXT("invalid bits")); + } + self->bits = bits; + + if (self->unit_id == ADC_UNIT_1) { + adc1_config_width(self->width); + } + for (adc_atten_t atten = ADC_ATTEN_DB_0; atten < ADC_ATTEN_MAX; atten++) { + if (self->characteristics[atten] != NULL) { + esp_adc_cal_characterize(self->unit_id, atten, self->width, DEFAULT_VREF, self->characteristics[atten]); + } + } +} + +mp_int_t madcblock_read_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id) { + int raw; + if (self->unit_id == ADC_UNIT_1) { + raw = adc1_get_raw(channel_id); + } else { + check_esp_err(adc2_get_raw(channel_id, self->width, &raw)); + } + return raw; +} + +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); + esp_adc_cal_characteristics_t *adc_chars = self->characteristics[atten]; + if (adc_chars == NULL) { + adc_chars = malloc(sizeof(esp_adc_cal_characteristics_t)); + esp_adc_cal_characterize(self->unit_id, atten, self->width, DEFAULT_VREF, adc_chars); + self->characteristics[atten] = adc_chars; + } + mp_int_t uv = esp_adc_cal_raw_to_voltage(raw, adc_chars) * 1000; + return uv; +} diff --git a/ports/esp32/adc.h b/ports/esp32/adc.h new file mode 100644 index 0000000000..ae5c0d3c37 --- /dev/null +++ b/ports/esp32/adc.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_ADC_H +#define MICROPY_INCLUDED_ESP32_ADC_H + +#include "py/runtime.h" +#include "esp_adc_cal.h" + +#define ADC_ATTEN_MAX SOC_ADC_ATTEN_NUM + +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; + esp_adc_cal_characteristics_t *characteristics[ADC_ATTEN_MAX]; +} machine_adc_block_obj_t; + +typedef struct _machine_adc_obj_t { + mp_obj_base_t base; + machine_adc_block_obj_t *block; + adc_channel_t channel_id; + gpio_num_t gpio_id; +} 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); +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); + +#endif // MICROPY_INCLUDED_ESP32_ADC_H diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index f66c59e341..40ae98822d 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -53,6 +53,7 @@ list(APPEND MICROPY_SOURCE_DRIVERS ) list(APPEND MICROPY_SOURCE_PORT + adc.c main.c ppp_set_auth.c uart.c @@ -66,7 +67,6 @@ list(APPEND MICROPY_SOURCE_PORT machine_timer.c machine_pin.c machine_touchpad.c - machine_adcblock.c machine_dac.c machine_i2c.c modmachine.c diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index 42746cb4bd..b5233e4dda 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -28,13 +28,9 @@ // This file is never compiled standalone, it's included directly from // extmod/machine_adc.c via MICROPY_PY_MACHINE_ADC_INCLUDEFILE. -#include "esp_log.h" - -#include "driver/gpio.h" -#include "driver/adc.h" - #include "py/mphal.h" -#include "machine_adc.h" +#include "adc.h" +#include "driver/adc.h" #define ADCBLOCK1 (&madcblock_obj[0]) #define ADCBLOCK2 (&madcblock_obj[1]) @@ -136,7 +132,7 @@ static inline void madc_atten_set(const machine_adc_obj_t *self, adc_atten_t att madc_obj_atten[self - &madc_obj[0]] = atten + 1; } -const machine_adc_obj_t *madc_search_helper(madcblock_obj_t *block, adc_channel_t channel_id, gpio_num_t gpio_id) { +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]; if ((block == NULL || block == adc->block) && (channel_id == -1 || channel_id == adc->channel_id) && (gpio_id == -1 || gpio_id == adc->gpio_id)) { diff --git a/ports/esp32/machine_adc.h b/ports/esp32/machine_adc.h deleted file mode 100644 index 6d06486c30..0000000000 --- a/ports/esp32/machine_adc.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef MICROPY_INCLUDED_MACHINE_ADC_H -#define MICROPY_INCLUDED_MACHINE_ADC_H - -#include "machine_adcblock.h" - -typedef struct _machine_adc_obj_t { - mp_obj_base_t base; - madcblock_obj_t *block; - adc_channel_t channel_id; - gpio_num_t gpio_id; -} machine_adc_obj_t; - -const machine_adc_obj_t *madc_search_helper(madcblock_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); - -#endif // MICROPY_INCLUDED_MACHINE_ADC_H diff --git a/ports/esp32/machine_adc_block.c b/ports/esp32/machine_adc_block.c new file mode 100644 index 0000000000..f2975ff2f2 --- /dev/null +++ b/ports/esp32/machine_adc_block.c @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Jonathan Hogg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This file is never compiled standalone, it's included directly from +// extmod/machine_adc_block.c via MICROPY_PY_MACHINE_ADC_BLOCK_INCLUDEFILE. + +#include "py/mphal.h" +#include "adc.h" +#include "driver/adc.h" + +machine_adc_block_obj_t madcblock_obj[] = { + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + {{&machine_adc_block_type}, ADC_UNIT_1, 12, -1, {0}}, + {{&machine_adc_block_type}, ADC_UNIT_2, 12, -1, {0}}, + #elif CONFIG_IDF_TARGET_ESP32S2 + {{&machine_adc_block_type}, ADC_UNIT_1, 13, -1, {0}}, + {{&machine_adc_block_type}, ADC_UNIT_2, 13, -1, {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); +} + +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); + } +} + +STATIC machine_adc_block_obj_t *mp_machine_adc_block_get(mp_int_t unit) { + for (int i = 0; i < MP_ARRAY_SIZE(madcblock_obj); i++) { + if (unit == madcblock_obj[i].unit_id) { + return &madcblock_obj[i]; + } + } + return NULL; +} + +STATIC machine_adc_obj_t *mp_machine_adc_block_connect(machine_adc_block_obj_t *self, mp_int_t channel_id, mp_hal_pin_obj_t gpio_id, mp_map_t *kw_args) { + const machine_adc_obj_t *adc = madc_search_helper(self, channel_id, gpio_id); + if (adc == NULL) { + return NULL; + } + madc_init_helper(adc, 0, NULL, kw_args); + return (machine_adc_obj_t *)adc; +} diff --git a/ports/esp32/machine_adcblock.c b/ports/esp32/machine_adcblock.c deleted file mode 100644 index 8d5296e2e5..0000000000 --- a/ports/esp32/machine_adcblock.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2021 Jonathan Hogg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include - -#include "esp_log.h" - -#include "driver/gpio.h" -#include "driver/adc.h" - -#include "py/runtime.h" -#include "py/mphal.h" -#include "modmachine.h" -#include "machine_adc.h" -#include "machine_adcblock.h" - -#define DEFAULT_VREF 1100 - -madcblock_obj_t madcblock_obj[] = { - #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 - {{&machine_adcblock_type}, ADC_UNIT_1, 12, -1, {0}}, - {{&machine_adcblock_type}, ADC_UNIT_2, 12, -1, {0}}, - #elif CONFIG_IDF_TARGET_ESP32S2 - {{&machine_adcblock_type}, ADC_UNIT_1, 13, -1, {0}}, - {{&machine_adcblock_type}, ADC_UNIT_2, 13, -1, {0}}, - #endif -}; - -STATIC void madcblock_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - madcblock_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "ADCBlock(%u, bits=%u)", self->unit_id, self->bits); -} - -void madcblock_bits_helper(madcblock_obj_t *self, mp_int_t bits) { - switch (bits) { - #if CONFIG_IDF_TARGET_ESP32 - case 9: - self->width = ADC_WIDTH_BIT_9; - break; - case 10: - self->width = ADC_WIDTH_BIT_10; - break; - case 11: - self->width = ADC_WIDTH_BIT_11; - break; - #endif - #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 - case 12: - self->width = ADC_WIDTH_BIT_12; - break; - #endif - #if CONFIG_IDF_TARGET_ESP32S2 - case 13: - self->width = ADC_WIDTH_BIT_13; - break; - #endif - default: - mp_raise_ValueError(MP_ERROR_TEXT("invalid bits")); - } - self->bits = bits; - - if (self->unit_id == ADC_UNIT_1) { - adc1_config_width(self->width); - } - for (adc_atten_t atten = ADC_ATTEN_DB_0; atten < ADC_ATTEN_MAX; atten++) { - if (self->characteristics[atten] != NULL) { - esp_adc_cal_characterize(self->unit_id, atten, self->width, DEFAULT_VREF, self->characteristics[atten]); - } - } -} - -STATIC void madcblock_init_helper(madcblock_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { - ARG_bits, - }; - - static const mp_arg_t allowed_args[] = { - { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - }; - - 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 bits = args[ARG_bits].u_int; - if (bits != -1) { - madcblock_bits_helper(self, bits); - } else if (self->width == -1) { - madcblock_bits_helper(self, self->bits); - } -} - -STATIC mp_obj_t madcblock_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); - adc_unit_t unit = mp_obj_get_int(args[0]); - madcblock_obj_t *self = NULL; - for (int i = 0; i < MP_ARRAY_SIZE(madcblock_obj); i++) { - if (unit == madcblock_obj[i].unit_id) { - self = &madcblock_obj[i]; - break; - } - } - if (!self) { - mp_raise_ValueError(MP_ERROR_TEXT("invalid block id")); - } - - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args); - madcblock_init_helper(self, n_pos_args - 1, args + 1, &kw_args); - - return MP_OBJ_FROM_PTR(self); -} - -STATIC mp_obj_t madcblock_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - madcblock_obj_t *self = pos_args[0]; - madcblock_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(madcblock_init_obj, 1, madcblock_init); - -STATIC mp_obj_t madcblock_connect(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - madcblock_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - adc_channel_t channel_id = -1; - gpio_num_t gpio_id = -1; - if (n_pos_args == 2) { - if (mp_obj_is_int(pos_args[1])) { - channel_id = mp_obj_get_int(pos_args[1]); - } else { - gpio_id = machine_pin_get_id(pos_args[1]); - } - } else if (n_pos_args == 3) { - channel_id = mp_obj_get_int(pos_args[1]); - gpio_id = machine_pin_get_id(pos_args[2]); - } else { - mp_raise_TypeError(MP_ERROR_TEXT("too many positional args")); - } - - const machine_adc_obj_t *adc = madc_search_helper(self, channel_id, gpio_id); - if (adc != NULL) { - madc_init_helper(adc, 0, pos_args + n_pos_args, kw_args); - return MP_OBJ_FROM_PTR(adc); - } - mp_raise_ValueError(MP_ERROR_TEXT("no matching ADC")); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(madcblock_connect_obj, 2, madcblock_connect); - -mp_int_t madcblock_read_helper(madcblock_obj_t *self, adc_channel_t channel_id) { - int raw; - if (self->unit_id == ADC_UNIT_1) { - raw = adc1_get_raw(channel_id); - } else { - check_esp_err(adc2_get_raw(channel_id, self->width, &raw)); - } - return raw; -} - -mp_int_t madcblock_read_uv_helper(madcblock_obj_t *self, adc_channel_t channel_id, adc_atten_t atten) { - int raw = madcblock_read_helper(self, channel_id); - esp_adc_cal_characteristics_t *adc_chars = self->characteristics[atten]; - if (adc_chars == NULL) { - adc_chars = malloc(sizeof(esp_adc_cal_characteristics_t)); - esp_adc_cal_characterize(self->unit_id, atten, self->width, DEFAULT_VREF, adc_chars); - self->characteristics[atten] = adc_chars; - } - mp_int_t uv = esp_adc_cal_raw_to_voltage(raw, adc_chars) * 1000; - return uv; -} - -STATIC const mp_rom_map_elem_t madcblock_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&madcblock_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&madcblock_connect_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(madcblock_locals_dict, madcblock_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - machine_adcblock_type, - MP_QSTR_ADCBlock, - MP_TYPE_FLAG_NONE, - make_new, madcblock_make_new, - print, madcblock_print, - locals_dict, &madcblock_locals_dict - ); diff --git a/ports/esp32/machine_adcblock.h b/ports/esp32/machine_adcblock.h deleted file mode 100644 index 7c9249b072..0000000000 --- a/ports/esp32/machine_adcblock.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MICROPY_INCLUDED_MACHINE_ADCBLOCK_H -#define MICROPY_INCLUDED_MACHINE_ADCBLOCK_H - -#include "esp_adc_cal.h" - -#define ADC_ATTEN_MAX SOC_ADC_ATTEN_NUM - -typedef struct _madcblock_obj_t { - mp_obj_base_t base; - adc_unit_t unit_id; - mp_int_t bits; - adc_bits_width_t width; - esp_adc_cal_characteristics_t *characteristics[ADC_ATTEN_MAX]; -} madcblock_obj_t; - -extern madcblock_obj_t madcblock_obj[]; - -extern void madcblock_bits_helper(madcblock_obj_t *self, mp_int_t bits); -extern mp_int_t madcblock_read_helper(madcblock_obj_t *self, adc_channel_t channel_id); -extern mp_int_t madcblock_read_uv_helper(madcblock_obj_t *self, adc_channel_t channel_id, adc_atten_t atten); - -#endif // MICROPY_INCLUDED_MACHINE_ADCBLOCK_H diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 1e83935a8b..461ddacdad 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -312,7 +312,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { #if MICROPY_PY_MACHINE_ADC { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, #endif - { MP_ROM_QSTR(MP_QSTR_ADCBlock), MP_ROM_PTR(&machine_adcblock_type) }, + #if MICROPY_PY_MACHINE_ADC_BLOCK + { MP_ROM_QSTR(MP_QSTR_ADCBlock), MP_ROM_PTR(&machine_adc_block_type) }, + #endif #if MICROPY_PY_MACHINE_DAC { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, #endif diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 7b26df609d..06a1d7b0e2 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -10,7 +10,6 @@ typedef enum { } wake_type_t; extern const mp_obj_type_t machine_touchpad_type; -extern const mp_obj_type_t machine_adcblock_type; extern const mp_obj_type_t machine_dac_type; extern const mp_obj_type_t machine_sdcard_type; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b4ec082092..706baae5b2 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -99,10 +99,11 @@ #define MICROPY_PY_MACHINE_ADC (1) #define MICROPY_PY_MACHINE_ADC_INCLUDEFILE "ports/esp32/machine_adc.c" #define MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH (1) -#define MICROPY_PY_MACHINE_ADC_BLOCK (1) #define MICROPY_PY_MACHINE_ADC_INIT (1) #define MICROPY_PY_MACHINE_ADC_READ (1) #define MICROPY_PY_MACHINE_ADC_READ_UV (1) +#define MICROPY_PY_MACHINE_ADC_BLOCK (1) +#define MICROPY_PY_MACHINE_ADC_BLOCK_INCLUDEFILE "ports/esp32/machine_adc_block.c" #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_BITSTREAM (1) #define MICROPY_PY_MACHINE_PULSE (1) diff --git a/ports/renesas-ra/modmachine.h b/ports/renesas-ra/modmachine.h index 9bb3196b37..22d1fc475e 100644 --- a/ports/renesas-ra/modmachine.h +++ b/ports/renesas-ra/modmachine.h @@ -30,7 +30,6 @@ #include "py/obj.h" extern const mp_obj_type_t machine_touchpad_type; -extern const mp_obj_type_t machine_adcblock_type; extern const mp_obj_type_t machine_dac_type; extern const mp_obj_type_t machine_sdcard_type;