Skip to content

Commit

Permalink
Add pico_bootsel_via_double_reset library, fix #87 (#137)
Browse files Browse the repository at this point in the history
* Add pico_bootsel_via_double_reset library, fix #87

* pico_bootsel_via_double_reset: remove unnecessary library guard, fix subdirectory ordering

* Fix C type used as PICO_CONFIG type
  • Loading branch information
Wren6991 committed Feb 18, 2021
1 parent 6b0f736 commit 4c1fac5
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
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

0 comments on commit 4c1fac5

Please sign in to comment.