Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ports/raspberrypi/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 57 additions & 0 deletions ports/raspberrypi/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions supervisor/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
20 changes: 20 additions & 0 deletions supervisor/shared/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}
15 changes: 1 addition & 14 deletions supervisor/shared/safe_mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down
Loading