diff options
| -rw-r--r-- | ports/rp2/modrp2.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c index 5dfedb992..cb5f51564 100644 --- a/ports/rp2/modrp2.c +++ b/ports/rp2/modrp2.c @@ -27,6 +27,11 @@ #include "py/runtime.h" #include "drivers/dht/dht.h" #include "modrp2.h" +#include "pico/stdlib.h" +#include "hardware/gpio.h" +#include "hardware/sync.h" +#include "hardware/structs/ioqspi.h" +#include "hardware/structs/sio.h" #if MICROPY_PY_NETWORK_CYW43 #include "extmod/modnetwork.h" @@ -36,11 +41,59 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_network_country_obj); #endif +// Picoboard has a button attached to the flash CS pin, which the bootrom +// checks, and jumps straight to the USB bootcode if the button is pressed +// (pulling flash CS low). We can check this pin in by jumping to some code in +// SRAM (so that the XIP interface is not required), floating the flash CS +// pin, and observing whether it is pulled low. +// +// This doesn't work if others are trying to access flash at the same time, +// e.g. XIP streamer, or the other core. +// https://github.com/raspberrypi/pico-examples/blob/master/picoboard/button/button.c + +bool __no_inline_not_in_flash_func(get_bootsel_button)() { + const uint CS_PIN_INDEX = 1; + + // Must disable interrupts, as interrupt handlers may be in flash, and we + // are about to temporarily disable flash access! + uint32_t flags = save_and_disable_interrupts(); + + // Set chip select to Hi-Z + 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); + + // Note we can't call into any sleep functions in flash right now + for (volatile int i = 0; i < 1000; ++i) {; + } + + // The HI GPIO registers in SIO can observe and control the 6 QSPI pins. + // Note the button pulls the pin *low* when pressed. + bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX)); + + // Need to restore the state of chip select, else we are going to have a + // bad time when we return to code in flash! + 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); + + restore_interrupts(flags); + + return button_state; +} + +STATIC mp_obj_t rp2_bootsel_button(void) { + return MP_OBJ_NEW_SMALL_INT(get_bootsel_button()); +} +MP_DEFINE_CONST_FUN_OBJ_0(rp2_bootsel_button_obj, rp2_bootsel_button); + + STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rp2) }, { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&rp2_flash_type) }, { MP_ROM_QSTR(MP_QSTR_PIO), MP_ROM_PTR(&rp2_pio_type) }, { MP_ROM_QSTR(MP_QSTR_StateMachine), MP_ROM_PTR(&rp2_state_machine_type) }, + { MP_ROM_QSTR(MP_QSTR_bootsel_button), MP_ROM_PTR(&rp2_bootsel_button_obj) }, #if MICROPY_PY_NETWORK_CYW43 // Deprecated (use network.country instead). |
