Skip to content

Commit e513a27

Browse files
Wren6991kilograham
authored andcommitted
Add pico_bootsel_via_double_reset library, fix #87 (#137)
* 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
1 parent aae65d3 commit e513a27

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

src/rp2_common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ if (NOT PICO_BARE_METAL)
3636
# NOTE THE ORDERING HERE IS IMPORTANT AS SOME TARGETS CHECK ON EXISTENCE OF OTHER TARGETS
3737
pico_add_subdirectory(boot_stage2)
3838

39+
pico_add_subdirectory(pico_bootsel_via_double_reset)
3940
pico_add_subdirectory(pico_multicore)
4041
pico_add_subdirectory(pico_unique_id)
4142

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_library(pico_bootsel_via_double_reset INTERFACE)
2+
3+
target_sources(pico_bootsel_via_double_reset INTERFACE
4+
${CMAKE_CURRENT_LIST_DIR}/pico_bootsel_via_double_reset.c
5+
)
6+
7+
target_link_libraries(pico_bootsel_via_double_reset INTERFACE
8+
pico_bootrom
9+
pico_time
10+
)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include "pico.h"
8+
#include "pico/time.h"
9+
#include "pico/bootrom.h"
10+
11+
// 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
12+
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
13+
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 200
14+
#endif
15+
16+
// 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
17+
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED
18+
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED -1
19+
#endif
20+
21+
// 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
22+
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
23+
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK 0u
24+
#endif
25+
26+
/** \defgroup pico_bootsel_via_double_reset
27+
*
28+
* When the 'pico_bootsel_via_double_reset' library is linked, a function is
29+
* injected before main() which will detect when the system has been reset
30+
* twice in quick succession, and enter the USB ROM bootloader (BOOTSEL mode)
31+
* when this happens. This allows a double tap of a reset button on a
32+
* development board to be used to enter the ROM bootloader, provided this
33+
* library is always linked.
34+
*/
35+
36+
// Doesn't make any sense for a RAM only binary
37+
#if !PICO_NO_FLASH
38+
static const uint32_t magic_token[] = {
39+
0xf01681de, 0xbd729b29, 0xd359be7a,
40+
};
41+
42+
static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];
43+
44+
/*! \brief Check for double reset and enter BOOTSEL mode if detected
45+
* \ingroup pico_bootsel_via_double_reset
46+
*
47+
* This function is registered to run automatically before main(). The
48+
* algorithm is:
49+
*
50+
* 1. Check for magic token in memory; enter BOOTSEL mode if found.
51+
* 2. Initialise that memory with that magic token.
52+
* 3. Do nothing for a short while (few hundred ms).
53+
* 4. Clear the magic token.
54+
* 5. Continue with normal boot.
55+
*
56+
* Resetting the device twice quickly will interrupt step 3, leaving the token
57+
* in place so that the second boot will go to the bootloader.
58+
*/
59+
static void __attribute__((constructor)) boot_double_tap_check(void) {
60+
for (uint i = 0; i < count_of(magic_token); i++) {
61+
if (magic_location[i] != magic_token[i]) {
62+
// Arm, wait, then disarm and continue booting
63+
for (i = 0; i < count_of(magic_token); i++) {
64+
magic_location[i] = magic_token[i];
65+
}
66+
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
67+
magic_location[0] = 0;
68+
return;
69+
}
70+
}
71+
// Detected a double reset, so enter USB bootloader
72+
magic_location[0] = 0;
73+
uint32_t led_mask = PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED >= 0 ?
74+
1u << PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED : 0u;
75+
reset_usb_boot(
76+
led_mask,
77+
PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
78+
);
79+
}
80+
81+
#endif

test/kitchen_sink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ target_link_libraries(kitchen_sink_libs INTERFACE
2727
hardware_xosc
2828
pico_bit_ops
2929
pico_bootrom
30+
pico_bootsel_via_double_reset
3031
pico_divider
3132
pico_double
3233
pico_fix_rp2040_usb_device_enumeration

0 commit comments

Comments
 (0)