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:
parent
673957b643
commit
f80d040c03
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue