Skip to content

Commit 3c49f53

Browse files
authored
Merge pull request adafruit#474 from tannewt/mcu_reset
Introduce reset mechanics to microcontroller.
2 parents 78db6c3 + a91e1cb commit 3c49f53

25 files changed

+308
-52
lines changed

atmel-samd/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ CFLAGS_CORTEX_M0 = \
123123
-DI2S_CALLBACK_MODE=false \
124124
-DTC_ASYNC=true \
125125
-DUSB_DEVICE_LPM_SUPPORT \
126+
-DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
126127
-DCIRCUITPY_CANARY_WORD=0xADAF00 \
127128
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
128129
--param max-inline-insns-single=500
@@ -315,6 +316,7 @@ SRC_BINDINGS_ENUMS = \
315316
digitalio/Direction.c \
316317
digitalio/DriveMode.c \
317318
digitalio/Pull.c \
319+
microcontroller/RunMode.c \
318320
help.c \
319321
util.c
320322

atmel-samd/boards/samd21x18-bootloader-crystalless.ld

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ MEMORY
1111
}
1212

1313
/* top end of the stack */
14-
_estack = ORIGIN(RAM) + LENGTH(RAM);
14+
_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
15+
_bootloader_dbl_tap = _estack;
1516

1617
/* define output sections */
1718
SECTIONS

atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ MEMORY
1111
}
1212

1313
/* top end of the stack */
14-
_estack = ORIGIN(RAM) + LENGTH(RAM);
14+
_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
15+
_bootloader_dbl_tap = _estack;
1516

1617
/* define output sections */
1718
SECTIONS

atmel-samd/boards/samd21x18-bootloader-external-flash.ld

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ MEMORY
1010
}
1111

1212
/* top end of the stack */
13-
_estack = ORIGIN(RAM) + LENGTH(RAM);
13+
_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
14+
_bootloader_dbl_tap = _estack;
1415

1516
/* define output sections */
1617
SECTIONS

atmel-samd/boards/samd21x18-bootloader.ld

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ MEMORY
1111
}
1212

1313
/* top end of the stack */
14-
_estack = ORIGIN(RAM) + LENGTH(RAM);
14+
_estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
15+
_bootloader_dbl_tap = _estack;
1516

1617
/* define output sections */
1718
SECTIONS

atmel-samd/boards/samd21x18-external-flash.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ MEMORY
1212

1313
/* top end of the stack */
1414
_estack = ORIGIN(RAM) + LENGTH(RAM);
15+
_bootloader_dbl_tap = 0;
1516

1617
/* define output sections */
1718
SECTIONS

atmel-samd/boards/samd21x18.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ MEMORY
1212

1313
/* top end of the stack */
1414
_estack = ORIGIN(RAM) + LENGTH(RAM);
15+
_bootloader_dbl_tap = 0;
1516

1617
/* define output sections */
1718
SECTIONS

atmel-samd/common-hal/digitalio/DigitalInOut.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
6464
}
6565

6666
void common_hal_digitalio_digitalinout_switch_to_input(
67-
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
67+
digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
6868
self->output = false;
6969

7070
common_hal_digitalio_digitalinout_set_pull(self, pull);
7171
}
7272

7373
void common_hal_digitalio_digitalinout_switch_to_output(
7474
digitalio_digitalinout_obj_t* self, bool value,
75-
enum digitalio_drive_mode_t drive_mode) {
75+
digitalio_drive_mode_t drive_mode) {
7676
struct port_config pin_conf;
7777
port_get_config_defaults(&pin_conf);
7878

@@ -88,7 +88,7 @@ void common_hal_digitalio_digitalinout_switch_to_output(
8888
common_hal_digitalio_digitalinout_set_value(self, value);
8989
}
9090

91-
enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
91+
digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
9292
digitalio_digitalinout_obj_t* self) {
9393
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT;
9494
}
@@ -131,7 +131,7 @@ bool common_hal_digitalio_digitalinout_get_value(
131131

132132
void common_hal_digitalio_digitalinout_set_drive_mode(
133133
digitalio_digitalinout_obj_t* self,
134-
enum digitalio_drive_mode_t drive_mode) {
134+
digitalio_drive_mode_t drive_mode) {
135135
bool value = common_hal_digitalio_digitalinout_get_value(self);
136136
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
137137
// True is implemented differently between modes so reset the value to make
@@ -141,7 +141,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
141141
}
142142
}
143143

