Skip to content

Add pico_bootsel_via_double_reset library, fix #87 #137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/rp2_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ if (NOT PICO_BARE_METAL)
# NOTE THE ORDERING HERE IS IMPORTANT AS SOME TARGETS CHECK ON EXISTENCE OF OTHER TARGETS
pico_add_subdirectory(boot_stage2)

pico_add_subdirectory(pico_bootsel_via_double_reset)
pico_add_subdirectory(pico_multicore)
pico_add_subdirectory(pico_unique_id)

Expand Down
10 changes: 10 additions & 0 deletions src/rp2_common/pico_bootsel_via_double_reset/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_library(pico_bootsel_via_double_reset INTERFACE)

target_sources(pico_bootsel_via_double_reset INTERFACE
${CMAKE_CURRENT_LIST_DIR}/pico_bootsel_via_double_reset.c
)

target_link_libraries(pico_bootsel_via_double_reset INTERFACE
pico_bootrom
pico_time
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pico.h"
#include "pico/time.h"
#include "pico/bootrom.h"

// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 200
#endif

// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED, GPIO to use as bootloader activity LED when BOOTSEL mode is entered via reset double tap (or -1 for none), type=int, default=-1, group=pico_bootsel_via_double_reset
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED -1
#endif

// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK, Optionally disable either the mass storage interface (bit 0) or the PICOBOOT interface (bit 1) when entering BOOTSEL mode via double reset, type=int, default=0, group=pico_bootsel_via_double_reset
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK 0u
#endif

/** \defgroup pico_bootsel_via_double_reset
*
* When the 'pico_bootsel_via_double_reset' library is linked, a function is
* injected before main() which will detect when the system has been reset
* twice in quick succession, and enter the USB ROM bootloader (BOOTSEL mode)
* when this happens. This allows a double tap of a reset button on a
* development board to be used to enter the ROM bootloader, provided this
* library is always linked.
*/

// Doesn't make any sense for a RAM only binary
#if !PICO_NO_FLASH
static const uint32_t magic_token[] = {
0xf01681de, 0xbd729b29, 0xd359be7a,
};

static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];

/*! \brief Check for double reset and enter BOOTSEL mode if detected
* \ingroup pico_bootsel_via_double_reset
*
* This function is registered to run automatically before main(). The
* algorithm is:
*
* 1. Check for magic token in memory; enter BOOTSEL mode if found.
* 2. Initialise that memory with that magic token.
* 3. Do nothing for a short while (few hundred ms).
* 4. Clear the magic token.
* 5. Continue with normal boot.
*
* Resetting the device twice quickly will interrupt step 3, leaving the token
* in place so that the second boot will go to the bootloader.
*/
static void __attribute__((constructor)) boot_double_tap_check(void) {
for (uint i = 0; i < count_of(magic_token); i++) {
if (magic_location[i] != magic_token[i]) {
// Arm, wait, then disarm and continue booting
for (i = 0; i < count_of(magic_token); i++) {
magic_location[i] = magic_token[i];
}
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
magic_location[0] = 0;
return;
}
}
// Detected a double reset, so enter USB bootloader
magic_location[0] = 0;
uint32_t led_mask = PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED >= 0 ?
1u << PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED : 0u;
reset_usb_boot(
led_mask,
PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
);
}

#endif
1 change: 1 addition & 0 deletions test/kitchen_sink/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ target_link_libraries(kitchen_sink_libs INTERFACE
hardware_xosc
pico_bit_ops
pico_bootrom
pico_bootsel_via_double_reset
pico_divider
pico_double
pico_fix_rp2040_usb_device_enumeration
Expand Down