summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/rp2/modrp2.c53
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).