Rework safe mode and have heap overwrite trigger it.

This creates a common safe mode mechanic that ports can share.
As a result, the nRF52 now has safe mode support as well.

The common safe mode adds a 700ms delay at startup where a reset
during that window will cause a reset into safe mode. This window
is designated by a yellow status pixel and flashing the single led
three times.

A couple NeoPixel fixes are included for the nRF52 as well.

Fixes #1034. Fixes #990. Fixes #615.
crypto-aes
Scott Shawcroft 4 years ago
parent 7ad2e6ace3
commit 6ef8639971
No known key found for this signature in database
GPG Key ID: FD0EDC4B6C53CA59

@ -51,6 +51,7 @@
#include "supervisor/shared/autoreload.h"
#include "supervisor/shared/translate.h"
#include "supervisor/shared/rgb_led_status.h"
#include "supervisor/shared/safe_mode.h"
#include "supervisor/shared/status_leds.h"
#include "supervisor/shared/stack.h"
#include "supervisor/serial.h"
@ -140,12 +141,6 @@ const char* first_existing_file_in_list(const char ** filenames) {
return NULL;
}
void write_compressed(const compressed_string_t* compressed) {
char decompressed[compressed->length];
decompress(compressed, decompressed);
serial_write(decompressed);
}
bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
const char* filename = first_existing_file_in_list(filenames);
if (filename == NULL) {
@ -166,11 +161,11 @@ bool run_code_py(safe_mode_t safe_mode) {
if (serial_connected_at_start) {
serial_write("\n");
if (autoreload_is_enabled()) {
write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
} else if (safe_mode != NO_SAFE_MODE) {
write_compressed(translate("Running in safe mode! Auto-reload is off.\n"));
serial_write_compressed(translate("Running in safe mode! Auto-reload is off.\n"));
} else if (!autoreload_is_enabled()) {
write_compressed(translate("Auto-reload is off.\n"));
serial_write_compressed(translate("Auto-reload is off.\n"));
}
}
#endif
@ -184,7 +179,7 @@ bool run_code_py(safe_mode_t safe_mode) {
bool found_main = false;
if (safe_mode != NO_SAFE_MODE) {
write_compressed(translate("Running in safe mode! Not running saved code.\n"));
serial_write_compressed(translate("Running in safe mode! Not running saved code.\n"));
} else {
new_status_color(MAIN_RUNNING);
@ -200,7 +195,7 @@ bool run_code_py(safe_mode_t safe_mode) {
if (!found_main){
found_main = maybe_run_list(double_extension_filenames, &result);
if (found_main) {
write_compressed(translate("WARNING: Your code filename has two extensions\n"));
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
}
}
stop_mp();
@ -239,37 +234,14 @@ bool run_code_py(safe_mode_t safe_mode) {
if (!serial_connected_at_start) {
if (autoreload_is_enabled()) {
write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
} else {
write_compressed(translate("Auto-reload is off.\n"));
}
}
// Output a user safe mode string if its set.
#ifdef BOARD_USER_SAFE_MODE
if (safe_mode == USER_SAFE_MODE) {
serial_write("\n");
write_compressed(translate("You requested starting safe mode by "));
serial_write(BOARD_USER_SAFE_MODE_ACTION);
serial_write("\n");
write_compressed(translate("To exit, please reset the board without "));
serial_write(BOARD_USER_SAFE_MODE_ACTION);
serial_write("\n");
} else
#endif
if (safe_mode != NO_SAFE_MODE) {
serial_write("\n");
write_compressed(translate("You are running in safe mode which means something really bad happened.\n"));
if (safe_mode == HARD_CRASH) {
write_compressed(translate("Looks like our core CircuitPython code crashed hard. Whoops!\n"));
write_compressed(translate("Please file an issue here with the contents of your CIRCUITPY drive:\n"));
serial_write("https://github.com/adafruit/circuitpython/issues\n");
} else if (safe_mode == BROWNOUT) {
write_compressed(translate("The microcontroller's power dipped. Please make sure your power supply provides\n"));
write_compressed(translate("enough power for the whole circuit and press reset (after ejecting CIRCUITPY).\n"));
serial_write_compressed(translate("Auto-reload is off.\n"));
}
}
print_safe_mode_message(safe_mode);
serial_write("\n");
write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
}
if (serial_connected_before_animation && !serial_connected()) {
serial_connected_at_start = false;
@ -394,6 +366,11 @@ int __attribute__((used)) main(void) {
init_status_leds();
rgb_led_status_init();
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
if (safe_mode == NO_SAFE_MODE) {
safe_mode = wait_for_safe_mode_reset();
}
stack_init();
// Create a new filesystem only if we're not in a safe mode.
@ -427,7 +404,7 @@ int __attribute__((used)) main(void) {
}
if (exit_code == PYEXEC_FORCED_EXIT) {
if (!first_run) {
write_compressed(translate("soft reboot\n"));
serial_write_compressed(translate("soft reboot\n"));
}
first_run = false;
skip_repl = run_code_py(safe_mode);
@ -455,12 +432,12 @@ void gc_collect(void) {
}
void NORETURN nlr_jump_fail(void *val) {
HardFault_Handler();
reset_into_safe_mode(MICROPY_NLR_JUMP_FAIL);
while (true) {}
}
void NORETURN __fatal_error(const char *msg) {
HardFault_Handler();
reset_into_safe_mode(MICROPY_FATAL_ERROR);
while (true) {}
}

@ -5,6 +5,8 @@
#define MICROPY_PORT_B (0)
#define MICROPY_PORT_C (0)
#define MICROPY_HW_LED_STATUS (&pin_PB23)
#define CIRCUITPY_INTERNAL_NVM_SIZE 0
#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - 0x010000)

@ -1,7 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Arduino Zero"
#define MICROPY_HW_MCU_NAME "samd21g18"
// #define MICROPY_HW_LED_MSC &pin_PA17 // red
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_LED_TX &pin_PA27
#define MICROPY_HW_LED_RX &pin_PB03

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit CircuitPlayground Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
// Don't allow touch on A0 (PA02), because it's connected to the speaker.
#define PA02_NO_TOUCH (true)

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit CircuitPlayground Express with Crickit libraries"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
// No framebuf on CRICKit version to save space.
#define MICROPY_PY_FRAMEBUF (0)

@ -1,5 +1,6 @@
// LEDs
//#define MICROPY_HW_LED_MSC PIN_PA17 // red
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger"
#define MICROPY_HW_MCU_NAME "samd21g18"

@ -1,5 +1,5 @@
// LEDs
//#define MICROPY_HW_LED_MSC PIN_PA17 // red
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic"
#define MICROPY_HW_MCU_NAME "samd21g18"

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
#define SPI_FLASH_MOSI_PIN &pin_PA08

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Express with Crickit libraries"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
#define SPI_FLASH_MOSI_PIN &pin_PA08

@ -1,5 +1,5 @@
// LEDs
//#define MICROPY_HW_LED_MSC PIN_PA17 // red
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 RFM69"
#define MICROPY_HW_MCU_NAME "samd21g18"

@ -1,5 +1,5 @@
// LEDs
//#define MICROPY_HW_LED_MSC PIN_PA17 // red
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 RFM9x"
#define MICROPY_HW_MCU_NAME "samd21g18"

@ -3,6 +3,8 @@
#define MICROPY_HW_BOARD_NAME "Hacked Feather M0 Express with 8Mbyte SPI flash"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
#define SPI_FLASH_MOSI_PIN &pin_PA08

@ -5,6 +5,7 @@
// Rev E
#define MICROPY_HW_LED_STATUS (&pin_PA23)
#define MICROPY_HW_NEOPIXEL (&pin_PB03)
// These are pins not to reset.

@ -1,6 +1,7 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather RadioFruit Zigbee"
#define MICROPY_HW_MCU_NAME "samr21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA27)
#define MICROPY_HW_NEOPIXEL (&pin_PA22)
#define SPI_FLASH_MOSI_PIN &pin_PA31

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Gemma M0"
#define MICROPY_HW_MCU_NAME "samd21e18"
#define MICROPY_HW_LED_STATUS (&pin_PA23)
#define MICROPY_HW_APA102_MOSI (&pin_PA00)
#define MICROPY_HW_APA102_SCK (&pin_PA01)

@ -5,6 +5,8 @@
// This is for Rev B which is green and has the SD card slot at the edge of the board.
#define MICROPY_HW_LED_STATUS (&pin_PB01)
#define MICROPY_HW_LED_TX &(pin_PC30)
#define MICROPY_HW_LED_RX &(pin_PC31)

@ -1,6 +1,7 @@
#define MICROPY_HW_BOARD_NAME "HalloWing M0 Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA23)
#define MICROPY_HW_NEOPIXEL (&pin_PA12)
#define SPI_FLASH_MOSI_PIN &pin_PB10

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy M0 Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define CIRCUITPY_BITBANG_APA102
#define MICROPY_HW_APA102_MOSI (&pin_PA01)
#define MICROPY_HW_APA102_SCK (&pin_PA00)

@ -4,6 +4,8 @@
#define CIRCUITPY_MCU_FAMILY samd51
// This is for Rev B
#define MICROPY_HW_LED_STATUS (&pin_PA22)
#define MICROPY_HW_APA102_MOSI (&pin_PB03)
#define MICROPY_HW_APA102_SCK (&pin_PB02)

@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Meow Meow"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PB23)
// These are pins not to reset.
#define MICROPY_PORT_A (0)
#define MICROPY_PORT_B (0)

@ -1,6 +1,7 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Metro M0 Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_LED_STATUS (&pin_PA17)
#define MICROPY_HW_LED_TX &pin_PA27
// Comment this out if you have trouble connecting over SWD. It's one of the SWD pins.
#define MICROPY_HW_LED_RX &pin_PA31

@ -8,6 +8,8 @@
#define MICROPY_HW_LED_TX (&pin_PA27)
#define MICROPY_HW_LED_RX (&pin_PB06)
#define MICROPY_HW_LED_STATUS (&pin_PA16)
#define MICROPY_HW_NEOPIXEL (&pin_PB22)
// These are pins not to reset.

@ -3,6 +3,8 @@
#define CIRCUITPY_MCU_FAMILY samd51
#define MICROPY_HW_LED_STATUS (&pin_PA15)
// RGB Status LED Pins
#define MICROPY_HW_APA102_MOSI (&pin_PB03)
#define MICROPY_HW_APA102_SCK (&pin_PB02)

@ -2,6 +2,8 @@
#define MICROPY_HW_MCU_NAME "samd21e18"
// Rev B - Black
#define MICROPY_HW_LED_STATUS (&pin_PA10)
#define MICROPY_HW_APA102_MOSI (&pin_PA00)
#define MICROPY_HW_APA102_SCK (&pin_PA01)

@ -2,6 +2,7 @@
#define MICROPY_HW_MCU_NAME "samd21e18"
// Rev B - Black
#define MICROPY_HW_LED_STATUS (&pin_PA10)
// #define MICROPY_HW_APA102_MOSI (&pin_PA00)
// #define MICROPY_HW_APA102_SCK (&pin_PA01)

@ -64,6 +64,9 @@
#include "reset.h"
#include "tick.h"
#include "supervisor/shared/safe_mode.h"
#include "supervisor/shared/stack.h"
#include "tusb.h"
#ifdef CIRCUITPY_GAMEPAD_TICKS
@ -153,35 +156,6 @@ safe_mode_t port_init(void) {
samd_peripherals_enable_cache();
#endif
// On power on start or external reset, set _ezero to the canary word. If it
// gets killed, we boot in safe mode. _ezero is the boundary between statically
// allocated memory including the fixed MicroPython heap and the stack. If either
// misbehaves, the canary will not be intact after soft reset.
#ifdef CIRCUITPY_CANARY_WORD
#ifdef SAMD21
bool power_on_or_external_reset = hri_pm_get_RCAUSE_POR_bit(PM) || hri_pm_get_RCAUSE_EXT_bit(PM);
bool system_reset = hri_pm_get_RCAUSE_SYST_bit(PM);
#endif
#ifdef SAMD51
bool power_on_or_external_reset = hri_rstc_get_RCAUSE_POR_bit(RSTC) || hri_rstc_get_RCAUSE_EXT_bit(RSTC);
bool system_reset = hri_rstc_get_RCAUSE_SYST_bit(RSTC);
#endif
if (power_on_or_external_reset) {
_ezero = CIRCUITPY_CANARY_WORD;
} else if (system_reset) {
// If we're starting from a system reset we're likely coming from the
// bootloader or hard fault handler. If we're coming from the handler
// the canary will be CIRCUITPY_SAFE_RESTART_WORD and we don't want to
// revive the canary so that a second hard fault won't restart. Resets
// from anywhere else are ok.
if (_ezero == CIRCUITPY_SAFE_RESTART_WORD) {
_ezero = ~CIRCUITPY_CANARY_WORD;
} else {
_ezero = CIRCUITPY_CANARY_WORD;
}
}
#endif
#ifdef SAMD21
hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, 2);
_pm_init();
@ -200,13 +174,6 @@ safe_mode_t port_init(void) {
// Init the board last so everything else is ready
board_init();
#ifdef CIRCUITPY_CANARY_WORD
// Run in safe mode if the canary is corrupt.
if (_ezero != CIRCUITPY_CANARY_WORD) {
return HARD_CRASH;
}
#endif
#ifdef SAMD21
if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) {
return BROWNOUT;
@ -280,6 +247,20 @@ void reset_to_bootloader(void) {
reset();
}
void reset_cpu(void) {
reset();
}
extern uint32_t _ebss;
// Place the word to save just after our BSS section that gets blanked.
void port_set_saved_word(uint32_t value) {
_ebss = value;
}
uint32_t port_get_saved_word(void) {
return _ebss;
}
/**
* \brief Default interrupt handler for unused IRQs.
*/
@ -290,18 +271,9 @@ __attribute__((used)) void HardFault_Handler(void)
// loop below.
REG_MTB_MASTER = 0x00000000 + 6;
#endif
#ifdef CIRCUITPY_CANARY_WORD
// If the canary is intact, then kill it and reset so we have a chance to
// read our files.
if (_ezero == CIRCUITPY_CANARY_WORD) {
_ezero = CIRCUITPY_SAFE_RESTART_WORD;
NVIC_SystemReset();
}
#endif
reset_into_safe_mode(HARD_CRASH);
while (true) {
asm("");
}
for (uint32_t i = 0; i < 100000; i++) {
asm("noop;");
asm("nop;");
}
}

@ -28,6 +28,8 @@
#define MICROPY_HW_MCU_NAME "nRF52832"
#define MICROPY_PY_SYS_PLATFORM "nRF52"
#define MICROPY_HW_LED_STATUS (&pin_P0_17)
#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8)
#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6)

@ -35,6 +35,8 @@
#define MICROPY_HW_NEOPIXEL (&pin_P0_16)
#define MICROPY_HW_LED_STATUS (&pin_P1_15)
#ifdef QSPI_FLASH_FILESYSTEM
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 17)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 22)

@ -33,6 +33,8 @@
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "Particle Argon"
#define MICROPY_HW_LED_STATUS (&pin_P1_12)
#define MICROPY_HW_RGB_LED_RED (&pin_P0_13)
#define MICROPY_HW_RGB_LED_GREEN (&pin_P0_14)
#define MICROPY_HW_RGB_LED_BLUE (&pin_P0_15)

@ -33,6 +33,8 @@
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "Particle Boron"
#define MICROPY_HW_LED_STATUS (&pin_P1_12)
#define MICROPY_HW_RGB_LED_RED (&pin_P0_13)
#define MICROPY_HW_RGB_LED_GREEN (&pin_P0_14)
#define MICROPY_HW_RGB_LED_BLUE (&pin_P0_15)

@ -33,6 +33,8 @@
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "Particle Xenon"
#define MICROPY_HW_LED_STATUS (&pin_P1_12)
#define MICROPY_HW_RGB_LED_RED (&pin_P0_13)
#define MICROPY_HW_RGB_LED_GREEN (&pin_P0_14)
#define MICROPY_HW_RGB_LED_BLUE (&pin_P0_15)

@ -29,6 +29,8 @@
#define MICROPY_HW_MCU_NAME "nRF52832"
#define MICROPY_PY_SYS_PLATFORM "nRF52-DK"
#define MICROPY_HW_LED_STATUS (&pin_P0_17)
#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8)
#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6)
#define MICROPY_HW_UART_HWFC (0)

@ -21,9 +21,13 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_P0_15), MP_ROM_PTR(&pin_P0_15) },
{ MP_ROM_QSTR(MP_QSTR_P0_16), MP_ROM_PTR(&pin_P0_16) },
{ MP_ROM_QSTR(MP_QSTR_P0_17), MP_ROM_PTR(&pin_P0_17) },
{ MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_P0_17) },
{ MP_ROM_QSTR(MP_QSTR_P0_18), MP_ROM_PTR(&pin_P0_18) },
{ MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_P0_18) },
{ MP_ROM_QSTR(MP_QSTR_P0_19), MP_ROM_PTR(&pin_P0_19) },
{ MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_P0_19) },
{ MP_ROM_QSTR(MP_QSTR_P0_20), MP_ROM_PTR(&pin_P0_20) },
{ MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_P0_20) },
{ MP_ROM_QSTR(MP_QSTR_P0_21), MP_ROM_PTR(&pin_P0_21) },
{ MP_ROM_QSTR(MP_QSTR_P0_22), MP_ROM_PTR(&pin_P0_22) },
{ MP_ROM_QSTR(MP_QSTR_P0_23), MP_ROM_PTR(&pin_P0_23) },

