Add BOOTSEL, allowing BOOTSEL use as a button

Since every board has a bootsel button, allow end users to read its
state with a simple `if (BOOTSEL)`.  Uses code from the pico-examples.
parent 481ee1c9
......@@ -59,7 +59,6 @@ void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long millis();
#ifdef __cplusplus
} // extern "C"
#endif
......@@ -68,6 +67,7 @@ unsigned long millis();
#include "SerialUSB.h"
#include "SerialUART.h"
#include "RP2040.h"
#include "Bootsel.h"
// Template which will evaluate at *compile time* to a single 32b number
// with the specified bits set.
......
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <Arduino.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/sio.h"
// This example blinks the Pico LED when the BOOTSEL button is pressed.
//
// 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.
static 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;
}
__Bootsel::operator bool() {
return get_bootsel_button();
}
__Bootsel BOOTSEL;
/*
* Simple BOOTSEL reader object
*
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
class __Bootsel {
public:
__Bootsel() { }
operator bool();
};
extern __Bootsel BOOTSEL;
/* Simple sketch to do something on a BOOTSEL press */
/* Releaed into the public domain */
void setup() {
Serial.begin(115200);
delay(5000);
Serial.println("I dare you to hit the BOOTSEL button...");
}
int c = 0;
void loop() {
if (BOOTSEL) {
Serial.printf("\a\aYou pressed BOOTSEL %d times!\n", ++c);
// Wait for BOOTSEL to be released
while (BOOTSEL) { delay(1); }
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment