summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Grayson <davidegrayson@gmail.com>2023-03-03 11:38:48 -0800
committerDamien George <damien@micropython.org>2023-03-09 11:44:20 +1100
commitf80d040c038c343b0709eba537014fb52bc8115e (patch)
tree145702c4816520d17faeadb8a9fc117c082394fe
parent673957b643b111e5879efd05a2ddf0808ed613d0 (diff)
rp2/modrp2: Disable other core, shorten delay to 8us in bootsel_button.
This function seems to work fine in multi-core applications now. The delay is now in units of microseconds instead of depending on the clock speed, and is adjustable by board configuration headers. Also added documentation.
-rw-r--r--docs/library/rp2.rst11
-rw-r--r--ports/rp2/modrp2.c46
-rw-r--r--ports/rp2/mpconfigport.h4
3 files changed, 35 insertions, 26 deletions
diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst
index ec7666d7c..7a473387b 100644
--- a/docs/library/rp2.rst
+++ b/docs/library/rp2.rst
@@ -66,6 +66,17 @@ For running PIO programs, see :class:`rp2.StateMachine`.
>>> rp2.asm_pio_encode("set(0, 1)", 0)
57345
+.. function:: bootsel_button()
+
+ Temporarily turns the QSPI_SS pin into an input and reads its value,
+ returning 1 for low and 0 for high.
+ On a typical RP2040 board with a BOOTSEL button, a return value of 1
+ indicates that the button is pressed.
+
+ Since this function temporarily disables access to the external flash
+ memory, it also temporarily disables interrupts and the other core to
+ prevent them from trying to execute code from flash.
+
.. class:: PIOASMError
This exception is raised from `asm_pio()` or `asm_pio_encode()` if there is
diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c
index cb5f51564..94d49489c 100644
--- a/ports/rp2/modrp2.c
+++ b/ports/rp2/modrp2.c
@@ -41,49 +41,43 @@
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.
+// Improved version of
// https://github.com/raspberrypi/pico-examples/blob/master/picoboard/button/button.c
-
-bool __no_inline_not_in_flash_func(get_bootsel_button)() {
+STATIC bool __no_inline_not_in_flash_func(bootsel_button)(void) {
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();
+ // Disable interrupts and the other core since they might be
+ // executing code from flash and we are about to temporarily
+ // disable flash access.
+ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
- // Set chip select to Hi-Z
+ // Set the CS pin to high impedance.
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);
+ (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) {;
+ // Delay without calling any functions in flash.
+ uint32_t start = timer_hw->timerawl;
+ while ((uint32_t)(timer_hw->timerawl - start) <= MICROPY_HW_BOOTSEL_DELAY_US) {
+ ;
}
// 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));
+ // The button pulls the QSPI_SS pin *low* when pressed.
+ bool button_state = !(sio_hw->gpio_hi_in & (1 << 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!
+ // Restore the QSPI_SS pin so we can use flash again.
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);
+ (GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB),
+ IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
- restore_interrupts(flags);
+ MICROPY_END_ATOMIC_SECTION(atomic_state);
return button_state;
}
STATIC mp_obj_t rp2_bootsel_button(void) {
- return MP_OBJ_NEW_SMALL_INT(get_bootsel_button());
+ return MP_OBJ_NEW_SMALL_INT(bootsel_button());
}
MP_DEFINE_CONST_FUN_OBJ_0(rp2_bootsel_button_obj, rp2_bootsel_button);
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index c987a0dc2..fc86e33e7 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -217,6 +217,10 @@ extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
#define MICROPY_HW_USB_PID (0x0005) // RP2 MicroPython
#endif
+#ifndef MICROPY_HW_BOOTSEL_DELAY_US
+#define MICROPY_HW_BOOTSEL_DELAY_US 8
+#endif
+
// Entering a critical section.
extern uint32_t mp_thread_begin_atomic_section(void);
extern void mp_thread_end_atomic_section(uint32_t);