Skip to content

3.0: Handle bad power on reset. #804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 66 additions & 20 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"

#include "genhdr/mpversion.h"
#include "py/nlr.h"
#include "py/compile.h"
#include "py/frozenmod.h"
Expand Down Expand Up @@ -99,19 +100,27 @@ void reset_mp(void) {
}
#define STRING_LIST(...) {__VA_ARGS__, ""}

bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {

// Look for the first file that exists in the list of filenames, using mp_import_stat().
// Return its index. If no file found, return -1.
const char* first_existing_file_in_list(const char ** filenames) {
for (int i = 0; filenames[i] != (char*)""; i++) {
mp_import_stat_t stat = mp_import_stat(filenames[i]);
if (stat != MP_IMPORT_STAT_FILE) {
continue;
if (stat == MP_IMPORT_STAT_FILE) {
return filenames[i];
}
serial_write(filenames[i]);
serial_write(MSG_OUTPUT_SUFFIX);
pyexec_file(filenames[i], exec_result);
return true;
}
return false;
return NULL;
}

bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
const char* filename = first_existing_file_in_list(filenames);
if (filename == NULL) {
return false;
}
mp_hal_stdout_tx_str(filename);
mp_hal_stdout_tx_str(MSG_OUTPUT_SUFFIX);
pyexec_file(filename, exec_result);
return true;
}

bool start_mp(safe_mode_t safe_mode) {
Expand Down Expand Up @@ -261,27 +270,64 @@ int __attribute__((used)) main(void) {
// If not in safe mode, run boot before initing USB and capture output in a
// file.
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
static const char *boot_py_filenames[] = STRING_LIST("settings.txt", "settings.py", "boot.py", "boot.txt");

new_status_color(BOOT_RUNNING);

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
// Since USB isn't up yet we can cheat and let ourselves write the boot
// output file.
filesystem_writable_by_python(true);
FIL file_pointer;
boot_output_file = &file_pointer;
f_open(&((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs,
boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
filesystem_writable_by_python(false);

// Get the base filesystem.
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;

bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;

bool skip_boot_output = false;

// If there's no boot.py file that might write some changing output,
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
// during the write, which may happen due to bobbling the power connector or weak power.

if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char file_contents[512];
UINT chars_read = 0;
f_read(boot_output_file, file_contents, 512, &chars_read);
f_close(boot_output_file);
skip_boot_output =
// + 2 accounts for \r\n.
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
}

if (!skip_boot_output) {
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
// in case power is momentary or will fail shortly due to, say a low, battery.
mp_hal_delay_ms(1500);

// USB isn't up, so we can write the file.
filesystem_writable_by_python(true);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);

// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
mp_hal_stdout_tx_str("\r\n");
}
#endif

// TODO(tannewt): Re-add support for flashing boot error output.
static const char *filenames[] = STRING_LIST("settings.txt", "settings.py", "boot.py", "boot.txt");
bool found_boot = maybe_run_list(filenames, NULL);
bool found_boot = maybe_run_list(boot_py_filenames, NULL);
(void) found_boot;

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
f_close(boot_output_file);
filesystem_flush();
boot_output_file = NULL;
if (!skip_boot_output) {
f_close(boot_output_file);
filesystem_flush();
boot_output_file = NULL;
}
filesystem_writable_by_python(false);
#endif

// Reset to remove any state that boot.py setup. It should only be used to
Expand Down
7 changes: 7 additions & 0 deletions ports/atmel-samd/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
gpio_toggle_pin_level(MICROPY_HW_LED_TX);
#endif

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (boot_output_file != NULL) {
UINT bytes_written = 0;
f_write(boot_output_file, str, len, &bytes_written);
}
#endif

usb_write(str, len);
}

Expand Down
18 changes: 18 additions & 0 deletions ports/atmel-samd/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ __attribute__((__aligned__(TRACE_BUFFER_SIZE_BYTES))) uint32_t mtb[TRACE_BUFFER_

safe_mode_t port_init(void) {
#if defined(SAMD21)

// Set brownout detection to ~2.7V. Default from factory is 1.7V,
// which is too low for proper operation of external SPI flash chips (they are 2.7-3.6V).
// Disable while changing level.
SYSCTRL->BOD33.bit.ENABLE = 0;
SYSCTRL->BOD33.bit.LEVEL = 39; // 2.77V with hysteresis off. Table 37.20 in datasheet.
SYSCTRL->BOD33.bit.ENABLE = 1;

#ifdef ENABLE_MICRO_TRACE_BUFFER
REG_MTB_POSITION = ((uint32_t) (mtb - REG_MTB_BASE)) & 0xFFFFFFF8;
REG_MTB_FLOW = (((uint32_t) mtb - REG_MTB_BASE) + TRACE_BUFFER_SIZE_BYTES) & 0xFFFFFFF8;
Expand All @@ -90,6 +98,16 @@ safe_mode_t port_init(void) {
#endif
#endif

#if defined(SAMD51)
// Set brownout detection to ~2.7V. Default from factory is 1.7V,
// which is too low for proper operation of external SPI flash chips (they are 2.7-3.6V).
// Disable while changing level.
SUPC->BOD33.bit.ENABLE = 0;
SUPC->BOD33.bit.LEVEL = 200; // 2.7V: 1.5V + LEVEL * 6mV.
SUPC->BOD33.bit.ENABLE = 1;
#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
Expand Down