From 3c6056f2526ce2741f11d45ed6c969650476f836 Mon Sep 17 00:00:00 2001 From: eightycc Date: Mon, 7 Apr 2025 15:35:08 -0700 Subject: [PATCH 1/6] Implement BOOTSEL button entry to safe mode for RP2. --- ports/raspberrypi/mpconfigport.h | 3 ++ ports/raspberrypi/supervisor/port.c | 57 +++++++++++++++++++++++++++++ supervisor/port.h | 5 +++ supervisor/shared/port.c | 20 ++++++++++ supervisor/shared/safe_mode.c | 15 +------- 5 files changed, 86 insertions(+), 14 deletions(-) diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 1181517fdf9a0..d3d46ffe2d6fe 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -33,6 +33,9 @@ #define CIRCUITPY_PROCESSOR_COUNT (2) +// For many RP2 boards BOOTSEL is not connected to a GPIO pin. +#define CIRCUITPY_BOOT_BUTTON (1) + #if CIRCUITPY_USB_HOST #define CIRCUITPY_USB_HOST_INSTANCE 1 #endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 7514b4e6ad4aa..712ab1812dbb9 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -56,6 +56,13 @@ #include "RP2350.h" // CMSIS #endif +#ifdef CIRCUITPY_BOOT_BUTTON +#include "hardware/gpio.h" +#include "hardware/sync.h" +#include "hardware/structs/ioqspi.h" +#include "hardware/structs/sio.h" +#endif + #include "supervisor/shared/serial.h" #include "tusb.h" @@ -576,3 +583,53 @@ void port_boot_info(void) { mp_printf(&mp_plat_print, "\n"); #endif } + +#if defined(CIRCUITPY_BOOT_BUTTON) +bool __no_inline_not_in_flash_func(port_boot_button_pressed)(void) { + // Sense the state of the boot button. Because this function + // disables flash, it cannot be safely called once the second + // core has been started. When the BOOTSEL button is sensed as + // pressed, return is delayed until the button is released and + // a delay has passed in order to debounce the button. + const uint32_t CS_PIN_INDEX = 1; + #if defined(PICO_RP2040) + const uint32_t CS_BIT = 1u << 1; + #else + const uint32_t CS_BIT = SIO_GPIO_HI_IN_QSPI_CSN_BITS; + #endif + uint32_t int_state = save_and_disable_interrupts(); + // Wait for any outstanding XIP activity to finish. Flash + // must be quiescent before disabling the chip select. Since + // there's no XIP busy indication we can test, we delay a + // generous 5 ms to allow any XIP activity to finish. + busy_wait_us(5000); + // Float the flash chip select pin. The line will HI-Z due to + // the external 10K pull-up resistor. + hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, + GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, + IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); + // Delay 100 us to allow the CS line to stabilize. If BOOTSEL is + // pressed, the line will be pulled low by the button and its + // 1K external resistor to ground. + busy_wait_us(100); + bool button_pressed = !(sio_hw->gpio_hi_in & CS_BIT); + // Wait for the button to be released. + if (button_pressed) { + while (!(sio_hw->gpio_hi_in & CS_BIT)) { + tight_loop_contents(); + } + // Wait for 50 ms to debounce the button. + busy_wait_us(50000); + } + // Restore the flash chip select pin to its original state. + hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, + GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, + IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); + // Delay 5 ms to allow the flash chip to re-enable and for the + // flash CS pin to stabilize. + busy_wait_us(5000); + // Restore the interrupt state. + restore_interrupts(int_state); + return button_pressed; +} +#endif diff --git a/supervisor/port.h b/supervisor/port.h index 29c071515c133..e38b5c49406ae 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -108,3 +108,8 @@ void port_boot_info(void); // Some ports want to mark additional pointers as gc roots. // A default weak implementation is provided that does nothing. void port_gc_collect(void); + +// Most ports that implement CIRCUITPY_BOOT_BUTTON use a generic version of +// this function to sense the button. Ports that need to can override this +// function to provide their own implementation. +bool port_boot_button_pressed(void); diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index 72bb45b8a270c..aeb7e14e81cd3 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -12,6 +12,11 @@ #include "lib/tlsf/tlsf.h" +#ifdef CIRCUITPY_BOOT_BUTTON +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/time/__init__.h" +#endif + static tlsf_t heap; MP_WEAK void port_wake_main_task(void) { @@ -60,3 +65,18 @@ MP_WEAK size_t port_heap_get_largest_free_size(void) { // IDF does this. Not sure why. return tlsf_fit_size(heap, max_size); } + +MP_WEAK bool port_boot_button_pressed(void) { + #if defined(CIRCUITPY_BOOT_BUTTON) && CIRCUITPY_BOOT_BUTTON != 1 + // Init/deinit the boot button every time in case it is used for LEDs. + digitalio_digitalinout_obj_t boot_button; + common_hal_digitalio_digitalinout_construct(&boot_button, CIRCUITPY_BOOT_BUTTON); + common_hal_digitalio_digitalinout_switch_to_input(&boot_button, PULL_UP); + common_hal_time_delay_ms(1); + bool button_pressed = !common_hal_digitalio_digitalinout_get_value(&boot_button); + common_hal_digitalio_digitalinout_deinit(&boot_button); + return button_pressed; + #else + return false; + #endif +} diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 85c49451bc718..977423cd6553d 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -8,10 +8,6 @@ #include "mphalport.h" -#if defined(CIRCUITPY_BOOT_BUTTON) -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/time/__init__.h" -#endif #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" @@ -78,19 +74,10 @@ safe_mode_t wait_for_safe_mode_reset(void) { new_status_color(BLACK); } #endif - // Init the boot button every time in case it is used for LEDs. - #ifdef CIRCUITPY_BOOT_BUTTON - digitalio_digitalinout_obj_t boot_button; - common_hal_digitalio_digitalinout_construct(&boot_button, CIRCUITPY_BOOT_BUTTON); - common_hal_digitalio_digitalinout_switch_to_input(&boot_button, PULL_UP); - common_hal_time_delay_ms(1); - bool button_pressed = !common_hal_digitalio_digitalinout_get_value(&boot_button); - common_hal_digitalio_digitalinout_deinit(&boot_button); - if (button_pressed) { + if (port_boot_button_pressed()) { boot_in_safe_mode = true; break; } - #endif diff = supervisor_ticks_ms64() - start_ticks; } #if CIRCUITPY_STATUS_LED From fd9af9145a97ed4a546e73e30580305eb936222e Mon Sep 17 00:00:00 2001 From: eightycc Date: Tue, 8 Apr 2025 13:27:30 -0700 Subject: [PATCH 2/6] Fix CI errors by adding CIRCUITPY_BOOT_BUTTON_NO_GPIO for boards w/o BOOTSEL GPIO connection. --- ports/raspberrypi/supervisor/port.c | 4 ++-- supervisor/shared/port.c | 2 +- supervisor/shared/safe_mode.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 712ab1812dbb9..c0523937dbada 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -56,7 +56,7 @@ #include "RP2350.h" // CMSIS #endif -#ifdef CIRCUITPY_BOOT_BUTTON +#ifdef CIRCUITPY_BOOT_BUTTON_NO_GPIO #include "hardware/gpio.h" #include "hardware/sync.h" #include "hardware/structs/ioqspi.h" @@ -584,7 +584,7 @@ void port_boot_info(void) { #endif } -#if defined(CIRCUITPY_BOOT_BUTTON) +#if defined(CIRCUITPY_BOOT_BUTTON_NO_GPIO) bool __no_inline_not_in_flash_func(port_boot_button_pressed)(void) { // Sense the state of the boot button. Because this function // disables flash, it cannot be safely called once the second diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index aeb7e14e81cd3..65e11f2fbf329 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -67,7 +67,7 @@ MP_WEAK size_t port_heap_get_largest_free_size(void) { } MP_WEAK bool port_boot_button_pressed(void) { - #if defined(CIRCUITPY_BOOT_BUTTON) && CIRCUITPY_BOOT_BUTTON != 1 + #if defined(CIRCUITPY_BOOT_BUTTON) // Init/deinit the boot button every time in case it is used for LEDs. digitalio_digitalinout_obj_t boot_button; common_hal_digitalio_digitalinout_construct(&boot_button, CIRCUITPY_BOOT_BUTTON); diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 977423cd6553d..da441c50d3de7 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -129,7 +129,7 @@ void print_safe_mode_message(safe_mode_t reason) { case SAFE_MODE_USER: #if defined(BOARD_USER_SAFE_MODE_ACTION) message = BOARD_USER_SAFE_MODE_ACTION; - #elif defined(CIRCUITPY_BOOT_BUTTON) + #elif defined(CIRCUITPY_BOOT_BUTTON) || defined(CIRCUITPY_BOOT_BUTTON_NO_GPIO) message = MP_ERROR_TEXT("You pressed the BOOT button at start up"); #else message = MP_ERROR_TEXT("You pressed the reset button during boot."); From 821b984b5a50cf6b7b3ea1008fb9defac01ed047 Mon Sep 17 00:00:00 2001 From: eightycc Date: Tue, 8 Apr 2025 13:47:22 -0700 Subject: [PATCH 3/6] Factor out duplicate code. --- supervisor/shared/bluetooth/bluetooth.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 15e472148f67e..73c05139eeea3 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -10,16 +10,13 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" -#if defined(CIRCUITPY_BOOT_BUTTON) -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/time/__init__.h" -#endif #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" #include "shared-module/storage/__init__.h" #include "common-hal/_bleio/__init__.h" +#include "supervisor/port.h" #include "supervisor/shared/serial.h" #include "supervisor/shared/status_leds.h" #include "supervisor/shared/tick.h" @@ -238,18 +235,10 @@ void supervisor_bluetooth_init(void) { new_status_color(BLACK); } #endif - // Init the boot button every time in case it is used for LEDs. - #ifdef CIRCUITPY_BOOT_BUTTON - digitalio_digitalinout_obj_t boot_button; - common_hal_digitalio_digitalinout_construct(&boot_button, CIRCUITPY_BOOT_BUTTON); - common_hal_digitalio_digitalinout_switch_to_input(&boot_button, PULL_UP); - common_hal_time_delay_ms(1); - bool button_pressed = !common_hal_digitalio_digitalinout_get_value(&boot_button); - common_hal_digitalio_digitalinout_deinit(&boot_button); - if (button_pressed) { + if (port_boot_button_pressed()) { boot_in_discovery_mode = true; + break; } - #endif diff = supervisor_ticks_ms64() - start_ticks; } if (boot_in_discovery_mode) { From c6038a6eeeb69ff2cc779e30984126e8c495d2fd Mon Sep 17 00:00:00 2001 From: eightycc Date: Tue, 8 Apr 2025 14:10:12 -0700 Subject: [PATCH 4/6] Fix another CI error, missed committing an update. --- ports/raspberrypi/mpconfigport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index d3d46ffe2d6fe..76e7ceb7cda48 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -34,7 +34,7 @@ #define CIRCUITPY_PROCESSOR_COUNT (2) // For many RP2 boards BOOTSEL is not connected to a GPIO pin. -#define CIRCUITPY_BOOT_BUTTON (1) +#define CIRCUITPY_BOOT_BUTTON_NO_GPIO (1) #if CIRCUITPY_USB_HOST #define CIRCUITPY_USB_HOST_INSTANCE 1 From 4d81b53024a73ad8a018f85bc7ac93f2da70af24 Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 11 Apr 2025 20:42:00 -0700 Subject: [PATCH 5/6] Update CIRCUITPY_BOOT_BUTTON_NO_GPIO to 0/1 for false/true. Add compile time check forbidding CIRCUITPY_BOOT_BUTTON and CIRCUITPY_BOOT_BUTTON_NO_GPIO. --- ports/raspberrypi/supervisor/port.c | 4 ++-- py/circuitpy_mpconfig.h | 9 +++++++++ supervisor/shared/safe_mode.c | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index c0523937dbada..7a929b866af3d 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -56,7 +56,7 @@ #include "RP2350.h" // CMSIS #endif -#ifdef CIRCUITPY_BOOT_BUTTON_NO_GPIO +#if CIRCUITPY_BOOT_BUTTON_NO_GPIO #include "hardware/gpio.h" #include "hardware/sync.h" #include "hardware/structs/ioqspi.h" @@ -584,7 +584,7 @@ void port_boot_info(void) { #endif } -#if defined(CIRCUITPY_BOOT_BUTTON_NO_GPIO) +#if CIRCUITPY_BOOT_BUTTON_NO_GPIO bool __no_inline_not_in_flash_func(port_boot_button_pressed)(void) { // Sense the state of the boot button. Because this function // disables flash, it cannot be safely called once the second diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 42e6f1841a445..836336a02a002 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -635,6 +635,15 @@ void background_callback_run_all(void); #define CIRCUITPY_SAVES_PARTITION_SIZE 0 #endif +// Boards that have a boot button connected to a GPIO pin should set +// CIRCUITPY_BOOT_BUTTON_NO_GPIO to 1. +#ifndef CIRCUITPY_BOOT_BUTTON_NO_GPIO +#define CIRCUITPY_BOOT_BUTTON_NO_GPIO (0) +#endif +#if defined(CIRCUITPY_BOOT_BUTTON) && CIRCUITPY_BOOT_BUTTON_NO_GPIO +#error "CIRCUITPY_BOOT_BUTTON and CIRCUITPY_BOOT_BUTTON_NO_GPIO are mutually exclusive" +#endif + #if defined(__GNUC__) && !defined(__ZEPHYR__) #if __GNUC__ < CIRCUITPY_MIN_GCC_VERSION // (the 3 level scheme here is required to get expansion & stringization diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index da441c50d3de7..5f24618f7f39b 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -129,7 +129,7 @@ void print_safe_mode_message(safe_mode_t reason) { case SAFE_MODE_USER: #if defined(BOARD_USER_SAFE_MODE_ACTION) message = BOARD_USER_SAFE_MODE_ACTION; - #elif defined(CIRCUITPY_BOOT_BUTTON) || defined(CIRCUITPY_BOOT_BUTTON_NO_GPIO) + #elif defined(CIRCUITPY_BOOT_BUTTON) || CIRCUITPY_BOOT_BUTTON_NO_GPIO message = MP_ERROR_TEXT("You pressed the BOOT button at start up"); #else message = MP_ERROR_TEXT("You pressed the reset button during boot."); From c266993c6670be2a28859b2205ec9ba63307f2ba Mon Sep 17 00:00:00 2001 From: eightycc Date: Tue, 15 Apr 2025 09:34:32 -0700 Subject: [PATCH 6/6] Set CIRCUITPY_BOOT_BUTTON_NO_GPIO only when CIRCUITPY_BOOT_BUTTON not defined. Co-authored-by: Scott Shawcroft --- ports/raspberrypi/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 76e7ceb7cda48..aa20cd90b8378 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -34,7 +34,9 @@ #define CIRCUITPY_PROCESSOR_COUNT (2) // For many RP2 boards BOOTSEL is not connected to a GPIO pin. +#ifndef CIRCUITPY_BOOT_BUTTON #define CIRCUITPY_BOOT_BUTTON_NO_GPIO (1) +#endif #if CIRCUITPY_USB_HOST #define CIRCUITPY_USB_HOST_INSTANCE 1 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy