Home > News & Updates > Arduino News > BUTTON, BUTTON, WHO’S GOT THE (PICO) BUTTON?

BUTTON, BUTTON, WHO’S GOT THE (PICO) BUTTON?

Summary of BUTTON, BUTTON, WHO’S GOT THE (PICO) BUTTON?


Summary (under 100 words): The Raspberry Pi Pico BOOTSEL button is wired to the flash chip-select, not a normal GPIO. You can read it by temporarily tri-stating the flash chip-select and sampling the pin, but code must run from RAM and you must disable interrupts and pause the other core to avoid corrupting flash access. The method works but is inefficient for frequent polling and may harm performance; use only when acceptable.

Parts used in thePico BOOTSEL button reading project:

  • Raspberry Pi Pico board
  • Flash memory chip (on-board)
  • BOOTSEL button (connected to flash chip-select)
  • RP2040 microcontroller (dual-core)
  • RAM (to run button-reading routine)
  • IO_QSPI and SIO hardware registers (ioqspi_hw, sio_hw)
  • Interrupt save/restore functions (save_and_disable_interrupts, restore_interrupts)
  • Functions to control other core (idleOtherCore, resumeOtherCore)

There is an episode of Ren and Stimpy with a big red “history eraser’ button that must not be pressed. Of course, who can resist the temptation of pressing the unpressable button? The same goes for development boards. If there is a button on there, you want to read it in your code, right? The Raspberry Pi Pico is a bit strange in that regard. The standard one lacks a reset button, but there is a big tantalizing button to reset in bootloader mode. You only use it when you power up, so why not read it in your code? Why not, indeed?

Turns out, that button isn’t what you think it is. It isn’t connected to a normal CPU pin at all. Instead, it connects to the flash memory chip. So does that mean you can’t read it at all? Not exactly. There’s good news, and then there’s bad news.

THE GOOD NEWS

The official Raspberry Pi examples show how to read the button (you have read all the examples, right?). You can convert the flash’s chip-select into an input temporarily and try to figure out if the pin is low, meaning that the button is pushed. Sounds easy, right?

THE BAD NEWS

The bad news is really bad. When you switch the flash chip-select to an input, you will lose access to the flash memory. But we are running from the flash memory! So, the first thing to think about is that the code will need to run from RAM.

But that’s not all. The Pico has interrupts and two CPU cores. So even if you are out of the flash memory, there’s no reason to assume someone else won’t want to use it simultaneously. So, to make this work, you need to disable interrupts and shut down the other CPU core while you read the pin.

THE EXAMPLE

Looking at the example, they do everything but disable the second core. I recently had to put this code in an Arduino-style program; there is excellent Arduino support for the Pico. Putting the function in RAM is pretty easy:

1
bool __no_inline_not_in_flash_func(_get_bootsel_button)() {

The rest is just manipulating the I/O pins and turning interrupts on and off:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);

That leaves the core. I put a wrapper around this function to avoid any possible problems with it being called from RAM (though it would probably work):

1
2
3
4
5
6
7
8
9
10
bool get_bootsel_button(void)
{
   bool rv;
// freeze
   rp2040.idleOtherCore();
   rv = _get_bootsel_button();
// unfreeze
   rp2040.resumeOtherCore();
   return rv;
}

It works. But I do worry about how inefficient it must be. You usually want to poll a button often. Turning off the other core, disabling interrupts, and the idle loop to let the pin settle — all that will take time. In practice, it seems to work OK, but it must be slowing things down some.

IN RETROSPECT…

So, can you read the Pico button? Yes. Should you? Maybe. For some applications, it is probably just fine. But if you are worried about performance, it probably isn’t the best idea.

With two 133 MHz cores, a ton of memory, easy debugging, and those cool peripheral processors, there’s a lot to love about the Pico. Just maybe not the BOOTSEL button.

Source: BUTTON, BUTTON, WHO’S GOT THE (PICO) BUTTON?

Quick Solutions to Questions related toPico BOOTSEL button reading:

  • Can you read the BOOTSEL button on the Raspberry Pi Pico?
    Yes; by temporarily converting the flash chip-select to an input and sampling the pin while running from RAM and with other execution paused.
  • Why is reading the BOOTSEL button different from a normal GPIO?
    Because the button is connected to the flash memory chip-select, not a normal CPU pin.
  • Do you need to run code from RAM to read the button?
    Yes; switching the flash chip-select to input loses access to flash, so the routine must run from RAM.
  • Must interrupts be disabled when reading the button?
    Yes; interrupts must be disabled to prevent flash access from other contexts while chip-select is tri-stated.
  • Do you need to stop the other CPU core when reading the button?
    Yes; the other core must be paused to avoid simultaneous flash access while the chip-select is in input state.
  • How does the button state read indicate a press?
    The button pulls the chip-select pin low when pressed, so a low level indicates the button is pushed.
  • Is reading the button frequently recommended?
    Probably not; disabling interrupts, idling the other core, and waiting for the pin to settle makes frequent polling inefficient.
  • What must you restore after sampling the button?
    You must restore the flash chip-select control to its normal state and restore interrupts and the other core.

About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter
Scroll to Top