@ -33,6 +33,8 @@
#define PORT_HEAP_SIZE (128 * 1024)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define MICROPY_HW_LED_STATUS (&pin_P0_13)
#define DEFAULT_I2C_BUS_SCL (&pin_P0_27)
#define DEFAULT_I2C_BUS_SDA (&pin_P0_26)

@ -28,5 +28,7 @@
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "nRF52840-DK"
#define MICROPY_HW_LED_STATUS (&pin_P0_06)
#define PORT_HEAP_SIZE (128 * 1024)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500

@ -28,6 +28,8 @@
#include "shared-bindings/neopixel_write/__init__.h"
#include "nrf_pwm.h"
#include "tick.h"
// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
// [[[Begin of the Neopixel NRF52 EasyDMA implementation
// by the Hackerspace San Salvador]]]
@ -95,6 +97,9 @@ static NRF_PWM_Type* find_free_pwm (void) {
return NULL;
}
uint64_t next_start_tick_ms = 0;
uint32_t next_start_tick_us = 1000;
void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) {
// To support both the SoftDevice + Neopixels we use the EasyDMA
// feature from the NRF25. However this technique implies to
@ -117,7 +122,7 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
// only malloc if there is PWM device available
if ( pwm != NULL ) {
if (numBytes == 4) {
if (pattern_size <= sizeof(one_pixel) * sizeof(uint32_t)) {
pixels_pattern = (uint16_t *) one_pixel;
} else {
pixels_pattern = (uint16_t *) m_malloc_maybe(pattern_size, false);
@ -125,6 +130,9 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
}
}
// Wait to make sure we don't append onto the last transmission.
wait_until(next_start_tick_ms, next_start_tick_us);
// Use the identified device to choose the implementation
// If a PWM device is available use DMA
if ( (pixels_pattern != NULL) && (pwm != NULL) ) {
@ -140,8 +148,8 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
}
// Zero padding to indicate the end of sequence
pixels_pattern[++pos] = 0 | (0x8000); // Seq end
pixels_pattern[++pos] = 0 | (0x8000); // Seq end
pixels_pattern[pos++] = 0 | (0x8000); // Seq end
pixels_pattern[pos++] = 0 | (0x8000); // Seq end
// Set the wave mode to count UP
// Set the PWM to use the 16MHz clock
@ -274,4 +282,13 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
// Enable interrupts again
__enable_irq();
}
// Update the next start.
current_tick(&next_start_tick_ms, &next_start_tick_us);
if (next_start_tick_us < 100) {
next_start_tick_ms += 1;
next_start_tick_us = 100 - next_start_tick_us;
} else {
next_start_tick_us -= 100;
}
}