144-
enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
144+
digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
145145
digitalio_digitalinout_obj_t* self) {
146146
if (self->open_drain) {
147147
return DRIVE_MODE_OPEN_DRAIN;
@@ -151,7 +151,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
151151
}
152152

153153
void common_hal_digitalio_digitalinout_set_pull(
154-
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) {
154+
digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
155155
enum port_pin_pull asf_pull = PORT_PIN_PULL_NONE;
156156
switch (pull) {
157157
case PULL_UP:
@@ -172,7 +172,7 @@ void common_hal_digitalio_digitalinout_set_pull(
172172
port_pin_set_config(self->pin->pin, &pin_conf);
173173
}
174174

175-
enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
175+
digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
176176
digitalio_digitalinout_obj_t* self) {
177177
uint32_t pin = self->pin->pin;
178178
PortGroup *const port_base = port_get_group_from_gpio_pin(pin);

atmel-samd/common-hal/microcontroller/__init__.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626

2727
#include "py/mphal.h"
2828
#include "py/obj.h"
29+
#include "py/runtime.h"
2930

31+
#include "reset.h"
3032
#include "samd21_pins.h"
3133

3234
#include "shared-bindings/nvm/ByteArray.h"
35+
#include "shared-bindings/microcontroller/__init__.h"
3336
#include "shared-bindings/microcontroller/Processor.h"
3437

3538
void common_hal_mcu_delay_us(uint32_t delay) {
@@ -51,9 +54,33 @@ void common_hal_mcu_enable_interrupts(void) {
5154
cpu_irq_restore(irq_flags);
5255
}
5356

57+
extern uint32_t _ezero;
58+
extern uint32_t _srelocate;
59+
60+
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
61+
// Set up the defaults.
62+
_bootloader_dbl_tap = DBL_TAP_MAGIC;
63+
_ezero = CIRCUITPY_CANARY_WORD;
64+
65+
if (runmode == RUNMODE_BOOTLOADER) {
66+
if (&_bootloader_dbl_tap < &_srelocate) {
67+
mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present.");
68+
}
69+
// Pretend to be the first of the two reset presses needed to enter the
70+
// bootloader. That way one reset will end in the bootloader.
71+
_bootloader_dbl_tap = DBL_TAP_MAGIC;
72+
} else if (runmode == RUNMODE_SAFE_MODE) {
73+
_ezero = CIRCUITPY_SOFTWARE_SAFE_MODE;
74+
}
75+
}
76+
77+
void common_hal_mcu_reset(void) {
78+
reset();
79+
}
80+
5481
// The singleton microcontroller.Processor object, bound to microcontroller.cpu
5582
// It currently only has properties, and no state.
56-
mcu_processor_obj_t common_hal_mcu_processor_obj = {
83+
const mcu_processor_obj_t common_hal_mcu_processor_obj = {
5784
.base = {
5885
.type = &mcu_processor_type,
5986
},
@@ -62,7 +89,7 @@ mcu_processor_obj_t common_hal_mcu_processor_obj = {
6289
// NVM is only available on Express boards for now.
6390
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0
6491
// The singleton nvm.ByteArray object.
65-
nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
92+
const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
6693
.base = {
6794
.type = &nvm_bytearray_type,
6895
},

atmel-samd/main.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ typedef enum {
8484
BROWNOUT,
8585
HARD_CRASH,
8686
USER_SAFE_MODE,
87+
SOFTWARE_SAFE_MODE
8788
} safe_mode_t;
8889

8990
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
@@ -375,7 +376,10 @@ bool start_mp(safe_mode_t safe_mode) {
375376
mp_hal_stdout_tx_str(".\r\n");
376377
} else
377378
#endif
378-
if (safe_mode != NO_SAFE_MODE) {
379+
if (safe_mode == SOFTWARE_SAFE_MODE) {
380+
mp_hal_stdout_tx_str("\r\nYou requested starting in safe mode from your software.");
381+
mp_hal_stdout_tx_str(".\r\nTo exit, please reset the board.\r\n");
382+
} else if (safe_mode != NO_SAFE_MODE) {
379383
mp_hal_stdout_tx_str("\r\nYou are running in safe mode which means something really bad happened.\r\n");
380384
if (safe_mode == HARD_CRASH) {
381385
mp_hal_stdout_tx_str("Looks like our core CircuitPython code crashed hard. Whoops!\r\n");
@@ -524,10 +528,14 @@ safe_mode_t samd21_init(void) {
524528
REG_MTB_MASTER = 0x00000000 + 6;
525529
#endif
526530

531+
// CIRCUITPY_SOFTWARE_SAFE_MODE works just like the canary except if it
532+
// survives we enter safe mode with a friendlier message.
533+
bool software_safe_mode = _ezero == CIRCUITPY_SOFTWARE_SAFE_MODE;
534+
527535
// On power on start or external reset, set _ezero to the canary word. If it
528-
// gets killed, we boot in safe mod. _ezero is the boundary between statically
529-
// allocated memory including the fixed MicroPython heap and the stack. If either
530-
// misbehaves, the canary will not be in tact after soft reset.
536+
// gets killed, we boot in safe mode. _ezero is the boundary between statically
537+
// allocated memory including the fixed MicroPython heap and the stack. If
538+
// either misbehaves, the canary will not be intact after soft reset.
531539
#ifdef CIRCUITPY_CANARY_WORD
532540
if (PM->RCAUSE.bit.POR == 1 || PM->RCAUSE.bit.EXT == 1) {
533541
_ezero = CIRCUITPY_CANARY_WORD;
@@ -607,6 +615,10 @@ safe_mode_t samd21_init(void) {
607615
return USER_SAFE_MODE;
608616
}
609617

618+
if (software_safe_mode) {
619+
return SOFTWARE_SAFE_MODE;
620+
}
621+
610622
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0
611623
// Upgrade the nvm flash to include one sector for eeprom emulation.
612624
struct nvm_fusebits fuses;

0 commit comments

Comments
 (0)