From 09f6919c93e6c182f138f5bdc5b6dc3a433380f3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 09:36:50 -0600 Subject: [PATCH] Add ability to read VOLTAGE_MONITOR on Pico W Because this must be treated like an in-use pin for all other purposes, unfortunately a special case must be added in shared-bindings. Multiple AnalogIn objects for VOLTAGE_MONITOR can be created (because in use tracking isn't working) but this causes no harm. Testing performed: Read the monitor, then imported wifi. When the pin state was insufficiently restored, the second step would fail with debug messages about do_ioctl timeout. ``` import analogio, board a = analogio.AnalogIn(board.VOLTAGE_MONITOR) print(a.value) import wifi ``` Closes: #7020 --- ports/raspberrypi/bindings/cyw43/__init__.c | 8 ++++ ports/raspberrypi/bindings/cyw43/__init__.h | 1 + .../boards/raspberry_pi_pico_w/pins.c | 4 ++ .../common-hal/analogio/AnalogIn.c | 39 +++++++++++++++---- shared-bindings/analogio/AnalogIn.c | 9 ++++- 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/ports/raspberrypi/bindings/cyw43/__init__.c b/ports/raspberrypi/bindings/cyw43/__init__.c index bf0cbc2e67..c72581a6e4 100644 --- a/ports/raspberrypi/bindings/cyw43/__init__.c +++ b/ports/raspberrypi/bindings/cyw43/__init__.c @@ -123,6 +123,14 @@ const mcu_pin_obj_t *validate_obj_is_pin_including_cyw43(mp_obj_t obj) { return MP_OBJ_TO_PTR(obj); } +const mcu_pin_obj_t *validate_obj_is_free_pin_or_gpio29(mp_obj_t obj) { + const mcu_pin_obj_t *pin = validate_obj_is_pin(obj); + if (obj != &pin_GPIO29) { + assert_pin_free(pin); + } + return pin; +} + const mcu_pin_obj_t *validate_obj_is_free_pin_including_cyw43(mp_obj_t obj) { const mcu_pin_obj_t *pin = validate_obj_is_pin_including_cyw43(obj); assert_pin_free(pin); diff --git a/ports/raspberrypi/bindings/cyw43/__init__.h b/ports/raspberrypi/bindings/cyw43/__init__.h index 2520c6c2d1..65e9813f99 100644 --- a/ports/raspberrypi/bindings/cyw43/__init__.h +++ b/ports/raspberrypi/bindings/cyw43/__init__.h @@ -32,6 +32,7 @@ extern const mp_obj_type_t cyw43_pin_type; const mcu_pin_obj_t *validate_obj_is_free_pin_including_cyw43(mp_obj_t obj); +const mcu_pin_obj_t *validate_obj_is_free_pin_or_gpio29(mp_obj_t obj); const mcu_pin_obj_t *validate_obj_is_pin_including_cyw43(mp_obj_t obj); #define CONSTANT_CYW43_PM_VALUE(pm_mode, pm2_sleep_ret_ms, li_beacon_period, li_dtim_period, li_assoc) \ diff --git a/ports/raspberrypi/boards/raspberry_pi_pico_w/pins.c b/ports/raspberrypi/boards/raspberry_pi_pico_w/pins.c index 5a63e43a6d..8c85642597 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico_w/pins.c +++ b/ports/raspberrypi/boards/raspberry_pi_pico_w/pins.c @@ -45,6 +45,10 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/common-hal/analogio/AnalogIn.c b/ports/raspberrypi/common-hal/analogio/AnalogIn.c index b827068e1a..1dc4749208 100644 --- a/ports/raspberrypi/common-hal/analogio/AnalogIn.c +++ b/ports/raspberrypi/common-hal/analogio/AnalogIn.c @@ -35,16 +35,26 @@ #define ADC_FIRST_PIN_NUMBER 26 #define ADC_PIN_COUNT 4 +// Voltage monitor is special on Pico W, because this pin is shared between the +// voltage monitor function and the wifi function. Special handling is required +// to read the analog voltage. +#if CIRCUITPY_CYW43 +#define SPECIAL_PIN(pin) (pin->number == 29) +#else +#define SPECIAL_PIN(pin) false +#endif + void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin) { if (pin->number < ADC_FIRST_PIN_NUMBER || pin->number > ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT) { raise_ValueError_invalid_pin(); } adc_init(); + if (!SPECIAL_PIN(pin)) { + adc_gpio_init(pin->number); + claim_pin(pin); + } - adc_gpio_init(pin->number); - - claim_pin(pin); self->pin = pin; } @@ -57,14 +67,29 @@ void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { return; } - reset_pin_number(self->pin->number); + if (!SPECIAL_PIN(self->pin)) { + reset_pin_number(self->pin->number); + } self->pin = NULL; } uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { - adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER); - uint16_t value = adc_read(); - + uint16_t value; + if (SPECIAL_PIN(self->pin)) { + common_hal_mcu_disable_interrupts(); + uint32_t old_pad = padsbank0_hw->io[self->pin->number]; + uint32_t old_ctrl = iobank0_hw->io[self->pin->number].ctrl; + adc_gpio_init(self->pin->number); + adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER); + value = adc_read(); + gpio_init(self->pin->number); + padsbank0_hw->io[self->pin->number] = old_pad; + iobank0_hw->io[self->pin->number].ctrl = old_ctrl; + common_hal_mcu_enable_interrupts(); + } else { + adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER); + value = adc_read(); + } // Stretch 12-bit ADC reading to 16-bit range return (value << 4) | (value >> 8); } diff --git a/shared-bindings/analogio/AnalogIn.c b/shared-bindings/analogio/AnalogIn.c index 0ca0e09023..274bfa4806 100644 --- a/shared-bindings/analogio/AnalogIn.c +++ b/shared-bindings/analogio/AnalogIn.c @@ -36,6 +36,10 @@ #include "shared-bindings/analogio/AnalogIn.h" #include "shared-bindings/util.h" +#if CIRCUITPY_CYW43 +#include "bindings/cyw43/__init__.h" +#endif + //| class AnalogIn: //| """Read analog voltage levels //| @@ -60,8 +64,11 @@ STATIC mp_obj_t analogio_analogin_make_new(const mp_obj_type_t *type, mp_arg_check_num(n_args, n_kw, 1, 1, false); // 1st argument is the pin + #if CIRCUITPY_CYW43 + const mcu_pin_obj_t *pin = validate_obj_is_free_pin_or_gpio29(args[0]); + #else const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]); - + #endif analogio_analogin_obj_t *self = m_new_obj(analogio_analogin_obj_t); self->base.type = &analogio_analogin_type; common_hal_analogio_analogin_construct(self, pin);