13
13
#include "pico/bootrom.h"
14
14
#include "pico/binary_info.h"
15
15
16
+ #if !PICO_RP2040
17
+ #include "hardware/structs/powman.h"
18
+ #endif
19
+
16
20
// 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
17
21
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
18
22
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 200
41
45
bi_decl (bi_program_feature ("double reset -> BOOTSEL" ));
42
46
#endif
43
47
48
+ #if PICO_RP2040
49
+
50
+ // RP2040 stores a token in RAM, which is retained over assertion of the RUN pin.
51
+
44
52
static const uint32_t magic_token [] = {
45
53
0xf01681de , 0xbd729b29 , 0xd359be7a ,
46
54
};
47
55
48
56
static uint32_t __uninitialized_ram (magic_location )[count_of (magic_token )];
49
57
58
+ static inline bool double_tap_flag_is_set (void ) {
59
+ for (uint i = 0 ; i < count_of (magic_token ); i ++ ) {
60
+ if (magic_location [i ] != magic_token [i ]) {
61
+ return false;
62
+ }
63
+ }
64
+ return true;
65
+ }
66
+
67
+ static inline void set_double_tap_flag (void ) {
68
+ for (uint i = 0 ; i < count_of (magic_token ); i ++ ) {
69
+ magic_location [i ] = magic_token [i ];
70
+ }
71
+ }
72
+
73
+ static inline void clear_double_tap_flag (void ) {
74
+ magic_location [0 ] = 0 ;
75
+ }
76
+
77
+ #else
78
+
79
+ // Newer microcontrollers have a purpose-made register which is retained over
80
+ // RUN events, for detecting double-tap events. The ROM has built-in support
81
+ // for this, but this library can also use the same hardware feature.
82
+ // (Also, RAM is powered down when the RUN pin is asserted, so it's a bad
83
+ // place to put the token!)
84
+ //
85
+ // Note if ROM support is also enabled (via DOUBLE_TAP in OTP BOOT_FLAGS) then
86
+ // we never reach this point with the double tap flag still set. The window
87
+ // is the sum of the delay added by this library and the delay added by the
88
+ // ROM. It's not recommended to enable both, but it works.
89
+
90
+ static inline bool double_tap_flag_is_set (void ) {
91
+ return powman_hw -> chip_reset & POWMAN_CHIP_RESET_DOUBLE_TAP_BITS ;
92
+ }
93
+
94
+ static inline void set_double_tap_flag (void ) {
95
+ hw_set_bits (& powman_hw -> chip_reset , POWMAN_CHIP_RESET_DOUBLE_TAP_BITS );
96
+ }
97
+
98
+ static inline void clear_double_tap_flag (void ) {
99
+ hw_clear_bits (& powman_hw -> chip_reset , POWMAN_CHIP_RESET_DOUBLE_TAP_BITS );
100
+ }
101
+
102
+ #endif
103
+
50
104
/* Check for double reset and enter BOOTSEL mode if detected
51
105
*
52
106
* This function is registered to run automatically before main(). The
@@ -62,19 +116,16 @@ static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];
62
116
* in place so that the second boot will go to the bootloader.
63
117
*/
64
118
static void __attribute__((constructor )) boot_double_tap_check (void ) {
65
- for (uint i = 0 ; i < count_of (magic_token ); i ++ ) {
66
- if (magic_location [i ] != magic_token [i ]) {
67
- // Arm, wait, then disarm and continue booting
68
- for (i = 0 ; i < count_of (magic_token ); i ++ ) {
69
- magic_location [i ] = magic_token [i ];
70
- }
71
- busy_wait_us (PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000 );
72
- magic_location [0 ] = 0 ;
73
- return ;
74
- }
119
+ if (!double_tap_flag_is_set ()) {
120
+ // Arm, wait, then disarm and continue booting
121
+ set_double_tap_flag ();
122
+ busy_wait_us (PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000 );
123
+ clear_double_tap_flag ();
124
+ return ;
75
125
}
126
+
76
127
// Detected a double reset, so enter USB bootloader
77
- magic_location [ 0 ] = 0 ;
128
+ clear_double_tap_flag () ;
78
129
#ifdef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED
79
130
const uint32_t led_mask = 1u << PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED ;
80
131
#else
0 commit comments