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.
This commit is contained in:
David Grayson 2023-03-03 11:38:48 -08:00 committed by Damien George
parent 673957b643
commit f80d040c03
3 changed files with 35 additions and 26 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);