@ -32,4 +32,7 @@ void nrf_peripherals_clocks_init(void) {
// generalized.
NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk);
NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
// Wait for clocks to start.
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}
}

@ -28,6 +28,9 @@
#include "supervisor/port.h"
#include "boards/board.h"
#include "nrfx/hal/nrf_power.h"
#include "nrfx/drivers/include/nrfx_power.h"
#include "nrf/cache.h"
#include "nrf/clocks.h"
#include "nrf/power.h"
@ -41,37 +44,32 @@
#include "common-hal/pulseio/PulseOut.h"
#include "tick.h"
safe_mode_t port_init(void) {
static void power_warning_handler(void) {
reset_into_safe_mode(BROWNOUT);
}
safe_mode_t port_init(void) {
nrf_peripherals_clocks_init();
// If GPIO voltage is set wrong in UICR, this will fix it, and
// will also do a reset to make the change take effect.
nrf_peripherals_power_init();
nrfx_power_pofwarn_config_t power_failure_config;
power_failure_config.handler = power_warning_handler;
power_failure_config.thr = NRF_POWER_POFTHR_V27;
power_failure_config.thrvddh = NRF_POWER_POFTHRVDDH_V27;
nrfx_power_pof_init(&power_failure_config);
nrfx_power_pof_enable(&power_failure_config);
nrf_peripherals_enable_cache();
// Configure millisecond timer initialization.
tick_init();
#if 0
#ifdef CIRCUITPY_CANARY_WORD
// Run in safe mode if the canary is corrupt.
if (_ezero != CIRCUITPY_CANARY_WORD) {
return HARD_CRASH;
}
#endif
#endif
// Will do usb_init() if chip supports USB.
board_init();
#if 0
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
}
#endif
return NO_SAFE_MODE;
}
@ -93,13 +91,26 @@ void reset_to_bootloader(void) {
enum { DFU_MAGIC_SERIAL = 0x4e };
NRF_POWER->GPREGRET = DFU_MAGIC_SERIAL;
reset_cpu();
}
void reset_cpu(void) {
NVIC_SystemReset();
}
extern uint32_t _ebss;
// Place the word to save just after our BSS section that gets blanked.
void port_set_saved_word(uint32_t value) {
_ebss = value;
}
uint32_t port_get_saved_word(void) {
return _ebss;
}
void HardFault_Handler(void)
{
void HardFault_Handler(void) {
reset_into_safe_mode(HARD_CRASH);
while (true) {
asm("");
asm("nop;");
}
}

@ -488,6 +488,8 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
mp_obj_type_t *type = mp_obj_get_type(base);
if (type->subscr != NULL) {
mp_obj_t ret = type->subscr(base, index, value);
// May have called port specific C code. Make sure it didn't mess up the heap.
assert_heap_ok();
if (ret != MP_OBJ_NULL) {
return ret;
}

@ -33,12 +33,7 @@
#error "Please define PORT_HEAP_SIZE to specify heap size in bytes."
#endif
typedef enum {
NO_SAFE_MODE = 0,
BROWNOUT,
HARD_CRASH,
USER_SAFE_MODE,
} safe_mode_t;
#include "supervisor/shared/safe_mode.h"
// Provided by the linker;
extern uint32_t _ezero;
@ -51,7 +46,10 @@ extern uint32_t _ebss;
safe_mode_t port_init(void);
// Reset the microcontroller.
// Reset the microcontroller completely.
void reset_cpu(void);
// Reset the microcontroller state.
void reset_port(void);
// Reset the rest of the board.
@ -60,8 +58,8 @@ void reset_board(void);
// Reset to the bootloader
void reset_to_bootloader(void);
#ifdef NRF52_SERIES
void HardFault_Handler(void);
#endif
// Save and retrieve a word from memory that is preserved over reset. Used for safe mode.
void port_set_saved_word(uint32_t);
uint32_t port_get_saved_word(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H

@ -36,6 +36,8 @@
#include "py/mpconfig.h"
#include "rgb_led_colors.h"
#include "supervisor/shared/safe_mode.h"
// Overall, the time module must be implemented.
// To work with a DotStar, one must have MICROPY_HW_APA102_SCK and
// MICROPY_HW_APA102_MOSI defined and bitbangio.SPI or busio.SPI implemented.

@ -0,0 +1,126 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "supervisor/shared/safe_mode.h"
#include "mphalport.h"
// #include "py/mpconfig.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "supervisor/serial.h"
#include "supervisor/shared/rgb_led_colors.h"
#include "supervisor/shared/rgb_led_status.h"
#include "supervisor/shared/translate.h"
#define SAFE_MODE_DATA_GUARD 0xad0000af
#define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff
static safe_mode_t current_safe_mode;
safe_mode_t wait_for_safe_mode_reset(void) {
uint32_t reset_state = port_get_saved_word();
safe_mode_t safe_mode = NO_SAFE_MODE;
if ((reset_state & SAFE_MODE_DATA_GUARD_MASK) == SAFE_MODE_DATA_GUARD) {
safe_mode = (reset_state & ~SAFE_MODE_DATA_GUARD_MASK) >> 8;
}
if (safe_mode != NO_SAFE_MODE) {
port_set_saved_word(SAFE_MODE_DATA_GUARD);
current_safe_mode = safe_mode;
return safe_mode;
}
port_set_saved_word(SAFE_MODE_DATA_GUARD | (MANUAL_SAFE_MODE << 8));
// Wait for a while to allow for reset.
temp_status_color(SAFE_MODE);
#ifdef MICROPY_HW_LED_STATUS
digitalio_digitalinout_obj_t status_led;
common_hal_digitalio_digitalinout_construct(&status_led, MICROPY_HW_LED_STATUS);
common_hal_digitalio_digitalinout_switch_to_output(&status_led, true, DRIVE_MODE_PUSH_PULL);
#endif
uint64_t start_ticks = ticks_ms;
uint64_t diff = 0;
while (diff < 700) {
#ifdef MICROPY_HW_LED_STATUS
// Blink on for 100, off for 100, on for 100, off for 100 and on for 200
common_hal_digitalio_digitalinout_set_value(&status_led, diff > 100 && diff / 100 != 2 && diff / 100 != 4);
#endif
diff = ticks_ms - start_ticks;
}
#ifdef MICROPY_HW_LED_STATUS
common_hal_digitalio_digitalinout_deinit(&status_led);
#endif
clear_temp_status();
port_set_saved_word(SAFE_MODE_DATA_GUARD);
return NO_SAFE_MODE;
}
void reset_into_safe_mode(safe_mode_t reason) {
if (current_safe_mode > BROWNOUT && reason > BROWNOUT) {
while (true) {
// This very bad because it means running in safe mode didn't save us. Only ignore brownout
// because it may be due to a switch bouncing.
}
}
port_set_saved_word(SAFE_MODE_DATA_GUARD | (reason << 8));
reset_cpu();
}
void print_safe_mode_message(safe_mode_t reason) {
// Output a user safe mode string if its set.
#ifdef BOARD_USER_SAFE_MODE
if (reason == USER_SAFE_MODE) {
serial_write("\r\n");
serial_write_compressed(translate("You requested starting safe mode by "));
serial_write(BOARD_USER_SAFE_MODE_ACTION);
serial_write("\r\n");
serial_write_compressed(translate("To exit, please reset the board without "));
serial_write(BOARD_USER_SAFE_MODE_ACTION);
serial_write("\r\n");
} else
#endif
if (reason != NO_SAFE_MODE) {
serial_write("\r\n");
serial_write_compressed(translate("You are running in safe mode which means something unanticipated happened.\n"));
if (reason == HARD_CRASH || reason == MICROPY_NLR_JUMP_FAIL || reason == MICROPY_FATAL_ERROR) {
serial_write_compressed(translate("Looks like our core CircuitPython code crashed hard. Whoops!\nPlease file an issue at https://github.com/adafruit/circuitpython/issues\n with the contents of your CIRCUITPY drive and this message:\n"));
if (reason == HARD_CRASH) {
serial_write_compressed(translate("Crash into the HardFault_Handler.\n"));
} else if (reason == MICROPY_NLR_JUMP_FAIL) {
serial_write_compressed(translate("MicroPython NLR jump failed. Likely memory corruption.\n"));
} else if (reason == MICROPY_FATAL_ERROR) {
serial_write_compressed(translate("MicroPython fatal error.\n"));
}
} else if (reason == BROWNOUT) {
serial_write_compressed(translate("The microcontroller's power dipped. Please make sure your power supply provides\nenough power for the whole circuit and press reset (after ejecting CIRCUITPY).\n"));
} else if (reason == HEAP_OVERWRITTEN) {
serial_write_compressed(translate("The CircuitPython heap was corrupted because the stack was too small.\nPlease increase stack size limits and press reset (after ejecting CIRCUITPY).\nIf you didn't change the stack, then file an issue here with the contents of your CIRCUITPY drive:\n"));
serial_write("https://github.com/adafruit/circuitpython/issues\r\n");
} else if (reason == MANUAL_SAFE_MODE) {
serial_write_compressed(translate("The reset button was pressed while booting CircuitPython. Press again to exit safe mode.\n"));
}
}
}

@ -0,0 +1,47 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SUPERVISOR_SAFE_MODE_H
#define MICROPY_INCLUDED_SUPERVISOR_SAFE_MODE_H
typedef enum {
NO_SAFE_MODE = 0,
BROWNOUT,
HARD_CRASH,
USER_SAFE_MODE,
HEAP_OVERWRITTEN,
MANUAL_SAFE_MODE,
MICROPY_NLR_JUMP_FAIL,
MICROPY_FATAL_ERROR
} safe_mode_t;
safe_mode_t wait_for_safe_mode_reset(void);
void reset_into_safe_mode(safe_mode_t reason);
void print_safe_mode_message(safe_mode_t reason);
#endif // MICROPY_INCLUDED_SUPERVISOR_SAFE_MODE_H

@ -29,6 +29,7 @@
#include "py/mpconfig.h"
#include "py/runtime.h"
#include "supervisor/cpu.h"
#include "supervisor/shared/safe_mode.h"
extern uint32_t _estack;
@ -38,8 +39,6 @@ supervisor_allocation* stack_alloc = NULL;
#define EXCEPTION_STACK_SIZE 1024
#define STACK_CANARY_VALUE 0x017829ef
void allocate_stack(void) {
mp_uint_t regs[10];
mp_uint_t sp = cpu_get_regs_and_sp(regs);
@ -62,9 +61,7 @@ inline bool stack_ok(void) {
inline void assert_heap_ok(void) {
if (!stack_ok()) {
asm("nop");
while(true) {}
mp_raise_RuntimeError(translate("Stack clobbered heap."));
reset_into_safe_mode(HEAP_OVERWRITTEN);
}
}

@ -40,7 +40,9 @@ uint32_t get_current_stack_size(void);
bool stack_ok(void);
// Use this after any calls into a library which may use a lot of stack. This will raise a Python
// exception when the stack has likely overwritten a portio of the heap.
// exception when the stack has likely overwritten a portion of the heap.
void assert_heap_ok(void);
#define STACK_CANARY_VALUE 0x017829ef
#endif // MICROPY_INCLUDED_SUPERVISOR_STACK_H

@ -34,6 +34,14 @@
#include "genhdr/compression.generated.h"
#endif
#include "supervisor/serial.h"
void serial_write_compressed(const compressed_string_t* compressed) {
char decompressed[compressed->length];
decompress(compressed, decompressed);
serial_write(decompressed);
}
char* decompress(const compressed_string_t* compressed, char* decompressed) {
uint8_t this_byte = 0;
uint8_t this_bit = 7;

@ -35,7 +35,7 @@ typedef struct {
} compressed_string_t;
const compressed_string_t* translate(const char* c);
void serial_write_compressed(const compressed_string_t* compressed);
char* decompress(const compressed_string_t* compressed, char* decompressed);
#endif // MICROPY_INCLUDED_SUPERVISOR_TRANSLATE_H

@ -6,6 +6,7 @@ SRC_SUPERVISOR = \
supervisor/shared/flash.c \
supervisor/shared/micropython.c \
supervisor/shared/rgb_led_status.c \
supervisor/shared/safe_mode.c \
supervisor/shared/stack.c \
supervisor/shared/status_leds.c \
supervisor/shared/translate.c

Loading…
Cancel
Save