6666
6767#include "autoreload.h"
6868#include "flash_api.h"
69+ #include "main.h"
6970#include "mpconfigboard.h"
7071#include "rgb_led_status.h"
7172#include "shared_dma.h"
@@ -110,7 +111,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
110111
111112// we don't make this function static because it needs a lot of stack and we
112113// want it to be executed without using stack within main() function
113- void init_flash_fs (bool create_allowed ) {
114+ void init_flash_fs (bool create_allowed , bool force_create ) {
114115 // init the vfs object
115116 fs_user_mount_t * vfs_fat = & fs_user_mount_flash ;
116117 vfs_fat -> flags = 0 ;
@@ -119,8 +120,8 @@ void init_flash_fs(bool create_allowed) {
119120 // try to mount the flash
120121 FRESULT res = f_mount (& vfs_fat -> fatfs );
121122
122- if (res == FR_NO_FILESYSTEM && create_allowed ) {
123- // no filesystem so create a fresh one
123+ if (( res == FR_NO_FILESYSTEM && create_allowed ) || force_create ) {
124+ // No filesystem so create a fresh one, or reformat has been requested.
124125
125126 // Wait two seconds before creating. Jittery power might
126127 // fail before we're ready. This can happen if someone
@@ -129,10 +130,10 @@ void init_flash_fs(bool create_allowed) {
129130
130131 // Then try one more time to mount the flash in case it was late coming up.
131132 res = f_mount (& vfs_fat -> fatfs );
132- if (res == FR_NO_FILESYSTEM ) {
133+ if (res == FR_NO_FILESYSTEM || force_create ) {
133134 uint8_t working_buf [_MAX_SS ];
134135 res = f_mkfs (& vfs_fat -> fatfs , FM_FAT , 0 , working_buf , sizeof (working_buf ));
135- // Flush the new file system to make sure its repaired immediately.
136+ // Flush the new file system to make sure it's repaired immediately.
136137 flash_flush ();
137138 if (res != FR_OK ) {
138139 return ;
@@ -528,6 +529,14 @@ void load_serial_number(void) {
528529extern uint32_t _ezero ;
529530
530531safe_mode_t samd21_init (void ) {
532+
533+ // Set brownout detection to ~2.7V. Default from factory is 1.7V,
534+ // which is too low for proper operation of external SPI flash chips (they are 2.7-3.6V).
535+ // Disable while changing level.
536+ SYSCTRL -> BOD33 .bit .ENABLE = 0 ;
537+ SYSCTRL -> BOD33 .bit .LEVEL = 39 ; // 2.77V with hysteresis off. Table 37.20 in datasheet.
538+ SYSCTRL -> BOD33 .bit .ENABLE = 1 ;
539+
531540#ifdef ENABLE_MICRO_TRACE_BUFFER
532541 REG_MTB_POSITION = ((uint32_t ) (mtb - REG_MTB_BASE )) & 0xFFFFFFF8 ;
533542 REG_MTB_FLOW = (((uint32_t ) mtb - REG_MTB_BASE ) + TRACE_BUFFER_SIZE_BYTES ) & 0xFFFFFFF8 ;
@@ -683,9 +692,9 @@ int main(void) {
683692 // Create a new filesystem only if we're not in a safe mode.
684693 // A power brownout here could make it appear as if there's
685694 // no SPI flash filesystem, and we might erase the existing one.
686- init_flash_fs (safe_mode == NO_SAFE_MODE );
695+ init_flash_fs (safe_mode == NO_SAFE_MODE , false );
687696
688- // Reset everything and prep MicroPython to run boot.py.
697+ // Reset everything and prep to run boot.py.
689698 reset_samd21 ();
690699 reset_board ();
691700 reset_mp ();
@@ -694,38 +703,83 @@ int main(void) {
694703 autoreload_enable ();
695704
696705 // By default our internal flash is readonly to local python code and
697- // writeable over USB. Set it here so that boot.py can change it .
706+ // writable over USB.
698707 flash_set_usb_writeable (true);
699708
700709 // If not in safe mode, run boot before initing USB and capture output in a
701710 // file.
702711 if (safe_mode == NO_SAFE_MODE && MP_STATE_VM (vfs_mount_table ) != NULL ) {
703712 new_status_color (BOOT_RUNNING );
713+
714+ // Run the first of these files found at boot time (if any).
715+ static char const * BOOT_PY_FILENAMES [] = {
716+ "settings.txt" ,
717+ "settings.py" ,
718+ "boot.py" ,
719+ "boot.txt" ,
720+ };
721+
722+ // Check for existance of any of the BOOT_PY_FILENAMES.
723+ char const * boot_py_to_use = NULL ;
724+ for (size_t i = 0 ; i < MP_ARRAY_SIZE (BOOT_PY_FILENAMES ); i ++ ) {
725+ if (mp_import_stat (BOOT_PY_FILENAMES [i ]) == MP_IMPORT_STAT_FILE ) {
726+ boot_py_to_use = BOOT_PY_FILENAMES [i ];
727+ break ;
728+ }
729+ }
730+
704731 #ifdef CIRCUITPY_BOOT_OUTPUT_FILE
705- // Since USB isn't up yet we can cheat and let ourselves write the boot
706- // output file.
707- flash_set_usb_writeable (false);
708732 FIL file_pointer ;
709733 boot_output_file = & file_pointer ;
710- f_open (& ((fs_user_mount_t * ) MP_STATE_VM (vfs_mount_table )-> obj )-> fatfs ,
711- boot_output_file , CIRCUITPY_BOOT_OUTPUT_FILE , FA_WRITE | FA_CREATE_ALWAYS );
712- flash_set_usb_writeable (true);
713- // Write version info to boot_out.txt.
714- mp_hal_stdout_tx_str (MICROPY_FULL_VERSION_INFO );
715- mp_hal_stdout_tx_str ("\r\n" );
734+
735+ // Get the base filesystem.
736+ FATFS * fs = & ((fs_user_mount_t * ) MP_STATE_VM (vfs_mount_table )-> obj )-> fatfs ;
737+
738+ char file_contents [512 ];
739+ UINT chars_read = 0 ;
740+ bool skip_boot_output = false;
741+
742+ // If there's no boot.py file that might write some changing output,
743+ // read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
744+ // match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
745+ // This saves wear and tear on the flash and also prevents filesystem damage if power is lost
746+ // during the write, which may happen due to bobbling the power connector or weak power.
747+
748+ if (!boot_py_to_use && f_open (fs , boot_output_file , CIRCUITPY_BOOT_OUTPUT_FILE , FA_READ ) == FR_OK ) {
749+ f_read (boot_output_file , file_contents , 512 , & chars_read );
750+ f_close (boot_output_file );
751+ skip_boot_output =
752+ // + 2 accounts for \r\n.
753+ chars_read == strlen (MICROPY_FULL_VERSION_INFO ) + 2 &&
754+ strncmp (file_contents , MICROPY_FULL_VERSION_INFO , strlen (MICROPY_FULL_VERSION_INFO )) == 0 ;
755+ }
756+
757+ if (!skip_boot_output ) {
758+ // Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
759+ // in case power is momentary or will fail shortly due to, say a low, battery.
760+ mp_hal_delay_ms (1500 );
761+
762+ // USB isn't up, so we can write the file.
763+ flash_set_usb_writeable (false);
764+ f_open (fs , boot_output_file , CIRCUITPY_BOOT_OUTPUT_FILE , FA_WRITE | FA_CREATE_ALWAYS );
765+ // Write version info to boot_out.txt.
766+ mp_hal_stdout_tx_str (MICROPY_FULL_VERSION_INFO );
767+ mp_hal_stdout_tx_str ("\r\n" );
768+ }
716769 #endif
717770
718771 // TODO(tannewt): Re-add support for flashing boot error output.
719- bool found_boot = maybe_run ("settings.txt" , NULL ) ||
720- maybe_run ("settings.py" , NULL ) ||
721- maybe_run ("boot.py" , NULL ) ||
722- maybe_run ("boot.txt" , NULL );
723- (void ) found_boot ;
772+ if (boot_py_to_use ) {
773+ maybe_run (boot_py_to_use , NULL );
774+ }
724775
725776 #ifdef CIRCUITPY_BOOT_OUTPUT_FILE
726- f_close (boot_output_file );
727- flash_flush ();
728- boot_output_file = NULL ;
777+ if (!skip_boot_output ) {
778+ f_close (boot_output_file );
779+ flash_flush ();
780+ boot_output_file = NULL ;
781+ }
782+ flash_set_usb_writeable (true);
729783 #endif
730784
731785 // Reset to remove any state that boot.py setup. It should only be used to
0 commit comments