Skip to content

Commit 3814e97

Browse files
authored
Merge pull request adafruit#802 from dhalbert/2.x-filesystem-work
2.x: handle bad power on reset better
2 parents ffc66e9 + 74a6edf commit 3814e97

File tree

7 files changed

+147
-27
lines changed

7 files changed

+147
-27
lines changed

atmel-samd/asf/sam0/drivers/tc/tc.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
#define TC_H_INCLUDED
4949

5050
/**
51-
* \defgroup asfdoc_sam0_tc_group SAM Timer/Counter (TC) Driver
51+
* \defgroup asfdoc_sam0_tc_group SAM Timer/Counter (TC) Driver
5252
*
5353
* This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration
5454
* and management of the timer modules within the device, for waveform
@@ -1146,12 +1146,14 @@ static inline void tc_enable_events(
11461146
/* Sanity check arguments */
11471147
Assert(module_inst);
11481148
Assert(module_inst->hw);
1149-
Assert(events);
1149+
Assert(events);
11501150

11511151
Tc *const tc_module = module_inst->hw;
11521152

11531153
uint32_t event_mask = 0;
11541154

1155+
#pragma GCC diagnostic push
1156+
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
11551157
if (events->invert_event_input == true) {
11561158
event_mask |= TC_EVCTRL_TCINV;
11571159
}
@@ -1171,6 +1173,7 @@ static inline void tc_enable_events(
11711173
}
11721174

11731175
tc_module->COUNT8.EVCTRL.reg |= event_mask | events->event_action;
1176+
#pragma GCC diagnostic pop
11741177
}
11751178

11761179
/**

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#include <string.h>
2828

2929
#include "flash_api.h"
30+
#include "main.h"
3031
#include "py/mperrno.h"
3132
#include "py/runtime.h"
33+
#include "shared-bindings/microcontroller/__init__.h"
3234
#include "shared-bindings/storage/__init__.h"
3335

3436
extern volatile bool mp_msc_enabled;
@@ -44,3 +46,9 @@ void common_hal_storage_remount(const char* mount_path, bool readonly) {
4446

4547
flash_set_usb_writeable(readonly);
4648
}
49+
50+
void common_hal_storage_erase_filesystem(void) {
51+
init_flash_fs(false, true); // Force a re-format.
52+
common_hal_mcu_reset();
53+
// We won't actually get here, since we're resetting.
54+
}

atmel-samd/main.c

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
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) {
528529
extern uint32_t _ezero;
529530

530531
safe_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

atmel-samd/main.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
// Functions defined in main.c that are useful elsewhere.
28+
// Eventually they should be factored out.
29+
30+
void init_flash_fs(bool create_allowed, bool force_create);

esp8266/common-hal/storage/__init__.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@
3232
void common_hal_storage_remount(const char* mount_path, bool readonly) {
3333
mp_raise_NotImplementedError("");
3434
}
35+
36+
void common_hal_storage_erase_filesystem() {
37+
mp_raise_NotImplementedError("Use esptool to erase flash and re-upload Python instead");
38+
}

shared-bindings/storage/__init__.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,32 @@ mp_obj_t storage_remount(mp_obj_t mount_path, mp_obj_t readonly) {
115115
}
116116
MP_DEFINE_CONST_FUN_OBJ_2(storage_remount_obj, storage_remount);
117117

118+
//| .. function:: erase_filesystem()
119+
//|
120+
//| Erase and re-create the ``CIRCUITPY`` filesystem. Then call
121+
//| `microcontroller.reset()` to restart CircuitPython and have the
122+
//| host computer remount CIRCUITPY.
123+
//|
124+
//| This function can be called from the REPL when ``CIRCUITPY``
125+
//| has become corrupted.
126+
//|
127+
//| .. warning:: All the data on ``CIRCUITPY`` will be lost, and
128+
//| CircuitPython will restart.
129+
130+
mp_obj_t storage_erase_filesystem(void) {
131+
common_hal_storage_erase_filesystem();
132+
return mp_const_none;
133+
}
134+
MP_DEFINE_CONST_FUN_OBJ_0(storage_erase_filesystem_obj, storage_erase_filesystem);
135+
136+
118137
STATIC const mp_rom_map_elem_t storage_module_globals_table[] = {
119138
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_storage) },
120139

121140
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) },
122141
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) },
123142
{ MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) },
143+
{ MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) },
124144

125145
//| .. class:: VfsFat(block_device)
126146
//|

shared-bindings/storage/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ void common_hal_storage_mount(mp_obj_t vfs_obj, const char* path, bool readonly)
3434
void common_hal_storage_umount_path(const char* path);
3535
void common_hal_storage_umount_object(mp_obj_t vfs_obj);
3636
void common_hal_storage_remount(const char* path, bool readonly);
37+
void common_hal_storage_erase_filesystem(void);
3738

3839
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_STORAGE___INIT___H

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy