8000 Merge pull request #804 from dhalbert/boot_out_fixes · godlygeek/circuitpython@d32349c · GitHub
[go: up one dir, main page]

Skip to content

Commit d32349c

Browse files
authored
Merge pull request adafruit#804 from dhalbert/boot_out_fixes
3.0: Handle bad power on reset.
2 parents 034b189 + f73e06d commit d32349c

File tree

3 files changed

+91
-20
lines changed

3 files changed

+91
-20
lines changed

main.c

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "extmod/vfs.h"
3131
#include "extmod/vfs_fat.h"
3232

33+
#include "genhdr/mpversion.h"
3334
#include "py/nlr.h"
3435
#include "py/compile.h"
3536
#include "py/frozenmod.h"
@@ -99,19 +100,27 @@ void reset_mp(void) {
99100
}
100101
#define STRING_LIST(...) {__VA_ARGS__, ""}
101102

102-
bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
103-
103+
// Look for the first file that exists in the list of filenames, using mp_import_stat().
104+
// Return its index. If no file found, return -1.
105+
const char* first_existing_file_in_list(const char ** filenames) {
104106
for (int i = 0; filenames[i] != (char*)""; i++) {
105107
mp_import_stat_t stat = mp_import_stat(filenames[i]);
106-
if (stat != MP_IMPORT_STAT_FILE) {
107-
continue;
108+
if (stat == MP_IMPORT_STAT_FILE) {
109+
return filenames[i];
108110
}
109-
serial_write(filenames[i]);
110-
serial_write(MSG_OUTPUT_SUFFIX);
111-
pyexec_file(filenames[i], exec_result);
112-
return true;
113111
}
114-
return false;
112+
return NULL;
113+
}
114+
115+
bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
116+
const char* filename = first_existing_file_in_list(filenames);
117+
if (filename == NULL) {
118+
return false;
119+
}
120+
mp_hal_stdout_tx_str(filename);
121+
mp_hal_stdout_tx_str(MSG_OUTPUT_SUFFIX);
122+
pyexec_file(filename, exec_result);
123+
return true;
115124
}
116125

117126
bool start_mp(safe_mode_t safe_mode) {
@@ -261,27 +270,64 @@ int __attribute__((used)) main(void) {
261270
// If not in safe mode, run boot before initing USB and capture output in a
262271
// file.
263272
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
273+
static const char *boot_py_filenames[] = STRING_LIST("settings.txt", "settings.py", "boot.py", "boot.txt");
274+
264275
new_status_color(BOOT_RUNNING);
276+
265277
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
266-
// Since USB isn't up yet we can cheat and let ourselves write the boot
267-
// output file.
268-
filesystem_writable_by_python(true);
269278
FIL file_pointer;
270279
boot_output_file = &file_pointer;
271-
f_open(&((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs,
272-
boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
273-
filesystem_writable_by_python(false);
280+
281+
// Get the base filesystem.
282+
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;
283+
284+
bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;
285+
286+
bool skip_boot_output = false;
287+
288+
// If there's no boot.py file that might write some changing output,
289+
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
290+
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
291+
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
292+
// during the write, which may happen due to bobbling the power connector or weak power.
293+
294+
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
295+
char file_contents[512];
296+
UINT chars_read = 0;
297+
f_read(boot_output_file, file_contents, 512, &chars_read);
298+
f_close(boot_output_file);
299+
skip_boot_output =
300+
// + 2 accounts for \r\n.
301+
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
302+
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
303+
}
304+
305+
if (!skip_boot_output) {
306+
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
307+
// in case power is momentary or will fail shortly due to, say a low, battery.
308+
mp_hal_delay_ms(1500);
309+
310+
// USB isn't up, so we can write the file.
311+
filesystem_writable_by_python(true);
312+
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
313+
314+
// Write version info to boot_out.txt.
315+
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
316+
mp_hal_stdout_tx_str("\r\n");
317+
}
274318
#endif
275319

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

281324
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
282-
f_close(boot_output_file);
283-
filesystem_flush();
284-
boot_output_file = NULL;
325+
if (!skip_boot_output) {
326+
f_close(boot_output_file);
327+
filesystem_flush();
328+
boot_output_file = NULL;
329+
}
330+
filesystem_writable_by_python(false);
285331
#endif
286332

287333
// Reset to remove any state that boot.py setup. It should only be used to

ports/atmel-samd/mphalport.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
4545
gpio_toggle_pin_level(MICROPY_HW_LED_TX);
4646
#endif
4747

48+
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
49+
if (boot_output_file != NULL) {
50+
UINT bytes_written = 0;
51+
f_write(boot_output_file, str, len, &bytes_written);
52+
}
53+
#endif
54+
4855
usb_write(str, len);
4956
}
5057

ports/atmel-samd/supervisor/port.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ __attribute__((__aligned__(TRACE_BUFFER_SIZE_BYTES))) uint32_t mtb[TRACE_BUFFER_
7979

8080
safe_mode_t port_init(void) {
8181
#if defined(SAMD21)
82+
83+
// Set brownout detection to ~2.7V. Default from factory is 1.7V,
84+
// which is too low for proper operation of external SPI flash chips (they are 2.7-3.6V).
85+
// Disable while changing level.
86+
SYSCTRL->BOD33.bit.ENABLE = 0;
87+
SYSCTRL->BOD33.bit.LEVEL = 39; // 2.77V with hysteresis off. Table 37.20 in datasheet.
88+
SYSCTRL->BOD33.bit.ENABLE = 1;
89+
8290
#ifdef ENABLE_MICRO_TRACE_BUFFER
8391
REG_MTB_POSITION = ((uint32_t) (mtb - REG_MTB_BASE)) & 0xFFFFFFF8;
8492
REG_MTB_FLOW = (((uint32_t) mtb - REG_MTB_BASE) + TRACE_BUFFER_SIZE_BYTES) & 0xFFFFFFF8;
@@ -90,6 +98,16 @@ safe_mode_t port_init(void) {
9098
#endif
9199
#endif
92100

101+
#if defined(SAMD51)
102+
// Set brownout detection to ~2.7V. Default from factory is 1.7V,
103+
// which is too low for proper operation of external SPI flash chips (they are 2.7-3.6V).
104+
// Disable while changing level.
105+
SUPC->BOD33.bit.ENABLE = 0;
106+
SUPC->BOD33.bit.LEVEL = 200; // 2.7V: 1.5V + LEVEL * 6mV.
107+
SUPC->BOD33.bit.ENABLE = 1;
108+
#endif
109+
110+
93111

94112
// On power on start or external reset, set _ezero to the canary word. If it
95113
// gets killed, we boot in safe mode. _ezero is the boundary between statically

0 commit comments

Comments
 (0)
0