diff --git a/extmod/modvfs.c b/extmod/modvfs.c index df422365b75ef..2730e8cbc97d4 100644 --- a/extmod/modvfs.c +++ b/extmod/modvfs.c @@ -38,6 +38,10 @@ #error "MICROPY_PY_VFS requires MICROPY_VFS" #endif +#if MICROPY_VFS_ROM +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_rom_ioctl_obj, 1, 4, mp_vfs_rom_ioctl); +#endif + static const mp_rom_map_elem_t vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_vfs) }, @@ -53,6 +57,7 @@ static const mp_rom_map_elem_t vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) }, #endif #if MICROPY_VFS_ROM + { MP_ROM_QSTR(MP_QSTR_rom_ioctl), MP_ROM_PTR(&mp_vfs_rom_ioctl_obj) }, { MP_ROM_QSTR(MP_QSTR_VfsRom), MP_ROM_PTR(&mp_type_vfs_rom) }, #endif #if MICROPY_VFS_POSIX diff --git a/extmod/vfs.h b/extmod/vfs.h index 626e25a351123..543b2a8808f26 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -52,6 +52,13 @@ #define MP_BLOCKDEV_IOCTL_BLOCK_SIZE (5) #define MP_BLOCKDEV_IOCTL_BLOCK_ERASE (6) +// Constants for vfs.rom_ioctl() function. +#define MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS (1) // rom_ioctl(1) +#define MP_VFS_ROM_IOCTL_GET_SEGMENT (2) // rom_ioctl(2, ) +#define MP_VFS_ROM_IOCTL_WRITE_PREPARE (3) // rom_ioctl(3, , ) +#define MP_VFS_ROM_IOCTL_WRITE (4) // rom_ioctl(4, , , ) +#define MP_VFS_ROM_IOCTL_WRITE_COMPLETE (5) // rom_ioctl(5, ) + // At the moment the VFS protocol just has import_stat, but could be extended to other methods typedef struct _mp_vfs_proto_t { mp_import_stat_t (*import_stat)(void *self, const char *path); @@ -122,4 +129,9 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_stat_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj); +#if MICROPY_VFS_ROM +// A port must define this. +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args); +#endif + #endif // MICROPY_INCLUDED_EXTMOD_VFS_H diff --git a/ports/esp32/esp32_partition.c b/ports/esp32/esp32_partition.c index 55830a285b0b6..485cbca1a71ad 100644 --- a/ports/esp32/esp32_partition.c +++ b/ports/esp32/esp32_partition.c @@ -53,6 +53,20 @@ typedef struct _esp32_partition_obj_t { uint16_t block_size; } esp32_partition_obj_t; +#if MICROPY_VFS_ROM + +static esp32_partition_obj_t esp32_partition_romfs_obj = { + .base = { .type = NULL }, + .part = NULL, + .cache = NULL, + .block_size = NATIVE_BLOCK_SIZE_BYTES, +}; + +static const void *esp32_partition_romfs_ptr = NULL; +static esp_partition_mmap_handle_t esp32_partition_romfs_handle; + +#endif + static esp32_partition_obj_t *esp32_partition_new(const esp_partition_t *part, uint16_t block_size) { if (part == NULL) { mp_raise_OSError(MP_ENOENT); @@ -114,6 +128,24 @@ static mp_obj_t esp32_partition_make_new(const mp_obj_type_t *type, size_t n_arg return MP_OBJ_FROM_PTR(esp32_partition_new(part, block_size)); } +#if MICROPY_VFS_ROM +static mp_int_t esp32_partition_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self == &esp32_partition_romfs_obj && flags == MP_BUFFER_READ) { + if (esp32_partition_romfs_ptr == NULL) { + check_esp_err(esp_partition_mmap(self->part, 0, self->part->size, ESP_PARTITION_MMAP_DATA, &esp32_partition_romfs_ptr, &esp32_partition_romfs_handle)); + } + bufinfo->buf = (void *)esp32_partition_romfs_ptr; + bufinfo->len = self->part->size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Unsupported. + return 1; + } +} +#endif + static mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // Parse args enum { ARG_type, ARG_subtype, ARG_label, ARG_block_size }; @@ -284,11 +316,51 @@ static const mp_rom_map_elem_t esp32_partition_locals_dict_table[] = { }; static MP_DEFINE_CONST_DICT(esp32_partition_locals_dict, esp32_partition_locals_dict_table); +#if MICROPY_VFS_ROM +#define ESP32_PARTITION_GET_BUFFER buffer, esp32_partition_get_buffer, +#else +#define ESP32_PARTITION_GET_BUFFER +#endif + MP_DEFINE_CONST_OBJ_TYPE( esp32_partition_type, MP_QSTR_Partition, MP_TYPE_FLAG_NONE, make_new, esp32_partition_make_new, print, esp32_partition_print, + ESP32_PARTITION_GET_BUFFER locals_dict, &esp32_partition_locals_dict ); + +/******************************************************************************/ +// romfs partition + +#if MICROPY_VFS_ROM + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (esp32_partition_romfs_obj.base.type == NULL) { + esp32_partition_romfs_obj.base.type = &esp32_partition_type; + // Get the romfs partition. + // TODO: number of segments ioctl can be used if there is more than one romfs. + esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "romfs"); + if (iter != NULL) { + esp32_partition_romfs_obj.part = esp_partition_get(iter); + } + esp_partition_iterator_release(iter); + } + + if (esp32_partition_romfs_obj.part == NULL) { + return MP_OBJ_NEW_SMALL_INT(-MP_ENODEV); + } + + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&esp32_partition_romfs_obj); + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM diff --git a/ports/esp32/modules/_boot.py b/ports/esp32/modules/_boot.py index 96af581f38a5c..8c8b4a24bc5ff 100644 --- a/ports/esp32/modules/_boot.py +++ b/ports/esp32/modules/_boot.py @@ -1,7 +1,14 @@ import gc import vfs +import sys from flashbdev import bdev +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass + try: if bdev: vfs.mount(bdev, "/") @@ -11,3 +18,5 @@ inisetup.setup() gc.collect() + +del sys diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b5b7d63a56333..6488b8f78646f 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -70,6 +70,7 @@ #define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_VFS (1) +#define MICROPY_VFS_ROM (1) // control over Python builtins #define MICROPY_PY_STR_BYTES_CMP_WARN (1) diff --git a/ports/esp32/partitions-4MiB.csv b/ports/esp32/partitions-4MiB.csv index 53f0f167442bc..dd02506e54684 100644 --- a/ports/esp32/partitions-4MiB.csv +++ b/ports/esp32/partitions-4MiB.csv @@ -3,5 +3,6 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 0x1F0000, +factory, app, factory, 0x10000, 0x1D0000, +romfs, data, 0x8f, 0x1E0000, 0x20000, vfs, data, fat, 0x200000, 0x200000, diff --git a/ports/esp8266/boards/ESP8266_GENERIC/_boot.py b/ports/esp8266/boards/ESP8266_GENERIC/_boot.py index 16da8bc4c3750..048d8a06ec8f7 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/_boot.py +++ b/ports/esp8266/boards/ESP8266_GENERIC/_boot.py @@ -1,6 +1,13 @@ # Minimal _boot.py for the 512kiB variant. Does not set up a block device or # filesystem. Other variants use esp8266/modules/_boot.py. -import gc +import gc, vfs gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) + +# Try to mount the ROMFS. +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/") +except: + pass + diff --git a/ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py b/ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py index 15f6cffc3f94a..9abaaa746f7c4 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py +++ b/ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py @@ -1,9 +1,9 @@ module("_boot.py", opt=3) -module("apa102.py", base_path="$(PORT_DIR)/modules", opt=3) -module("port_diag.py", base_path="$(PORT_DIR)/modules", opt=3) -require("ntptime") -require("dht") -require("onewire") -require("ds18x20") -require("webrepl") -require("neopixel") +# module("apa102.py", base_path="$(PORT_DIR)/modules", opt=3) +# module("port_diag.py", base_path="$(PORT_DIR)/modules", opt=3) +# require("ntptime") +# require("dht") +# require("onewire") +# require("ds18x20") +# require("webrepl") +# require("neopixel") diff --git a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h index 1f679961e8786..1c564f52fb3ca 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h +++ b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h @@ -3,15 +3,11 @@ #define MICROPY_HW_BOARD_NAME "ESP module" #define MICROPY_HW_MCU_NAME "ESP8266" -#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_XTENSA (1) #define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) -#define MICROPY_READER_VFS (MICROPY_VFS) -#define MICROPY_VFS (1) - #define MICROPY_PY_CRYPTOLIB (1) #elif defined(MICROPY_ESP8266_1M) @@ -19,16 +15,11 @@ #define MICROPY_HW_BOARD_NAME "ESP module (1M)" #define MICROPY_HW_MCU_NAME "ESP8266" -#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_XTENSA (1) #define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) -#define MICROPY_READER_VFS (MICROPY_VFS) -#define MICROPY_VFS (1) - - #define MICROPY_PY_CRYPTOLIB (1) #elif defined(MICROPY_ESP8266_512K) @@ -46,5 +37,18 @@ #define MICROPY_PY_ASYNCIO (0) #define MICROPY_PY_RE_SUB (0) #define MICROPY_PY_FRAMEBUF (0) +#define MICROPY_PY_HEAPQ (0) + +#define MICROPY_VFS_WRITABLE (0) + +#define MICROPY_PY_ESP_FLASH_FUNCS (0) +#define MICROPY_PY_ESP_EXTRA_FUNCS (0) #endif + +// Configuration common to all variants. + +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_VFS (1) +#define MICROPY_VFS_ROM (1) diff --git a/ports/esp8266/boards/esp8266_1MiB.ld b/ports/esp8266/boards/esp8266_1MiB.ld index 94bc6a229a75b..678013940acdf 100644 --- a/ports/esp8266/boards/esp8266_1MiB.ld +++ b/ports/esp8266/boards/esp8266_1MiB.ld @@ -2,7 +2,8 @@ Flash layout: 0x40200000 36k header + iram/dram init - 0x40209000 572k firmware (irom0) + 0x40209000 556k firmware (irom0) + 0x40294000 16k ROMFS 0x40298000 396k filesystem 0x402fb000 20k SDK parameters */ @@ -12,7 +13,8 @@ MEMORY dport0_0_seg : org = 0x3ff00000, len = 16 dram0_0_seg : org = 0x3ffe8000, len = 80K iram1_0_seg : org = 0x40100000, len = 32K - irom0_0_seg : org = 0x40209000, len = 572K + irom0_0_seg : org = 0x40209000, len = 556K + FLASH_ROMFS : org = 0x40294000, len = 16K } /* define common sections and symbols */ diff --git a/ports/esp8266/boards/esp8266_2MiB.ld b/ports/esp8266/boards/esp8266_2MiB.ld index b5813ce0fb7a4..76cb22de14e37 100644 --- a/ports/esp8266/boards/esp8266_2MiB.ld +++ b/ports/esp8266/boards/esp8266_2MiB.ld @@ -2,7 +2,8 @@ Flash layout: 0x40200000 36k header + iram/dram init - 0x40209000 988k firmware (irom0) + 0x40209000 732k firmware (irom0) + 0x402c0000 256k ROMFS 0x40300000 1M+ filesystem (not memory mapped) */ @@ -11,7 +12,8 @@ MEMORY dport0_0_seg : org = 0x3ff00000, len = 16 dram0_0_seg : org = 0x3ffe8000, len = 80K iram1_0_seg : org = 0x40100000, len = 32K - irom0_0_seg : org = 0x40209000, len = 1M - 36K + irom0_0_seg : org = 0x40209000, len = 1M - 36K - 256K + FLASH_ROMFS : org = 0x402c0000, len = 256K } /* define common sections and symbols */ diff --git a/ports/esp8266/boards/esp8266_512kiB.ld b/ports/esp8266/boards/esp8266_512kiB.ld index c4cc798499df0..24a33fe031c70 100644 --- a/ports/esp8266/boards/esp8266_512kiB.ld +++ b/ports/esp8266/boards/esp8266_512kiB.ld @@ -2,7 +2,8 @@ Flash layout: 0x40200000 36k header + iram/dram init - 0x40209000 456k firmware (irom0) + 0x40209000 448k firmware (irom0) + 0x40279000 8k ROMFS 0x4027b000 20k SDK parameters */ @@ -11,7 +12,8 @@ MEMORY dport0_0_seg : org = 0x3ff00000, len = 16 dram0_0_seg : org = 0x3ffe8000, len = 80K iram1_0_seg : org = 0x40100000, len = 32K - irom0_0_seg : org = 0x40209000, len = 512K - 36K - 20K + irom0_0_seg : org = 0x40209000, len = 512K - 36K - 20K - 8K + FLASH_ROMFS : org = 0x4027a000, len = 8K } /* define common sections and symbols */ diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld index cf4883acc9d20..4c4970045902c 100644 --- a/ports/esp8266/boards/esp8266_common.ld +++ b/ports/esp8266/boards/esp8266_common.ld @@ -3,6 +3,10 @@ /* define the top of RAM */ _heap_end = ORIGIN(dram0_0_seg) + LENGTH(dram0_0_seg); +/* define ROMFS extents */ +_micropy_hw_romfs_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_size = LENGTH(FLASH_ROMFS); + PHDRS { dport0_0_phdr PT_LOAD; diff --git a/ports/esp8266/boards/esp8266_ota.ld b/ports/esp8266/boards/esp8266_ota.ld index 7fdf6abef00e3..c5ea2d58fa1a7 100644 --- a/ports/esp8266/boards/esp8266_ota.ld +++ b/ports/esp8266/boards/esp8266_ota.ld @@ -6,7 +6,8 @@ MEMORY dram0_0_seg : org = 0x3ffe8000, len = 0x14000 iram1_0_seg : org = 0x40100000, len = 0x8000 /* 0x3c000 is size of bootloader, 0x9000 is size of packed RAM segments */ - irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000 + irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000 - 8K + FLASH_ROMFS : org = 0x402d2000, len = 8K } /* define common sections and symbols */ diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index f303da1a33289..d35b17532f100 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -164,9 +164,10 @@ static MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); #define IS_OTA_FIRMWARE() ((*(uint32_t *)0x40200000 & 0xff00) == 0x100) extern byte _firmware_size[]; +extern uint8_t _micropy_hw_romfs_size; static mp_obj_t esp_flash_user_start(void) { - return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size); + return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size + (uint32_t)&_micropy_hw_romfs_size); } static MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); @@ -345,21 +346,25 @@ static const mp_rom_map_elem_t esp_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep_type), MP_ROM_PTR(&esp_sleep_type_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&esp_deepsleep_obj) }, + #if MICROPY_PY_ESP_FLASH_FUNCS { MP_ROM_QSTR(MP_QSTR_flash_id), MP_ROM_PTR(&esp_flash_id_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) }, + #endif #if MICROPY_ESP8266_APA102 { MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) }, #endif + #if MICROPY_PY_ESP_EXTRA_FUNCS { MP_ROM_QSTR(MP_QSTR_freemem), MP_ROM_PTR(&esp_freemem_obj) }, { MP_ROM_QSTR(MP_QSTR_meminfo), MP_ROM_PTR(&esp_meminfo_obj) }, { MP_ROM_QSTR(MP_QSTR_check_fw), MP_ROM_PTR(&esp_check_fw_obj) }, { MP_ROM_QSTR(MP_QSTR_malloc), MP_ROM_PTR(&esp_malloc_obj) }, { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&esp_free_obj) }, { MP_ROM_QSTR(MP_QSTR_esf_free_bufs), MP_ROM_PTR(&esp_esf_free_bufs_obj) }, + #endif #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA { MP_ROM_QSTR(MP_QSTR_set_native_code_location), MP_ROM_PTR(&esp_set_native_code_location_obj) }, #endif @@ -379,3 +384,66 @@ const mp_obj_module_t esp_module = { }; MP_REGISTER_MODULE(MP_QSTR_esp, esp_module); + +///// + +#if MICROPY_VFS_ROM + +#include "py/objarray.h" +#include "extmod/vfs.h" + +#define FLASH_MEM_BASE (0x40200000) +#define FLASH_PAGE_SIZE (4096) + +#define MICROPY_HW_ROMFS_BASE (uintptr_t)(&_micropy_hw_romfs_start) +#define MICROPY_HW_ROMFS_BYTES (uintptr_t)(&_micropy_hw_romfs_size) + +#define ROMFS_SPI_FLASH_OFFSET (MICROPY_HW_ROMFS_BASE - FLASH_MEM_BASE) + +extern uint8_t _micropy_hw_romfs_start; +extern uint8_t _micropy_hw_romfs_size; + +static const MP_DEFINE_MEMORYVIEW_OBJ(romfs_obj, 'B', 0, MICROPY_HW_ROMFS_BYTES, (void *)MICROPY_HW_ROMFS_BASE); + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&romfs_obj); + + case MP_VFS_ROM_IOCTL_WRITE_PREPARE: { + uint32_t dest = ROMFS_SPI_FLASH_OFFSET; + uint32_t dest_max = dest + mp_obj_get_int(args[2]); + while (dest < dest_max) { + ets_loop_iter(); // flash access takes time so run any pending tasks + SpiFlashOpResult res = spi_flash_erase_sector(dest / FLASH_PAGE_SIZE); + ets_loop_iter(); + if (res != SPI_FLASH_RESULT_OK) { + return MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? -MP_ETIMEDOUT : -MP_EIO); + } + dest += FLASH_PAGE_SIZE; + } + return MP_OBJ_NEW_SMALL_INT(4); // minimum write size + } + + case MP_VFS_ROM_IOCTL_WRITE: { + mp_int_t offset = ROMFS_SPI_FLASH_OFFSET + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + ets_loop_iter(); // flash access takes time so run any pending tasks + SpiFlashOpResult res = spi_flash_write(offset, bufinfo.buf, (bufinfo.len + 3) & ~3); + ets_loop_iter(); + if (res == SPI_FLASH_RESULT_OK) { + return MP_OBJ_NEW_SMALL_INT(0); + } + return MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? -MP_ETIMEDOUT : -MP_EIO); + } + + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM diff --git a/ports/esp8266/modules/_boot.py b/ports/esp8266/modules/_boot.py index 00a0d6550f945..570dd3139e99f 100644 --- a/ports/esp8266/modules/_boot.py +++ b/ports/esp8266/modules/_boot.py @@ -1,9 +1,17 @@ import gc gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) -import vfs + +import sys, vfs from flashbdev import bdev +# Try to mount the ROMFS. +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass + if bdev: try: vfs.mount(bdev, "/") diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 83d80a7c963f6..e88986b16b55b 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -111,6 +111,14 @@ #define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32 +#ifndef MICROPY_PY_ESP_FLASH_FUNCS +#define MICROPY_PY_ESP_FLASH_FUNCS (1) +#endif + +#ifndef MICROPY_PY_ESP_EXTRA_FUNCS +#define MICROPY_PY_ESP_EXTRA_FUNCS (1) +#endif + #define MICROPY_FATFS_ENABLE_LFN (1) #define MICROPY_FATFS_RPATH (2) #define MICROPY_FATFS_MAX_SS (4096) diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 8106ab4f3ff03..e3a942e22124f 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -267,6 +267,11 @@ ifeq ($(USE_UF2_BOOTLOADER),1) CFLAGS += -DMICROPY_MACHINE_UF2_BOOTLOADER=1 endif +# Set the default size of the VfsRom file system. Can be changed at board level +ifeq ($(MICROPY_HW_ROMFS_BYTES),) + MICROPY_HW_ROMFS_BYTES ?= 0x40000 +endif + # Add sources for respective board flash type # Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively SRC_HAL_C += hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).c @@ -450,9 +455,10 @@ LDFLAGS += \ # LDDEFINES are used for link time adaptation of linker scripts, utilizing # the C preprocessor. Therefore keep LDDEFINES separated from LDFLAGS! -LDDEFINES = \ +LDDEFINES += \ -DMICROPY_HW_FLASH_BASE=$(MICROPY_HW_FLASH_BASE) \ - -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DMICROPY_HW_ROMFS_BYTES=$(MICROPY_HW_ROMFS_BYTES) ifdef MICROPY_HW_FLASH_RESERVED LDDEFINES += -DMICROPY_HW_FLASH_RESERVED=$(MICROPY_HW_FLASH_RESERVED) diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld index 0e961a49433f2..b5c5464dd7a65 100644 --- a/ports/mimxrt/boards/MIMXRT1011.ld +++ b/ports/mimxrt/boards/MIMXRT1011.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1015.ld b/ports/mimxrt/boards/MIMXRT1015.ld index 58b88e0fe3084..64ca7bfd3f2fc 100644 --- a/ports/mimxrt/boards/MIMXRT1015.ld +++ b/ports/mimxrt/boards/MIMXRT1015.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00008000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld index 78add04c0c26c..7b032788aa8ee 100644 --- a/ports/mimxrt/boards/MIMXRT1021.ld +++ b/ports/mimxrt/boards/MIMXRT1021.ld @@ -18,8 +18,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00010000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld index ea034d713e2f6..d1b4d556eba61 100644 --- a/ports/mimxrt/boards/MIMXRT1052.ld +++ b/ports/mimxrt/boards/MIMXRT1052.ld @@ -20,8 +20,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00200000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld index 3d7e6d0634196..d5da419f7e309 100644 --- a/ports/mimxrt/boards/MIMXRT1062.ld +++ b/ports/mimxrt/boards/MIMXRT1062.ld @@ -20,8 +20,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld index 7c35cb60c750b..a8215bc3bf5c0 100644 --- a/ports/mimxrt/boards/MIMXRT1064.ld +++ b/ports/mimxrt/boards/MIMXRT1064.ld @@ -14,8 +14,10 @@ interrupts_start = flash_start + 0x0000C000; interrupts_size = 0x00000400; text_start = flash_start + 0x0000C400; vfs_start = flash_start + 0x00100000; -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/boards/MIMXRT1176.ld b/ports/mimxrt/boards/MIMXRT1176.ld index 4d114ef96fa4a..11664a752f041 100644 --- a/ports/mimxrt/boards/MIMXRT1176.ld +++ b/ports/mimxrt/boards/MIMXRT1176.ld @@ -30,8 +30,10 @@ m_core1_image_start = vfs_start - 0x00040000; m_core1_image_size = 0x00040000; #endif -text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); +vfsrom_start = ((vfs_start) - MICROPY_HW_ROMFS_BYTES); +vfsrom_end = ((vfsrom_start) + MICROPY_HW_ROMFS_BYTES); +text_size = ((vfsrom_start) - (text_start)); itcm_start = 0x00000000; itcm_size = 0x00020000; dtcm_start = 0x20000000; diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c index fdd48e280bc15..09ce2a4fbd898 100644 --- a/ports/mimxrt/mimxrt_flash.c +++ b/ports/mimxrt/mimxrt_flash.c @@ -5,6 +5,7 @@ * * Copyright (c) 2020-2021 Damien P. George * Copyright (c) 2021-2023 Philipp Ebensberger + * Copyright (c) 2021-2024 Robert Hammelrath * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +30,7 @@ #include "py/runtime.h" #include "extmod/vfs.h" +#include "py/mperrno.h" #include "modmimxrt.h" #include "flash.h" #include BOARD_FLASH_OPS_HEADER_H @@ -60,6 +62,19 @@ static mp_obj_t mimxrt_flash_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(&mimxrt_flash_obj); } +static mp_int_t mimxrt_flash_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mimxrt_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)((uintptr_t)&__flash_start + self->flash_base); + bufinfo->len = self->flash_size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Write unsupported. + return 1; + } +} + // readblocks(block_num, buf, [offset]) // read size of buffer number of bytes from block (with offset) into buffer static mp_obj_t mimxrt_flash_readblocks(size_t n_args, const mp_obj_t *args) { @@ -151,5 +166,39 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, mimxrt_flash_make_new, + buffer, mimxrt_flash_get_buffer, locals_dict, &mimxrt_flash_locals_dict ); + +#if MICROPY_VFS_ROM + +extern uint8_t vfsrom_start; +extern uint8_t vfsrom_end; + +// Put VfsRom file system between the code space and the VFS file system. +// The size is defined in Makefile(s) as linker symbol MICROPY_HW_ROMFS_BYTES. +// For machine.mem32 the absolute address is required, for the flash functions +// erase and write the offset to the flash start address. +#define MICROPY_HW_ROMFS_BASE ((uintptr_t)&vfsrom_start - (uintptr_t)&__flash_start) +#define MICROPY_HW_ROMFS_BYTES ((uintptr_t)&vfsrom_end - (uintptr_t)&vfsrom_start) + +static mimxrt_flash_obj_t mimxrt_flash_romfs_obj = { + .base = { &mimxrt_flash_type }, +}; + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + mimxrt_flash_romfs_obj.flash_base = MICROPY_HW_ROMFS_BASE; + mimxrt_flash_romfs_obj.flash_size = MICROPY_HW_ROMFS_BYTES; + return MP_OBJ_FROM_PTR(&mimxrt_flash_romfs_obj); + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} +#endif // MICROPY_VFS_ROM diff --git a/ports/mimxrt/modules/_boot.py b/ports/mimxrt/modules/_boot.py index fa3b780434a43..b658bf3b9e80f 100644 --- a/ports/mimxrt/modules/_boot.py +++ b/ports/mimxrt/modules/_boot.py @@ -8,6 +8,12 @@ import mimxrt from machine import Pin +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass + bdev = mimxrt.Flash() try: fs = vfs.VfsLfs2(bdev, progsize=256) diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 7da85f1aee579..4a4a184fde7ca 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -59,6 +59,9 @@ uint32_t trng_random_u32(void); #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif // Control over Python builtins #define MICROPY_PY_BUILTINS_HELP_TEXT mimxrt_help_text diff --git a/ports/nrf/boards/memory.ld b/ports/nrf/boards/memory.ld index 9c4c9c8bd1267..fac072516158f 100644 --- a/ports/nrf/boards/memory.ld +++ b/ports/nrf/boards/memory.ld @@ -8,10 +8,12 @@ _head_size = DEFINED(_sd_size) ? _sd_size : _bootloader_head_size; _head_ram = DEFINED(_sd_ram) ? _sd_ram : _bootloader_head_ram_size; _sd_size = DEFINED(_sd_size) ? _sd_size : 0; _sd_ram = DEFINED(_sd_ram) ? _sd_ram : 0; +_vfsrom_size = DEFINED(_vfsrom_size) ? _vfsrom_size : 0; _fs_size = DEFINED(_fs_size) ? _fs_size : 64K; /* TODO: set to 0 if not using the filesystem */ -_app_size = _flash_size - _head_size - _fs_size - _bootloader_tail_size; +_app_size = _flash_size - _head_size - _vfsrom_size - _fs_size - _bootloader_tail_size; _app_start = _head_size; -_fs_start = _head_size + _app_size; +_vfsrom_start = _head_size + _app_size; +_fs_start = _vfsrom_start + _vfsrom_size; _fs_end = _fs_start + _fs_size; _app_ram_start = 0x20000000 + _head_ram; _app_ram_size = _ram_size - _head_ram; diff --git a/ports/nrf/boards/nrf51x22_256k_16k.ld b/ports/nrf/boards/nrf51x22_256k_16k.ld index 8a40ae0f17307..7fd978a358f4c 100644 --- a/ports/nrf/boards/nrf51x22_256k_16k.ld +++ b/ports/nrf/boards/nrf51x22_256k_16k.ld @@ -6,6 +6,7 @@ GROUP(-lgcc -lc -lnosys) _flash_size = 256K; _ram_size = 16K; +_vfsrom_size = 12K; /* Default stack size when there is no SoftDevice */ _stack_size = 4K; diff --git a/ports/nrf/boards/nrf51x22_256k_32k.ld b/ports/nrf/boards/nrf51x22_256k_32k.ld index 06c0914035b4a..e7940e2097c9e 100644 --- a/ports/nrf/boards/nrf51x22_256k_32k.ld +++ b/ports/nrf/boards/nrf51x22_256k_32k.ld @@ -6,6 +6,7 @@ GROUP(-lgcc -lc -lnosys) _flash_size = 256K; _ram_size = 32K; +_vfsrom_size = 12K; /* Default stack size when there is no SoftDevice */ _stack_size = 4K; diff --git a/ports/nrf/boards/nrf52832_512k_64k.ld b/ports/nrf/boards/nrf52832_512k_64k.ld index 22804df5cdb5e..dead8f345c6d0 100644 --- a/ports/nrf/boards/nrf52832_512k_64k.ld +++ b/ports/nrf/boards/nrf52832_512k_64k.ld @@ -4,6 +4,7 @@ _flash_size = 512K; _ram_size = 64K; +_vfsrom_size = 128K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 8K; diff --git a/ports/nrf/boards/nrf52840_1M_256k.ld b/ports/nrf/boards/nrf52840_1M_256k.ld index 16d61af6a30b9..2670b88f50d4d 100644 --- a/ports/nrf/boards/nrf52840_1M_256k.ld +++ b/ports/nrf/boards/nrf52840_1M_256k.ld @@ -4,6 +4,7 @@ _flash_size = 1M; _ram_size = 256K; +_vfsrom_size = 128K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 8K; diff --git a/ports/nrf/boards/nrf9160_1M_256k.ld b/ports/nrf/boards/nrf9160_1M_256k.ld index 6347095a899ce..467a0325e25d5 100644 --- a/ports/nrf/boards/nrf9160_1M_256k.ld +++ b/ports/nrf/boards/nrf9160_1M_256k.ld @@ -7,6 +7,7 @@ _ram_size = 256K; _sd_size = 0x00008000; _sd_ram = 0x00020000; _fs_size = 80K; +_vfsrom_size = 128K; /* produce a link error if there is not this amount of RAM for these sections */ _stack_size = 32K; diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 29550bd77a748..17dbe19dfda5d 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -179,22 +179,8 @@ void NORETURN _start(void) { #if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE flashbdev_init(); - - // Try to mount the flash on "/flash" and chdir to it for the boot-up directory. - mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash); - int ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); - - if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) { - pyexec_frozen_module("_mkfs.py", false); // Frozen script for formatting flash filesystem. - ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); - } - - if (ret != 0) { - printf("MPY: can't mount flash\n"); - } else { - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash)); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); - } + // Execute _boot.py to set up the filesystem. + pyexec_frozen_module("_boot.py", false); #endif #if MICROPY_MBFS diff --git a/ports/nrf/modules/manifest.py b/ports/nrf/modules/manifest.py index 7ba0f80d884d0..631ad19a8db8a 100644 --- a/ports/nrf/modules/manifest.py +++ b/ports/nrf/modules/manifest.py @@ -1,2 +1,2 @@ -module("_mkfs.py", base_path="$(PORT_DIR)/modules/scripts", opt=3) +module("_boot.py", base_path="$(PORT_DIR)/modules/scripts", opt=3) include("$(MPY_DIR)/extmod/asyncio") diff --git a/ports/nrf/modules/nrf/flashbdev.c b/ports/nrf/modules/nrf/flashbdev.c index e490dc53dd677..feacca8746486 100644 --- a/ports/nrf/modules/nrf/flashbdev.c +++ b/ports/nrf/modules/nrf/flashbdev.c @@ -183,12 +183,26 @@ static mp_obj_t nrf_flashbdev_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } +static mp_int_t nrf_flashbdev_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + nrf_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)self->start; + bufinfo->len = self->len; + bufinfo->typecode = 'B'; + return 0; + } else { + // Unsupported. + return 1; + } +} + MP_DEFINE_CONST_OBJ_TYPE( nrf_flashbdev_type, MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, nrf_flashbdev_make_new, print, nrf_flashbdev_print, + buffer, nrf_flashbdev_get_buffer, locals_dict, &nrf_flashbdev_locals_dict ); @@ -202,4 +216,34 @@ void flashbdev_init(void) { nrf_flash_obj.len = num_pages * FLASH_PAGESIZE; } +#if MICROPY_VFS_ROM + +extern byte _vfsrom_start[]; +extern byte _vfsrom_size[]; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)_vfsrom_start) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)_vfsrom_size) + +static nrf_flash_obj_t nrf_flash_romfs_obj = { + .base = { &nrf_flashbdev_type }, + .start = MICROPY_HW_ROMFS_BASE, // Get from MCU-Specific loader script. + .len = MICROPY_HW_ROMFS_BYTES, // Get from MCU-Specific loader script. +}; + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&nrf_flash_romfs_obj); + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM + #endif // MICROPY_PY_NRF && MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/nrf/modules/scripts/_boot.py b/ports/nrf/modules/scripts/_boot.py new file mode 100644 index 0000000000000..00cde657dbc9f --- /dev/null +++ b/ports/nrf/modules/scripts/_boot.py @@ -0,0 +1,37 @@ +import gc +import vfs +import sys +import nrf +import os + +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass + +try: + bdev = nrf.Flash() + fs_type = ( + vfs.VfsLfs2 + if hasattr(vfs, "VfsLfs2") + else (vfs.VfsLfs1 if hasattr(vfs, "VfsLfs1") else vfs.VfsFat) + ) + vfs.mount(fs_type(bdev), "/flash") +except AttributeError: + fs_type = None +except: + try: + fs_type.mkfs(bdev) + vfs.mount(fs_type(bdev), "/flash") + except: + pass + +if fs_type is not None: + os.chdir("/flash") + sys.path.append("/flash") + sys.path.append("/flash/lib") + +del os, nrf, vfs, sys, bdev, fs_type +gc.collect() +del gc diff --git a/ports/nrf/modules/scripts/_mkfs.py b/ports/nrf/modules/scripts/_mkfs.py deleted file mode 100644 index 601f9558eb7b5..0000000000000 --- a/ports/nrf/modules/scripts/_mkfs.py +++ /dev/null @@ -1,23 +0,0 @@ -import vfs, nrf - -try: - from vfs import VfsLfs1 - - vfs.VfsLfs1.mkfs(nrf.Flash()) -except ImportError: - try: - from vfs import VfsLfs2 - - vfs.VfsLfs2.mkfs(nrf.Flash()) - except ImportError: - try: - from vfs import VfsFat - - vfs.VfsFat.mkfs(nrf.Flash()) - except ImportError: - pass - except OSError as e: - if e.args[0] == 5: # I/O Error - flashbdev_size = (nrf.Flash.ioctl(4, 0) * nrf.Flash.ioctl(5, 0)) // 1024 - print() - print("Is `FS_SIZE=%iK` enough for FAT filesystem?" % flashbdev_size) diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 7cc8a66d9840c..7d06fe1bd79a6 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -69,6 +69,11 @@ #define MICROPY_VFS (CORE_FEAT) #endif +// VfsROM filesystem +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (CORE_FEAT) +#endif + // micro:bit filesystem #ifndef MICROPY_MBFS #define MICROPY_MBFS (!MICROPY_VFS) diff --git a/ports/qemu/main.c b/ports/qemu/main.c index 75c6fe4cdc0d8..bcb62d51dd057 100644 --- a/ports/qemu/main.c +++ b/ports/qemu/main.c @@ -77,3 +77,7 @@ void nlr_jump_fail(void *val) { mp_printf(&mp_plat_print, "uncaught NLR\n"); exit(1); } + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); +} diff --git a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld index c1fac5106c37e..3b5be1642ec6c 100644 --- a/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld +++ b/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/ra6m5.ld @@ -6,7 +6,8 @@ MEMORY { FLASH_BOOT (r) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64K */ - FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x000f0000 /* 960KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000C0000 /* 768KB/2MB */ + VFSROM_FS (r) : ORIGIN = 0x000D0000, LENGTH = 0x00030000 /* 192KB/2MB */ FLASH_FS (r) : ORIGIN = 0x00100000, LENGTH = 0x00100000 /* 1MB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 /* 512KB */ OSPI_RAM (rwx) : ORIGIN = 0x68000000, LENGTH = 0x00800000 /* 8MB/8MB */ @@ -304,3 +305,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld b/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld index 52f8acf93eb33..e1c1c5b796a61 100644 --- a/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA4M1/ra4m1_ek.ld @@ -3,9 +3,14 @@ */ /* Linker script to configure memory regions. */ +/* + * VFSROM_FS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (2k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00037000 /* 220KB/256KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00034000 /* 208KB/256KB */ + VFSROM_FS (r) : ORIGIN = 0x00034000, LENGTH = 0x00003000 /* 12KB/256KB */ FLASH_FS (r) : ORIGIN = 0x00037000, LENGTH = 0x00009000 /* 36KB/256KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 /* 32KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +305,5 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/EK_RA4W1/mpconfigboard.h b/ports/renesas-ra/boards/EK_RA4W1/mpconfigboard.h index 9eda05f0fdd1b..19477f9df9c3e 100644 --- a/ports/renesas-ra/boards/EK_RA4W1/mpconfigboard.h +++ b/ports/renesas-ra/boards/EK_RA4W1/mpconfigboard.h @@ -67,3 +67,5 @@ #define MICROPY_HW_LED_ON(pin) mp_hal_pin_low(pin) #define MICROPY_HW_LED_OFF(pin) mp_hal_pin_high(pin) #define MICROPY_HW_LED_TOGGLE(pin) mp_hal_pin_toggle(pin) + +#define MICROPY_VFS_ROM (1) diff --git a/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld b/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld index 1241b5bc2302b..bdc90d545876d 100644 --- a/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA4W1/ra4w1_ek.ld @@ -3,9 +3,14 @@ */ /* Linker script to configure memory regions. */ +/* + * VFSROM_FS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (2k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00070000 /* 448KB/512KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00060000 /* 384KB/512KB */ + VFSROM_FS (r) : ORIGIN = 0x00060000, LENGTH = 0x00010000 /* 64KB/512KB */ FLASH_FS (r) : ORIGIN = 0x00070000, LENGTH = 0x00010000 /* 64KB/512KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00018000 /* 96KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +305,5 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld b/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld index c7d85ed3db0a1..c10cdfcbb22f9 100644 --- a/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld +++ b/ports/renesas-ra/boards/EK_RA6M1/ra6m1_ek.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00070000 /* 448KB/512KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00060000 /* 384KB/512KB */ + VFSROM_FS (r) : ORIGIN = 0x00060000, LENGTH = 0x00010000 /* 64KB/512KB */ FLASH_FS (r) : ORIGIN = 0x00070000, LENGTH = 0x00010000 /* 64KB/512KB */ RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00040000 /* 256KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +301,5 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld b/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld index 086f6630c110a..346ef827fc71d 100644 --- a/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld +++ b/ports/renesas-ra/boards/EK_RA6M2/ra6m2_ek.ld @@ -3,9 +3,15 @@ */ /* Linker script to configure memory regions. */ + +/* + * VFSROM_FS and FLASH_FS must start and length must be a multiple + * of the physical sector size of that region (32k). + */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000e0000 /* 896KB/1MB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000e0000 /* 768KB/1MB */ + VFSROM_FS (r) : ORIGIN = 0x000c0000, LENGTH = 0x00020000 /* 128KB/1MB */ FLASH_FS (r) : ORIGIN = 0x000e0000, LENGTH = 0x00020000 /* 128KB/1MB */ RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00060000 /* 384KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00008000 /* 32KB */ @@ -300,3 +306,6 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld b/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld index 52f8acf93eb33..6667a7153387a 100644 --- a/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld +++ b/ports/renesas-ra/boards/RA4M1_CLICKER/ra4m1_clicker.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00037000 /* 220KB/256KB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00034000 /* 208KB/256KB */ + VFSROM_FS (r) : ORIGIN = 0x00034000, LENGTH = 0x00003000 /* 12KB/256KB */ FLASH_FS (r) : ORIGIN = 0x00037000, LENGTH = 0x00009000 /* 36KB/256KB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 /* 32KB */ DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x00002000 /* 8KB */ @@ -300,3 +301,5 @@ _heap_end = __HeapLimit; /* tunable */ _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld b/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld index 8363d2e743f24..42fa6682a884e 100644 --- a/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld +++ b/ports/renesas-ra/boards/VK_RA6M5/vk_ra6m5.ld @@ -5,7 +5,8 @@ /* Linker script to configure memory regions. */ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000 /* 1MB/2MB */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x000C0000 /* 768KB/2MB */ + VFSROM_FS (r) : ORIGIN = 0x000C0000, LENGTH = 0x00040000 /* 256KB/2MB */ FLASH_FS (r) : ORIGIN = 0x00100000, LENGTH = 0x00100000 /* 1MB/2MB */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 /* 512KB */ OSPI_RAM (rwx) : ORIGIN = 0x68000000, LENGTH = 0x00800000 /* 8MB/8MB */ @@ -306,3 +307,6 @@ _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); _micropy_hw_external_flash_storage_start = ORIGIN(QSPI_FLASH); _micropy_hw_external_flash_storage_end = ORIGIN(QSPI_FLASH) + LENGTH(QSPI_FLASH); + +_micropy_hw_vfsrom_storage_start = ORIGIN(VFSROM_FS); +_micropy_hw_vfsrom_storage_len = LENGTH(VFSROM_FS); diff --git a/ports/renesas-ra/build_all_boards.sh b/ports/renesas-ra/build_all_boards.sh deleted file mode 100644 index 0c192dba93103..0000000000000 --- a/ports/renesas-ra/build_all_boards.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set -eu -o pipefail -export BOARD="RA4M1_CLICKER" -DT=`date +%Y%m%d%H%M` -make DEBUG=0 BOARD=${BOARD} clean 2>&1 | tee ${BOARD}_build_${DT}.log -make DEBUG=0 BOARD=${BOARD} 2>&1 | tee -a ${BOARD}_build_${DT}.log -# -export BOARD="EK_RA6M2" -DT=`date +%Y%m%d%H%M` -make DEBUG=1 BOARD=${BOARD} clean 2>&1 | tee ${BOARD}_build_${DT}.log -make DEBUG=1 BOARD=${BOARD} 2>&1 | tee -a ${BOARD}_build_${DT}.log -# -export BOARD="EK_RA4M1" -DT=`date +%Y%m%d%H%M` -make DEBUG=0 BOARD=${BOARD} clean 2>&1 | tee ${BOARD}_build_${DT}.log -make DEBUG=0 BOARD=${BOARD} 2>&1 | tee -a ${BOARD}_build_${DT}.log -# -export BOARD="EK_RA4W1" -DT=`date +%Y%m%d%H%M` -make DEBUG=0 BOARD=${BOARD} clean 2>&1 | tee ${BOARD}_build_${DT}.log -make DEBUG=0 BOARD=${BOARD} 2>&1 | tee -a ${BOARD}_build_${DT}.log -# -export BOARD="EK_RA6M1" -DT=`date +%Y%m%d%H%M` -make DEBUG=1 BOARD=${BOARD} clean 2>&1 | tee ${BOARD}_build_${DT}.log -make DEBUG=1 BOARD=${BOARD} 2>&1 | tee -a ${BOARD}_build_${DT}.log diff --git a/ports/renesas-ra/mpconfigboard_common.h b/ports/renesas-ra/mpconfigboard_common.h index 479c9f61d1a68..2bd0eab5611e3 100644 --- a/ports/renesas-ra/mpconfigboard_common.h +++ b/ports/renesas-ra/mpconfigboard_common.h @@ -154,6 +154,10 @@ #define MICROPY_HW_UART_IS_RESERVED(uart_id) (false) #endif +// Whether to support the VFSROM file system +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif /*****************************************************************************/ // General configuration diff --git a/ports/renesas-ra/storage.c b/ports/renesas-ra/storage.c index 12416e4dc7a9f..57ffd957f8d16 100644 --- a/ports/renesas-ra/storage.c +++ b/ports/renesas-ra/storage.c @@ -28,6 +28,7 @@ #include #include +#include "py/objarray.h" #include "py/runtime.h" #include "py/mperrno.h" #include "extmod/vfs_fat.h" @@ -36,6 +37,13 @@ #include "led.h" #include "storage.h" #include "irq.h" +#include "flash.h" + +typedef struct _pyb_flash_obj_t { + mp_obj_base_t base; + uint32_t start; // in bytes + uint32_t len; // in bytes +} pyb_flash_obj_t; #if MICROPY_HW_ENABLE_STORAGE @@ -236,12 +244,6 @@ int storage_readblocks_ext(uint8_t *dest, uint32_t block, uint32_t offset, uint3 } #endif -typedef struct _pyb_flash_obj_t { - mp_obj_base_t base; - uint32_t start; // in bytes - uint32_t len; // in bytes -} pyb_flash_obj_t; - // This Flash object represents the entire available flash, with emulated partition table at start const pyb_flash_obj_t pyb_flash_obj = { { &pyb_flash_type }, @@ -427,3 +429,57 @@ void pyb_flash_init_vfs(fs_user_mount_t *vfs) { } #endif + +#if MICROPY_VFS_ROM + +extern uint32_t _micropy_hw_vfsrom_storage_start, _micropy_hw_vfsrom_storage_len; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)&_micropy_hw_vfsrom_storage_start) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)&_micropy_hw_vfsrom_storage_len) +#define VFSROM_BLOCK_SIZE (2048) + +static const MP_DEFINE_MEMORYVIEW_OBJ(romfs_obj, 'B', 0, MICROPY_HW_ROMFS_BYTES, (void *)MICROPY_HW_ROMFS_BASE); + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&romfs_obj); + + case MP_VFS_ROM_IOCTL_WRITE_PREPARE: { + // Erase sectors in given range. + if (n_args < 3) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = MICROPY_HW_ROMFS_BASE; + uint32_t dest_max = dest + mp_obj_get_int(args[2]); + uint32_t sec_size = sector_size(dest); + for (; dest < dest_max; dest += sec_size) { + flash_erase(dest, sec_size); + } + return MP_OBJ_NEW_SMALL_INT(4); // minimum write size + } + + case MP_VFS_ROM_IOCTL_WRITE: { + // Write data to flash. + if (n_args < 4) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = MICROPY_HW_ROMFS_BASE + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + flash_write(dest, bufinfo.buf, bufinfo.len); + return MP_OBJ_NEW_SMALL_INT(0); + } + + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} + +#endif // MICROPY_VFS_ROM diff --git a/ports/rp2/modules/_boot.py b/ports/rp2/modules/_boot.py index 71cb28d6823bb..772287078806c 100644 --- a/ports/rp2/modules/_boot.py +++ b/ports/rp2/modules/_boot.py @@ -1,6 +1,13 @@ import vfs +import sys import machine, rp2 +# Try to mount the ROMFS. +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass # Try to mount the filesystem, and format the flash if it doesn't exist. # Note: the flash requires the programming size to be aligned to 256 bytes. @@ -12,4 +19,4 @@ fs = vfs.VfsLfs2(bdev, progsize=256) vfs.mount(fs, "/") -del vfs, bdev, fs +del vfs, sys, bdev, fs diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index fe8287ba1d6e5..435e0a7ca14d7 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -170,6 +170,7 @@ #define MICROPY_VFS (1) #define MICROPY_VFS_LFS2 (1) #define MICROPY_VFS_FAT (1) +#define MICROPY_VFS_ROM (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_LWIP_PPP (MICROPY_PY_NETWORK_PPP_LWIP) #define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) diff --git a/ports/rp2/rp2_flash.c b/ports/rp2/rp2_flash.c index a487fb1633b21..a2a320bad41e0 100644 --- a/ports/rp2/rp2_flash.c +++ b/ports/rp2/rp2_flash.c @@ -28,6 +28,7 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "extmod/vfs.h" #include "modrp2.h" #include "hardware/flash.h" @@ -44,6 +45,13 @@ static_assert(MICROPY_HW_FLASH_STORAGE_BYTES % 4096 == 0, "Flash storage size mu #define MICROPY_HW_FLASH_STORAGE_BASE (PICO_FLASH_SIZE_BYTES - MICROPY_HW_FLASH_STORAGE_BYTES) #endif +#ifndef MICROPY_HW_ROMFS_BYTES +#define MICROPY_HW_ROMFS_BYTES (128 * 1024) +#endif + +// Put ROMFS at the upper end of the code space. +#define MICROPY_HW_ROMFS_BASE (MICROPY_HW_FLASH_STORAGE_BASE - MICROPY_HW_ROMFS_BYTES) + static_assert(MICROPY_HW_FLASH_STORAGE_BYTES <= PICO_FLASH_SIZE_BYTES, "MICROPY_HW_FLASH_STORAGE_BYTES too big"); static_assert(MICROPY_HW_FLASH_STORAGE_BASE + MICROPY_HW_FLASH_STORAGE_BYTES <= PICO_FLASH_SIZE_BYTES, "MICROPY_HW_FLASH_STORAGE_BYTES too big"); @@ -59,6 +67,14 @@ static rp2_flash_obj_t rp2_flash_obj = { .flash_size = MICROPY_HW_FLASH_STORAGE_BYTES, }; +#if MICROPY_HW_ROMFS_BYTES > 0 +static rp2_flash_obj_t rp2_flash_romfs_obj = { + .base = { &rp2_flash_type }, + .flash_base = MICROPY_HW_ROMFS_BASE, + .flash_size = MICROPY_HW_ROMFS_BYTES, +}; +#endif + // Tag the flash drive in the binary as readable/writable (but not reformatable) bi_decl(bi_block_device( BINARY_INFO_TAG_MICROPYTHON, @@ -138,6 +154,19 @@ static mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, siz return MP_OBJ_FROM_PTR(self); } +static mp_int_t rp2_flash_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + rp2_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)(XIP_BASE + self->flash_base); + bufinfo->len = self->flash_size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Write unsupported. + return 1; + } +} + static mp_obj_t rp2_flash_readblocks(size_t n_args, const mp_obj_t *args) { rp2_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]); uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES; @@ -218,5 +247,19 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, rp2_flash_make_new, + buffer, rp2_flash_get_buffer, locals_dict, &rp2_flash_locals_dict ); + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + switch (mp_obj_get_int(args[0])) { + #if MICROPY_HW_ROMFS_BYTES > 0 + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&rp2_flash_romfs_obj); + #endif + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} diff --git a/ports/samd/Makefile b/ports/samd/Makefile index 005664f178d3c..e7441a6d94970 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -90,7 +90,7 @@ CFLAGS += $(CFLAGS_EXTRA) CFLAGS += -DMICROPY_HW_CODESIZE=$(strip $(subst K,' ', $(MICROPY_HW_CODESIZE))) LDFLAGS += -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref -LDFLAGS += --defsym=_codesize=$(MICROPY_HW_CODESIZE) +LDFLAGS += --defsym=_codesize=$(MICROPY_HW_CODESIZE) --defsym=_vfsromsize=$(MICROPY_HW_VFSROMSIZE) LIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -103,6 +103,10 @@ CFLAGS += -Os -DNDEBUG LDFLAGS += --gc-sections --print-memory-usage CFLAGS += -fdata-sections -ffunction-sections endif +# Disable VFSROM support if the size was set to 0 +ifeq ($(MICROPY_HW_VFSROMSIZE),0) + CFLAGS += -DMICROPY_VFS_ROM=0 +endif # Flags for optional C++ source code CXXFLAGS += $(filter-out -std=c99,$(CFLAGS)) diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk index e2895c7c0c2f9..6ea327a650d40 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk @@ -5,4 +5,4 @@ TEXT0 = 0x2000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 232K diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk index 6ec2d43dedbd8..73be611309e4a 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +# The default for MICROPY_HW_VFSROMSIZE is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk index e2895c7c0c2f9..6ea327a650d40 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.mk @@ -5,4 +5,4 @@ TEXT0 = 0x2000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 232K diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk index 740154a6d6825..adc9b1397c3eb 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +# The default for MICROPY_HW_VFSROMSIZE is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk index 43ca5a59cc636..709441b833212 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk @@ -7,4 +7,7 @@ TEXT0 = 0x4000 MICROPY_PY_NETWORK ?= 1 MICROPY_PY_NETWORK_NINAW10 ?= 1 -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +# The default for MICROPY_HW_VFSROMSIZE is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk index 54948627d2b67..eea063fe55433 100644 --- a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk @@ -6,4 +6,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +# The default for MICROPY_HW_VFSROMSIZE is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk index cc43c22cea588..4e8fb3d4429fb 100644 --- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk @@ -3,4 +3,4 @@ CMSIS_MCU = SAMD21J18A LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 -MICROPY_HW_CODESIZE ?= 248K +MICROPY_HW_CODESIZE ?= 232K diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk index 7bf70ac669566..fd6d4b24516d0 100644 --- a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 496K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +# The default for MICROPY_HW_VFSROMSIZE is 64K +MICROPY_HW_CODESIZE ?= 432K diff --git a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk index 263e582694495..0af891e263686 100644 --- a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk +++ b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.mk @@ -5,4 +5,7 @@ TEXT0 = 0x4000 # The ?='s allow overriding in mpconfigboard.mk. # MicroPython settings -MICROPY_HW_CODESIZE ?= 1008K +# The size of a MCU flash filesystem will be +# 1008k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE +MICROPY_HW_CODESIZE ?= 752K +MICROPY_HW_VFSROMSIZE ?= 256K diff --git a/ports/samd/boards/samd21x18a.ld b/ports/samd/boards/samd21x18a.ld index 3ab051569fb18..7de761b0f6a84 100644 --- a/ports/samd/boards/samd21x18a.ld +++ b/ports/samd/boards/samd21x18a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _vfsromsize are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_VFSROMSIZE and are set in Makefile. */ _flashsize = 256K; /* The physical flash size */ @@ -21,8 +21,18 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 8K; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs will be 0. +That does not matter since these devices do not use the MCU flash file +system. +*/ + _oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +_sflash_fs = _flashsize - _codesize - _bootloader - _vfsromsize; + +_oflash_vfsrom = ORIGIN(FLASH) + _flashsize - _vfsromsize - _bootloader; +_sflash_vfsrom = _vfsromsize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/boards/samd51x19a.ld b/ports/samd/boards/samd51x19a.ld index 30bc8e33281fb..45d102da8874c 100644 --- a/ports/samd/boards/samd51x19a.ld +++ b/ports/samd/boards/samd51x19a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _vfsromsize are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_VFSROMSIZE and are set in Makefile. */ _flashsize = 512K; /* The physical flash size */ @@ -21,8 +21,18 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 16K; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs might be 0. +That does not matter since these devices do not use the MCU flash file +system. +*/ + _oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +_sflash_fs = _flashsize - _codesize - _bootloader - _vfsromsize; + +_oflash_vfsrom = ORIGIN(FLASH) + _flashsize - _vfsromsize - _bootloader; +_sflash_vfsrom = _vfsromsize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/boards/samd51x20a.ld b/ports/samd/boards/samd51x20a.ld index 472ab316c6fde..e485a173fcdaa 100644 --- a/ports/samd/boards/samd51x20a.ld +++ b/ports/samd/boards/samd51x20a.ld @@ -3,8 +3,8 @@ */ /* -_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as -MICROPY_HW_CODESIZE and is set in Makefile +_codesize and _vfsromsize are defined in mpconfigmcu.mk or mpconfigboard.mk +as MICROPY_HW_CODESIZE and MICROPY_HW_VFSROMSIZE and are set in Makefile. */ _flashsize = 1024K; /* The physical flash size */ @@ -21,8 +21,18 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM) - 8; _sstack = _estack - 16K; +/* +The VfsROM file system is placed at the end of the flash. +For device with SPI flash the number for _sflash_fs might be 0. +That does not matter since these devices do not use the MCU flash file +system. +*/ + _oflash_fs = ORIGIN(FLASH) + _codesize; -_sflash_fs = _flashsize - _codesize - _bootloader; +_sflash_fs = _flashsize - _codesize - _bootloader - _vfsromsize; + +_oflash_vfsrom = ORIGIN(FLASH) + _flashsize - _vfsromsize - _bootloader; +_sflash_vfsrom = _vfsromsize; _sheap = _ebss; _eheap = _sstack; diff --git a/ports/samd/mcu/samd21/manifest.py b/ports/samd/mcu/samd21/manifest.py index 2a19a843f8a9b..8ad1e38ba099a 100644 --- a/ports/samd/mcu/samd21/manifest.py +++ b/ports/samd/mcu/samd21/manifest.py @@ -1,5 +1,2 @@ include("$(PORT_DIR)/boards/manifest.py") include("$(MPY_DIR)/extmod/asyncio") -require("onewire") -require("ds18x20") -require("dht") diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h index 29965f50f63a8..131ee723a9667 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.h +++ b/ports/samd/mcu/samd21/mpconfigmcu.h @@ -2,7 +2,7 @@ #include "samd21.h" #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES) -#if MICROPY_HW_CODESIZE == 248 +#if MICROPY_HW_CODESIZE == 232 #define SAMD21_EXTRA_FEATURES 1 #else #define SAMD21_EXTRA_FEATURES 0 diff --git a/ports/samd/mcu/samd21/mpconfigmcu.mk b/ports/samd/mcu/samd21/mpconfigmcu.mk index 34209775c2565..cc6058562c4b2 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.mk +++ b/ports/samd/mcu/samd21/mpconfigmcu.mk @@ -4,10 +4,13 @@ CFLAGS_MCU += -DCFG_TUSB_MCU=OPT_MCU_SAMD21 MPY_CROSS_MCU_ARCH = armv6m -MICROPY_HW_CODESIZE ?= 184K +MICROPY_HW_CODESIZE ?= 191K -ifeq ($(MICROPY_HW_CODESIZE), 248K) +ifeq ($(MICROPY_HW_CODESIZE), 232K) FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py +MICROPY_HW_VFSROMSIZE ?= 16K +else +MICROPY_HW_VFSROMSIZE ?= 15K endif MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/mcu/samd51/manifest.py b/ports/samd/mcu/samd51/manifest.py index 2a19a843f8a9b..8ad1e38ba099a 100644 --- a/ports/samd/mcu/samd51/manifest.py +++ b/ports/samd/mcu/samd51/manifest.py @@ -1,5 +1,2 @@ include("$(PORT_DIR)/boards/manifest.py") include("$(MPY_DIR)/extmod/asyncio") -require("onewire") -require("ds18x20") -require("dht") diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h index 9a7b8528f3573..19b29612dfa24 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.h +++ b/ports/samd/mcu/samd51/mpconfigmcu.h @@ -18,10 +18,10 @@ unsigned long trng_random_u32(void); #define MICROPY_PY_MACHINE_UART_IRQ (1) // fatfs configuration used in ffconf.h -#define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_MAX_SS (4096) -#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define VFS_BLOCK_SIZE_BYTES (1536) // diff --git a/ports/samd/mcu/samd51/mpconfigmcu.mk b/ports/samd/mcu/samd51/mpconfigmcu.mk index 9bef5eca166ab..9bb1292434f16 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.mk +++ b/ports/samd/mcu/samd51/mpconfigmcu.mk @@ -5,6 +5,7 @@ CFLAGS_MCU += -DCFG_TUSB_MCU=OPT_MCU_SAMD51 MPY_CROSS_MCU_ARCH = armv7m MICROPY_HW_CODESIZE ?= 368K +MICROPY_HW_VFSROMSIZE ?= 64K MICROPY_VFS_LFS2 ?= 1 MICROPY_VFS_FAT ?= 1 diff --git a/ports/samd/modules/_boot.py b/ports/samd/modules/_boot.py index f4053e2cddf00..88a9c0c4a9504 100644 --- a/ports/samd/modules/_boot.py +++ b/ports/samd/modules/_boot.py @@ -3,6 +3,12 @@ import samd import sys +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom") + sys.path.insert(0, "/rom") +except: + pass + bdev = samd.Flash() # Try to mount the filesystem, and format the flash if it doesn't exist. diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index 0b47500bf7e7c..896acd1a00c0c 100644 --- a/ports/samd/mpconfigport.h +++ b/ports/samd/mpconfigport.h @@ -85,6 +85,9 @@ #define MICROPY_PY_OS_INCLUDEFILE "ports/samd/modos.c" #define MICROPY_READER_VFS (1) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (1) +#endif #ifndef MICROPY_PY_MACHINE_ADC #define MICROPY_PY_MACHINE_ADC (1) #endif diff --git a/ports/samd/samd_flash.c b/ports/samd/samd_flash.c index f68bdf140f490..6e2e07e8d68ef 100644 --- a/ports/samd/samd_flash.c +++ b/ports/samd/samd_flash.c @@ -26,11 +26,13 @@ #include +#include "py/objarray.h" #include "py/runtime.h" #include "extmod/vfs.h" +#include "py/mperrno.h" #include "samd_soc.h" -#if MICROPY_HW_MCUFLASH +#if MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM // ASF 4 #include "hal_flash.h" @@ -45,7 +47,6 @@ #endif static struct flash_descriptor flash_desc; -static mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h extern const mp_obj_type_t samd_flash_type; typedef struct _samd_flash_obj_t { @@ -54,8 +55,9 @@ typedef struct _samd_flash_obj_t { uint32_t flash_size; } samd_flash_obj_t; +#if MICROPY_HW_MCUFLASH +static mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h extern uint8_t _oflash_fs, _sflash_fs; - // Build a Flash storage at top. static samd_flash_obj_t samd_flash_obj = { .base = { &samd_flash_type }, @@ -63,9 +65,31 @@ static samd_flash_obj_t samd_flash_obj = { .flash_size = (uint32_t)&_sflash_fs, // Get from MCU-Specific loader script. }; +static mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj. + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // Return singleton object. + return MP_OBJ_FROM_PTR(&samd_flash_obj); +} + +static mp_int_t samd_flash_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + samd_flash_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = (void *)((uintptr_t)self->flash_base); + bufinfo->len = self->flash_size; + bufinfo->typecode = 'B'; + return 0; + } else { + // Write unsupported. + return 1; + } +} +#endif // MICROPY_HW_MCUFLASH + // Flash init (from cctpy) // Method is needed for when MP starts up in _boot.py -static void samd_flash_init(void) { +void samd_flash_init(void) { #ifdef SAMD51 hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK); #endif @@ -76,27 +100,19 @@ static void samd_flash_init(void) { flash_init(&flash_desc, NVMCTRL); } -static mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj. - mp_arg_check_num(n_args, n_kw, 0, 0, false); - - samd_flash_init(); - - // Return singleton object. - return MP_OBJ_FROM_PTR(&samd_flash_obj); -} - +#if MICROPY_HW_MCUFLASH // Function for ioctl. static mp_obj_t eraseblock(uint32_t sector_in) { // Destination address aligned with page start to be erased. - uint32_t DEST_ADDR = sector_in; // Number of pages to be erased. - mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc); // adf4 API call + uint32_t dest_addr = sector_in; // Number of pages to be erased. + mp_int_t page_size = flash_get_page_size(&flash_desc); // adf4 API call - flash_erase(&flash_desc, DEST_ADDR, (BLOCK_SIZE / PAGE_SIZE)); + flash_erase(&flash_desc, dest_addr, (BLOCK_SIZE / page_size)); return mp_const_none; } + static mp_obj_t samd_flash_version(void) { return MP_OBJ_NEW_SMALL_INT(flash_get_version()); } @@ -131,7 +147,7 @@ static mp_obj_t samd_flash_writeblocks(size_t n_args, const mp_obj_t *args) { } // Write data to flash (adf4 API) flash_write(&flash_desc, offset, bufinfo.buf, bufinfo.len); - // TODO check return value + return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_writeblocks_obj, 3, 4, samd_flash_writeblocks); @@ -176,7 +192,75 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_Flash, MP_TYPE_FLAG_NONE, make_new, samd_flash_make_new, + buffer, samd_flash_get_buffer, locals_dict, &samd_flash_locals_dict ); +#endif -#endif // MICROPY_HW_MCUFLASH +#if MICROPY_VFS_ROM +// +// Uses object-based capabilities for devices using the internal flash +// for the regular file system and ioctl function for devices with +// external flash. +// +extern uint8_t _oflash_vfsrom, _sflash_vfsrom; + +#define MICROPY_HW_ROMFS_BASE ((uint32_t)&_oflash_vfsrom) +#define MICROPY_HW_ROMFS_BYTES ((uint32_t)&_sflash_vfsrom) + +#if MICROPY_HW_MCUFLASH +static samd_flash_obj_t samd_flash_romfs_obj = { + .base = { &samd_flash_type }, + .flash_base = MICROPY_HW_ROMFS_BASE, // Get from MCU-Specific loader script. + .flash_size = MICROPY_HW_ROMFS_BYTES, // Get from MCU-Specific loader script. +}; +#else +static const MP_DEFINE_MEMORYVIEW_OBJ(samd_flash_romfs_obj, 'B', 0, MICROPY_HW_ROMFS_BYTES, (void *)MICROPY_HW_ROMFS_BASE); +#endif + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + if (MICROPY_HW_ROMFS_BYTES <= 0) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + switch (mp_obj_get_int(args[0])) { + case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS: + return MP_OBJ_NEW_SMALL_INT(1); + + case MP_VFS_ROM_IOCTL_GET_SEGMENT: + return MP_OBJ_FROM_PTR(&samd_flash_romfs_obj); + + #if !MICROPY_HW_MCUFLASH + + case MP_VFS_ROM_IOCTL_WRITE_PREPARE: { + // Erase sectors in given range. + if (n_args < 3) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest_addr = MICROPY_HW_ROMFS_BASE; + uint32_t bytes_used = mp_obj_get_int(args[2]); + mp_int_t page_size = flash_get_page_size(&flash_desc); // adf4 API call + flash_erase(&flash_desc, dest_addr, (bytes_used + page_size - 1) / page_size); + return MP_OBJ_NEW_SMALL_INT(4); + } + + case MP_VFS_ROM_IOCTL_WRITE: { + // Write data to flash. + if (n_args < 4) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest_addr = MICROPY_HW_ROMFS_BASE + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + flash_write(&flash_desc, dest_addr, bufinfo.buf, bufinfo.len); + return MP_OBJ_NEW_SMALL_INT(0); + } + + #endif + + default: + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } +} +#endif + +#endif // MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c index e78032513c216..3ec418ff96e17 100644 --- a/ports/samd/samd_soc.c +++ b/ports/samd/samd_soc.c @@ -39,6 +39,7 @@ #include "tusb.h" extern void machine_rtc_start(bool force); +extern void samd_flash_init(void); static void usb_init(void) { // Init USB clock @@ -120,6 +121,9 @@ void samd_init(void) { mp_hal_ticks_cpu_enable(); #endif machine_rtc_start(false); + #if MICROPY_HW_MCUFLASH || MICROPY_VFS_ROM + samd_flash_init(); + #endif } #if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_UART diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index a9612f1a5792e..d75a898448714 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -287,6 +287,7 @@ SRC_C += \ rtc.c \ flash.c \ flashbdev.c \ + romfs.c \ spibdev.c \ storage.c \ sdcard.c \ diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h index 8f4ce30eff80a..bddef85f764d6 100644 --- a/ports/stm32/boardctrl.h +++ b/ports/stm32/boardctrl.h @@ -61,6 +61,12 @@ #define MICROPY_BOARD_TOP_SOFT_RESET_LOOP boardctrl_top_soft_reset_loop #endif +#ifndef MICROPY_BOARD_FROZEN_BOOT_FILE +#if MICROPY_VFS_ROM +#define MICROPY_BOARD_FROZEN_BOOT_FILE "_boot.py" +#endif +#endif + #ifndef MICROPY_BOARD_RUN_BOOT_PY #define MICROPY_BOARD_RUN_BOOT_PY boardctrl_run_boot_py #endif diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h index c573f942a0a13..f8c426b4d00ae 100644 --- a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/mpconfigboard.h @@ -25,6 +25,10 @@ #define MICROPY_HW_RTC_USE_US (0) #define MICROPY_HW_RTC_USE_CALOUT (1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // External SPI Flash config #if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h b/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h index fdf3128a3606d..b46d3c4b81097 100644 --- a/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h +++ b/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h @@ -32,6 +32,11 @@ typedef unsigned int mp_uint_t; // must be pointer size #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0) #define MICROPY_HW_TIM_IS_RESERVED(id) (id == 1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // Flash storage config #define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) #define MICROPY_HW_SPIFLASH_SOFT_RESET (1) @@ -125,8 +130,8 @@ void GIGA_board_low_power(int mode); // QSPI flash #1 for storage #define MICROPY_HW_QSPI_PRESCALER (2) // 100MHz #define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (27) -// Reserve 1MiB at the end for compatibility with alternate firmware that places WiFi blob here. -#define MICROPY_HW_SPIFLASH_SIZE_BITS (120 * 1024 * 1024) +// Reserve 4MiB for romfs and 1MiB at for WiFi/BT firmware. +#define MICROPY_HW_SPIFLASH_SIZE_BITS (88 * 1024 * 1024) #define MICROPY_HW_QSPIFLASH_CS (pyb_pin_QSPI2_CS) #define MICROPY_HW_QSPIFLASH_SCK (pyb_pin_QSPI2_CLK) #define MICROPY_HW_QSPIFLASH_IO0 (pyb_pin_QSPI2_D0) diff --git a/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld b/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld index 793a76b970292..43dda26f07dc3 100644 --- a/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld +++ b/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld @@ -13,11 +13,11 @@ MEMORY SRAM3 (xrw) : ORIGIN = 0x30040000, LENGTH = 32K /* SRAM3 D2 */ SRAM4 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 D3 */ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* Total available flash */ - FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 16384K /* 16MBs external QSPI flash */ FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* Arduino bootloader */ FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* filesystem */ FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1280K /* CM7 firmware */ FLASH_CM4 (rx) : ORIGIN = 0x08180000, LENGTH = 512K /* CM4 firmware */ + FLASH_ROMFS (rx) : ORIGIN = 0x90B00000, LENGTH = 4096K /* romfs partition in QSPI flash */ } /* produce a link error if there is not this amount of RAM for these sections */ @@ -44,6 +44,10 @@ _micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM); _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +/* Location of romfs filesystem */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); + /* OpenAMP shared memory region */ _openamp_shm_region_start = ORIGIN(SRAM4); _openamp_shm_region_end = ORIGIN(SRAM4) + LENGTH(SRAM4); diff --git a/ports/stm32/boards/ARDUINO_NICLA_VISION/mpconfigboard.h b/ports/stm32/boards/ARDUINO_NICLA_VISION/mpconfigboard.h index 505f8b6890169..d1b9f60b23e33 100644 --- a/ports/stm32/boards/ARDUINO_NICLA_VISION/mpconfigboard.h +++ b/ports/stm32/boards/ARDUINO_NICLA_VISION/mpconfigboard.h @@ -32,6 +32,11 @@ typedef unsigned int mp_uint_t; // must be pointer size #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0) #define MICROPY_HW_TIM_IS_RESERVED(id) (id == 3) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // Flash storage config #define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) #define MICROPY_HW_SPIFLASH_SOFT_RESET (1) @@ -130,8 +135,8 @@ void NICLAV_board_osc_enable(int enable); // QSPI flash for storage #define MICROPY_HW_QSPI_PRESCALER (2) // 100MHz #define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (27) -// Reserve 1MiB at the end for compatibility with alternate firmware that places WiFi blob here. -#define MICROPY_HW_SPIFLASH_SIZE_BITS (120 * 1024 * 1024) +// Reserve 4MiB for romfs and 1MiB at for WiFi/BT firmware. +#define MICROPY_HW_SPIFLASH_SIZE_BITS (88 * 1024 * 1024) #define MICROPY_HW_QSPIFLASH_CS (pyb_pin_QSPI2_CS) #define MICROPY_HW_QSPIFLASH_SCK (pyb_pin_QSPI2_CLK) #define MICROPY_HW_QSPIFLASH_IO0 (pyb_pin_QSPI2_D0) diff --git a/ports/stm32/boards/ARDUINO_NICLA_VISION/stm32h747.ld b/ports/stm32/boards/ARDUINO_NICLA_VISION/stm32h747.ld index 6d6ce279f299c..580f51726dc4d 100644 --- a/ports/stm32/boards/ARDUINO_NICLA_VISION/stm32h747.ld +++ b/ports/stm32/boards/ARDUINO_NICLA_VISION/stm32h747.ld @@ -13,11 +13,11 @@ MEMORY SRAM3 (xrw) : ORIGIN = 0x30040000, LENGTH = 32K /* SRAM3 D2 */ SRAM4 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 D3 */ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* Total available flash */ - FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 16384K /* 16MBs external QSPI flash */ FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* Arduino bootloader */ FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* filesystem */ FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1280K /* CM7 firmware */ FLASH_CM4 (rx) : ORIGIN = 0x08180000, LENGTH = 512K /* CM4 firmware */ + FLASH_ROMFS (rx) : ORIGIN = 0x90B00000, LENGTH = 4096K /* romfs partition in QSPI flash */ } _cm4_ram_start = ORIGIN(SRAM4); @@ -46,6 +46,10 @@ _micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM); _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +/* Location of romfs filesystem */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); + /* OpenAMP shared memory region */ _openamp_shm_region_start = ORIGIN(SRAM4); _openamp_shm_region_end = ORIGIN(SRAM4) + LENGTH(SRAM4); diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h b/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h index 900bf18673728..e295dcb82cd4e 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h @@ -32,6 +32,11 @@ typedef unsigned int mp_uint_t; // must be pointer size #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0) #define MICROPY_HW_TIM_IS_RESERVED(id) (id == 1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // Flash storage config #define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) #define MICROPY_HW_SPIFLASH_SOFT_RESET (1) @@ -129,8 +134,8 @@ void PORTENTA_board_osc_enable(int enable); // QSPI flash #1 for storage #define MICROPY_HW_QSPI_PRESCALER (2) // 100MHz #define MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 (27) -// Reserve 1MiB at the end for compatibility with alternate firmware that places WiFi blob here. -#define MICROPY_HW_SPIFLASH_SIZE_BITS (120 * 1024 * 1024) +// Reserve 4MiB for romfs and 1MiB at for WiFi/BT firmware. +#define MICROPY_HW_SPIFLASH_SIZE_BITS (88 * 1024 * 1024) #define MICROPY_HW_QSPIFLASH_CS (pyb_pin_QSPI2_CS) #define MICROPY_HW_QSPIFLASH_SCK (pyb_pin_QSPI2_CLK) #define MICROPY_HW_QSPIFLASH_IO0 (pyb_pin_QSPI2_D0) diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld b/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld index 793a76b970292..43dda26f07dc3 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/stm32h747.ld @@ -13,11 +13,11 @@ MEMORY SRAM3 (xrw) : ORIGIN = 0x30040000, LENGTH = 32K /* SRAM3 D2 */ SRAM4 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 D3 */ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* Total available flash */ - FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 16384K /* 16MBs external QSPI flash */ FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* Arduino bootloader */ FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* filesystem */ FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1280K /* CM7 firmware */ FLASH_CM4 (rx) : ORIGIN = 0x08180000, LENGTH = 512K /* CM4 firmware */ + FLASH_ROMFS (rx) : ORIGIN = 0x90B00000, LENGTH = 4096K /* romfs partition in QSPI flash */ } /* produce a link error if there is not this amount of RAM for these sections */ @@ -44,6 +44,10 @@ _micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM); _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +/* Location of romfs filesystem */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); + /* OpenAMP shared memory region */ _openamp_shm_region_start = ORIGIN(SRAM4); _openamp_shm_region_end = ORIGIN(SRAM4) + LENGTH(SRAM4); diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h index 9878b1533eedb..e038bc2325ea2 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h +++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h @@ -32,6 +32,10 @@ // For 2.7 to 3.6 V, 75 to 100 MHz: 3 wait states. #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_3 +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // UART buses // Bluetooth HCI #define MICROPY_HW_UART2_CTS (pyb_pin_BT_CTS) diff --git a/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld b/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld index d3c43a6948316..5e516c01bf92d 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld +++ b/ports/stm32/boards/LEGO_HUB_NO6/stm32f413xg.ld @@ -3,11 +3,11 @@ */ /* Specify the memory areas */ -/* FLASH_FS2 is placed before FLASH_TEXT to support 1MB and 1.5MB FLASH with common code in flashbdev.c */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */ - FLASH_APP (rx) : ORIGIN = 0x08010000, LENGTH = 976K + FLASH_APP (rx) : ORIGIN = 0x08010000, LENGTH = 448K + FLASH_ROMFS (rx): ORIGIN = 0x08080000, LENGTH = 256K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K /* SRAM1 + SRAM2 */ } @@ -25,3 +25,7 @@ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; + +/* ROMFS location */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); diff --git a/ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h index 3615225e51b6b..b07c7cea9171e 100644 --- a/ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h +++ b/ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h @@ -32,6 +32,10 @@ // For 2.7 to 3.6 V, 75 to 100 MHz: 3 wait states. #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_3 +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // UART buses // Bluetooth HCI #define MICROPY_HW_UART2_CTS (pyb_pin_BT_CTS) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h index 6a9ac02714fb7..00f31b5628168 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -6,11 +6,13 @@ #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_SOCKET (0) #define MICROPY_PY_NETWORK (0) #define MICROPY_PY_STM (0) #define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_PY_MACHINE_PIN_LEGACY (0) #define MICROPY_PY_HEAPQ (0) #define MICROPY_PY_FRAMEBUF (0) @@ -32,6 +34,10 @@ // The board has an external 32kHz crystal #define MICROPY_HW_RTC_USE_LSE (1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // UART config #define MICROPY_HW_UART1_TX (pin_B6) #define MICROPY_HW_UART1_RX (pin_B7) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk index 193ed793f6fc0..d8187824830f0 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -9,7 +9,7 @@ MICROPY_VFS_LFS1 ?= 1 MICROPY_HW_ENABLE_ISR_UART_FLASH_FUNCS_IN_RAM = 1 # Don't include default frozen modules because MCU is tight on flash space -FROZEN_MANIFEST ?= +FROZEN_MANIFEST ?= boards/manifest_minimal.py # LTO reduces final binary size, may be slower to build depending on gcc version and hardware LTO ?= 1 diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index 70d7f9cc4b8e4..5efefde358cc8 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -20,7 +20,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* sectors 2-7 */ - FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 2048K /* external QSPI */ + FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 1024K /* external QSPI */ + FLASH_ROMFS (rx): ORIGIN = 0x90100000, LENGTH = 512K /* external QSPI */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K /* DTCM+SRAM1+SRAM2 */ } @@ -39,6 +40,10 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; +/* ROMFS location */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); + /* Define output sections */ SECTIONS { diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index f0ef67e77e604..e8923bf9b66e5 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -64,6 +64,11 @@ void board_sleep(int value); #define MICROPY_HW_RTC_USE_US (1) #define MICROPY_HW_RTC_USE_CALOUT (1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev2.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // SPI flash #1, for R/W storage #define MICROPY_HW_SOFTQSPI_SCK_LOW(self) (GPIOE->BSRR = (0x10000 << 11)) #define MICROPY_HW_SOFTQSPI_SCK_HIGH(self) (GPIOE->BSRR = (1 << 11)) diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index 4262a48a9962c..e130efd6608fa 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -17,8 +17,9 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K - FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 1504K /* sectors 1-9 3x32K 1*128K 5*256K */ FLASH_EXT (rx) : ORIGIN = 0x90000000, LENGTH = 2048K /* external QSPI */ + FLASH_ROMFS (rx): ORIGIN = 0x90000000, LENGTH = 1024K /* external QSPI */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 512K /* DTCM=128k, SRAM1=368K, SRAM2=16K */ } @@ -37,4 +38,8 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; +/* ROMFS location */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); + INCLUDE common_bl.ld diff --git a/ports/stm32/boards/PYBD_SF6/mpconfigboard.h b/ports/stm32/boards/PYBD_SF6/mpconfigboard.h index 8c11d7b2eec96..526a111177987 100644 --- a/ports/stm32/boards/PYBD_SF6/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF6/mpconfigboard.h @@ -45,6 +45,11 @@ #define MICROPY_HW_CLK_PLLQ (6) #define MICROPY_HW_FLASH_LATENCY (FLASH_LATENCY_4) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) +#define MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ (&spi_bdev2.spiflash) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // Extra UART config #define MICROPY_HW_UART7_TX (pyb_pin_W16) #define MICROPY_HW_UART7_RX (pyb_pin_W22B) diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index 6219862be4957..b9216c70ff1fa 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -24,6 +24,10 @@ #define MICROPY_HW_RTC_USE_US (0) #define MICROPY_HW_RTC_USE_CALOUT (1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // UART config #define MICROPY_HW_UART1_NAME "XB" #define MICROPY_HW_UART1_TX (pin_B6) diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index c8f660c8fbb86..2b96ff974b7f2 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -24,6 +24,10 @@ #define MICROPY_HW_RTC_USE_US (0) #define MICROPY_HW_RTC_USE_CALOUT (1) +// ROMFS config +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (1) +#define MICROPY_HW_ROMFS_ENABLE_PART1 (1) + // UART config #define MICROPY_HW_UART1_NAME "XB" #define MICROPY_HW_UART1_TX (pin_B6) diff --git a/ports/stm32/boards/_boot.py b/ports/stm32/boards/_boot.py new file mode 100644 index 0000000000000..be65bff646ad0 --- /dev/null +++ b/ports/stm32/boards/_boot.py @@ -0,0 +1,10 @@ +import sys, vfs + +try: + vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2, 0)), "/rom") + # Note: this won't execute boot.py/main.py because the cwd is still /flash. + sys.path.insert(0, "/rom") +except: + pass + +del sys, vfs diff --git a/ports/stm32/boards/manifest.py b/ports/stm32/boards/manifest.py index 4f38179713ea6..7e4d1821351eb 100644 --- a/ports/stm32/boards/manifest.py +++ b/ports/stm32/boards/manifest.py @@ -1,3 +1,4 @@ +freeze(".", "_boot.py", opt=3) include("$(MPY_DIR)/extmod/asyncio") require("dht") diff --git a/ports/stm32/boards/manifest_minimal.py b/ports/stm32/boards/manifest_minimal.py new file mode 100644 index 0000000000000..ec2408e1074aa --- /dev/null +++ b/ports/stm32/boards/manifest_minimal.py @@ -0,0 +1 @@ +freeze(".", "_boot.py", opt=3) diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld index a8f0d3316ebf6..0f0fedaf3067a 100644 --- a/ports/stm32/boards/stm32f091xc.ld +++ b/ports/stm32/boards/stm32f091xc.ld @@ -5,7 +5,8 @@ /* Specify the memory areas */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 236K /* sectors 0-117 */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 226K /* sectors 0-112 */ + FLASH_ROMFS (rx): ORIGIN = 0x08038800, LENGTH = 10K /* sectors 113-117 */ FLASH_FS (r) : ORIGIN = 0x0803B000, LENGTH = 20K /* sectors 118-127 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K } @@ -32,3 +33,6 @@ _heap_end = _sstack; _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index 792558b6371e0..98039f3e56d7b 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -8,7 +8,8 @@ MEMORY FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */ FLASH_START (rx): ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3,4 are for filesystem */ - FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5,6,7,8,9,10,11 */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 640K /* sectors 5,6,7,8,9 */ + FLASH_ROMFS (rx): ORIGIN = 0x080c0000, LENGTH = 256K /* sectors 10,11 */ CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K } @@ -33,3 +34,7 @@ _micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(CCMRAM); _micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + +/* ROMFS location */ +_micropy_hw_romfs_part1_start = ORIGIN(FLASH_ROMFS); +_micropy_hw_romfs_part1_size = LENGTH(FLASH_ROMFS); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 4ce0a75b87e2b..2a650077f3a45 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -67,6 +67,26 @@ #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (1) #endif +// Whether to enable ROMFS on the internal flash. +#ifndef MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH +#define MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH (0) +#endif + +// Whether to enable ROMFS on external QSPI flash. +#ifndef MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI +#define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (0) +#endif + +// Whether to enable ROMFS partition 1. +#ifndef MICROPY_HW_ROMFS_ENABLE_PART1 +#define MICROPY_HW_ROMFS_ENABLE_PART1 (0) +#endif + +// Whether to enable ROMFS partition 2. +#ifndef MICROPY_HW_ROMFS_ENABLE_PART2 +#define MICROPY_HW_ROMFS_ENABLE_PART2 (0) +#endif + // Whether to enable storage on the internal flash of the MCU #ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 2b57446ee8233..da86fa641623a 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -79,6 +79,9 @@ #define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_ROM +#define MICROPY_VFS_ROM (MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH || MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI) +#endif // control over Python builtins #ifndef MICROPY_PY_BUILTINS_HELP_TEXT diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 98364db41d4fb..34359a1ccf838 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -34,8 +34,6 @@ #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) -#define QSPI_MAP_ADDR (0x90000000) - #ifndef MICROPY_HW_QSPI_PRESCALER #define MICROPY_HW_QSPI_PRESCALER 3 // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) #endif diff --git a/ports/stm32/qspi.h b/ports/stm32/qspi.h index c774b12582be6..6fe91168cfdba 100644 --- a/ports/stm32/qspi.h +++ b/ports/stm32/qspi.h @@ -28,9 +28,16 @@ #include "drivers/bus/qspi.h" +#define QSPI_MAP_ADDR (0x90000000) +#define QSPI_MAP_ADDR_MAX (0xa0000000) + extern const mp_qspi_proto_t qspi_proto; void qspi_init(void); void qspi_memory_map(void); +static inline bool qspi_is_valid_addr(uint32_t addr) { + return QSPI_MAP_ADDR <= addr && addr < QSPI_MAP_ADDR_MAX; +} + #endif // MICROPY_INCLUDED_STM32_QSPI_H diff --git a/ports/stm32/romfs.c b/ports/stm32/romfs.c new file mode 100644 index 0000000000000..5bee9f548b6eb --- /dev/null +++ b/ports/stm32/romfs.c @@ -0,0 +1,161 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Damien P. George + * + * 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 "py/obj.h" +#include "py/objarray.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "drivers/memory/spiflash.h" + +#include "flash.h" +#include "qspi.h" +#include "storage.h" + +#if MICROPY_VFS_ROM + +#if MICROPY_HW_ROMFS_ENABLE_PART1 && !defined(MICROPY_HW_ROMFS_PART1_START) +#define MICROPY_HW_ROMFS_PART1_START (uintptr_t)(&_micropy_hw_romfs_part1_start) +#define MICROPY_HW_ROMFS_PART1_SIZE (uintptr_t)(&_micropy_hw_romfs_part1_size) +extern uint8_t _micropy_hw_romfs_part1_start; +extern uint8_t _micropy_hw_romfs_part1_size; +#endif + +#if MICROPY_HW_ROMFS_ENABLE_PART2 && !defined(MICROPY_HW_ROMFS_PART2_START) +#define MICROPY_HW_ROMFS_PART2_START (uintptr_t)(&_micropy_hw_romfs_part2_start) +#define MICROPY_HW_ROMFS_PART2_SIZE (uintptr_t)(&_micropy_hw_romfs_part2_size) +extern uint8_t _micropy_hw_romfs_part2_start; +extern uint8_t _micropy_hw_romfs_part2_size; +#endif + +#define ROMFS_MEMORYVIEW(base, size) {{&mp_type_memoryview}, 'B', 0, (size), (void *)(base)} + +static const mp_obj_array_t romfs_obj_table[] = { + #if MICROPY_HW_ROMFS_ENABLE_PART1 + ROMFS_MEMORYVIEW(MICROPY_HW_ROMFS_PART1_START, MICROPY_HW_ROMFS_PART1_SIZE), + #endif + #if MICROPY_HW_ROMFS_ENABLE_PART2 + ROMFS_MEMORYVIEW(MICROPY_HW_ROMFS_PART2_START, MICROPY_HW_ROMFS_PART2_SIZE), + #endif +}; + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + mp_int_t cmd = mp_obj_get_int(args[0]); + if (cmd == MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS) { + return MP_OBJ_NEW_SMALL_INT(MP_ARRAY_SIZE(romfs_obj_table)); + } + + if (n_args < 2) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + + mp_int_t romfs_id = mp_obj_get_int(args[1]); + if (!(0 <= romfs_id && romfs_id < MP_ARRAY_SIZE(romfs_obj_table))) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + + const mp_obj_array_t *romfs_obj = &romfs_obj_table[romfs_id]; + uintptr_t romfs_base = (uintptr_t)romfs_obj->items; + uintptr_t romfs_len = romfs_obj->len; + + if (cmd == MP_VFS_ROM_IOCTL_GET_SEGMENT) { + // Return the ROMFS memoryview object. + return MP_OBJ_FROM_PTR(romfs_obj); + } + + if (cmd == MP_VFS_ROM_IOCTL_WRITE_PREPARE) { + // Erase sectors in given range. + if (n_args < 3) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = romfs_base; + uint32_t dest_max = dest + mp_obj_get_int(args[2]); + if (dest_max > romfs_base + romfs_len) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + + #if MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH + if (flash_is_valid_addr(dest)) { + while (dest < dest_max) { + int ret = flash_erase(dest); + if (ret < 0) { + return MP_OBJ_NEW_SMALL_INT(ret); + } + uint32_t sector_size = 0; + flash_get_sector_info(dest, NULL, §or_size); + dest += sector_size; + } + return MP_OBJ_NEW_SMALL_INT(16); + } + #endif + + #if MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI + if (qspi_is_valid_addr(dest)) { + dest -= QSPI_MAP_ADDR; + dest_max -= QSPI_MAP_ADDR; + while (dest < dest_max) { + int ret = mp_spiflash_erase_block(MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ, dest); + if (ret < 0) { + return MP_OBJ_NEW_SMALL_INT(ret); + } + dest += MP_SPIFLASH_ERASE_BLOCK_SIZE; + } + return MP_OBJ_NEW_SMALL_INT(4); + } + #endif + } + + if (cmd == MP_VFS_ROM_IOCTL_WRITE) { + // Write data to flash. + if (n_args < 4) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + uint32_t dest = romfs_base + mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + if (dest + bufinfo.len > romfs_base + romfs_len) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); + } + + #if MICROPY_HW_ROMFS_ENABLE_INTERNAL_FLASH + if (flash_is_valid_addr(dest)) { + int ret = flash_write(dest, bufinfo.buf, bufinfo.len / 4); + return MP_OBJ_NEW_SMALL_INT(ret); + } + #endif + + #if MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI + if (qspi_is_valid_addr(dest)) { + dest -= QSPI_MAP_ADDR; + int ret = mp_spiflash_write(MICROPY_HW_ROMFS_QSPI_SPIFLASH_OBJ, dest, bufinfo.len, bufinfo.buf); + return MP_OBJ_NEW_SMALL_INT(ret); + } + #endif + } + + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); +} + +#endif // MICROPY_VFS_ROM diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index a6594fd4d98c9..7625bd223f0cd 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -28,6 +28,7 @@ #include "py/mperrno.h" #include "extmod/vfs_fat.h" +#include "flash.h" #include "systick.h" #include "led.h" #include "storage.h" @@ -289,6 +290,7 @@ static mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, siz { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); diff --git a/ports/unix/main.c b/ports/unix/main.c index 58fa3ff589a55..53a5a2309f55b 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -45,6 +45,7 @@ #include "py/gc.h" #include "py/objstr.h" #include "py/cstack.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "py/mpthread.h" #include "extmod/misc.h" @@ -803,3 +804,7 @@ void nlr_jump_fail(void *val) { fprintf(stderr, "FATAL: uncaught NLR %p\n", val); exit(1); } + +mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) { + return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL); +} diff --git a/py/objarray.h b/py/objarray.h index 4a0e8a983fe77..bb7a514b97913 100644 --- a/py/objarray.h +++ b/py/objarray.h @@ -53,6 +53,10 @@ typedef struct _mp_obj_array_t { } mp_obj_array_t; #if MICROPY_PY_BUILTINS_MEMORYVIEW + +#define MP_DEFINE_MEMORYVIEW_OBJ(obj_name, typecode, offset, len, ptr) \ + mp_obj_array_t obj_name = {{&mp_type_memoryview}, (typecode), (offset), (len), (ptr)} + static inline void mp_obj_memoryview_init(mp_obj_array_t *self, size_t typecode, size_t offset, size_t len, void *items) { self->base.type = &mp_type_memoryview; self->typecode = typecode; @@ -60,6 +64,7 @@ static inline void mp_obj_memoryview_init(mp_obj_array_t *self, size_t typecode, self->len = len; self->items = items; } + #endif #if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY diff --git a/tools/mpremote/mpremote/commands.py b/tools/mpremote/mpremote/commands.py index f86befd080349..f03596202421e 100644 --- a/tools/mpremote/mpremote/commands.py +++ b/tools/mpremote/mpremote/commands.py @@ -7,6 +7,7 @@ from .transport import TransportError, stdout_write_bytes from .transport_serial import SerialTransport +from .romfs import make_romfs class CommandError(Exception): @@ -478,3 +479,120 @@ def do_rtc(state, args): state.transport.exec("machine.RTC().datetime({})".format(timetuple)) else: print(state.transport.eval("machine.RTC().datetime()")) + + +def _do_romfs_query(state, args): + state.ensure_raw_repl() + state.did_action() + + # Detect the romfs and get its associated device. + state.transport.exec("import vfs") + num_rom_partitions = state.transport.eval("hasattr(vfs, 'rom_ioctl') and vfs.rom_ioctl(1)") + if num_rom_partitions is False: + print("No ROM partitions available") + return + + for rom_id in range(num_rom_partitions): + state.transport.exec(f"dev=vfs.rom_ioctl(2,{rom_id})") + has_object = state.transport.eval("hasattr(dev,'ioctl')") + if has_object: + rom_block_count = state.transport.eval("dev.ioctl(4,0)") + rom_block_size = state.transport.eval("dev.ioctl(5,0)") + rom_size = rom_block_count * rom_block_size + print( + f"ROM{rom_id} partition has size {rom_size} bytes ({rom_block_count} blocks of {rom_block_size} bytes each)" + ) + else: + rom_size = state.transport.eval("len(dev)") + print(f"ROM{rom_id} partition has size {rom_size} bytes") + print("Contents:", state.transport.eval("bytes(memoryview(dev)[:8]).hex(':')"), "...") + + +def _do_romfs_build(state, args): + state.did_action() + + input_directory = args.path[0] + output_file = input_directory + ".romfs" + romfs = make_romfs(input_directory, mpy_cross=args.mpy) + print(f"Image size is {len(romfs)} bytes") + with open(output_file, "wb") as f: + f.write(romfs) + + +def _do_romfs_deploy(state, args): + rom_id = 0 + + state.ensure_raw_repl() + state.did_action() + + # Read in or create the romfs filesystem. + romfs_filename = args.path[0] + if romfs_filename.endswith(".romfs"): + with open(romfs_filename, "rb") as f: + romfs = f.read() + else: + romfs = make_romfs(romfs_filename, mpy_cross=args.mpy) + print(f"Image size is {len(romfs)} bytes") + + # Detect the romfs and get its associated device. + state.transport.exec(f"import vfs;dev=vfs.rom_ioctl(2,{rom_id})") + has_object = state.transport.eval("hasattr(dev,'ioctl')") + if has_object: + rom_block_count = state.transport.eval("dev.ioctl(4,0)") + rom_block_size = state.transport.eval("dev.ioctl(5,0)") + rom_size = rom_block_count * rom_block_size + print( + f"ROM partition has size {rom_size} bytes ({rom_block_count} blocks of {rom_block_size} bytes each)" + ) + else: + rom_size = state.transport.eval("len(dev)") + print(f"ROM partition has size {rom_size} bytes") + + # Check if romfs will fit on the target device. + if len(romfs) > rom_size: + print("ROMFS partition is too small for image") + sys.exit(1) + + # Prepare ROM for writing. + print("Preparing ROM for writing") + chunk_size = 4096 + if has_object: + for offset in range(0, len(romfs), rom_block_size): + state.transport.exec(f"dev.ioctl(6,{offset // rom_block_size})") + chunk_size = min(chunk_size, rom_block_size) + else: + rom_min_write = state.transport.eval(f"vfs.rom_ioctl(3,{rom_id},{len(romfs)})") + chunk_size = max(chunk_size, rom_min_write) + + # Deploy the romfs filesystem to the device. + state.transport.exec(f"buf=bytearray({chunk_size})") + for offset in range(0, len(romfs), chunk_size): + romfs_chunk = romfs[offset : offset + chunk_size] + state.transport.exec(f"buf[:{len(romfs_chunk)}]=" + repr(romfs_chunk)) + print(f"\rWriting at offset {offset}", end="") + if has_object: + state.transport.exec( + f"dev.writeblocks({offset // rom_block_size},buf,{offset % rom_block_size})" + ) + else: + state.transport.exec(f"vfs.rom_ioctl(4,{rom_id},{offset},buf)") + + # Complete writing. + if has_object: + pass + else: + state.transport.eval(f"vfs.rom_ioctl(5,{rom_id})") + + print() + print("ROMFS image deployed") + + +def do_romfs(state, args): + if args.command[0] == "query": + _do_romfs_query(state, args) + elif args.command[0] == "build": + _do_romfs_build(state, args) + elif args.command[0] == "deploy": + _do_romfs_deploy(state, args) + else: + raise CommandError(f"romfs: '{args.command[0]}' is not a command") diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py index e6e397020fe85..6130cb6200614 100644 --- a/tools/mpremote/mpremote/main.py +++ b/tools/mpremote/mpremote/main.py @@ -36,6 +36,7 @@ do_resume, do_rtc, do_soft_reset, + do_romfs, ) from .mip import do_mip from .repl import do_repl @@ -228,6 +229,14 @@ def argparse_mip(): return cmd_parser +def argparse_romfs(): + cmd_parser = argparse.ArgumentParser(description="manage romfs") + _bool_flag(cmd_parser, "mpy", "m", True, "download as compiled .mpy files (default)") + cmd_parser.add_argument("command", nargs=1, help="romfs command (e.g. query, build, deploy)") + cmd_parser.add_argument("path", nargs="*", help="path to directory to deploy") + return cmd_parser + + def argparse_none(description): return lambda: argparse.ArgumentParser(description=description) @@ -302,6 +311,15 @@ def argparse_none(description): do_version, argparse_none("print version and exit"), ), + # separate commands for each step: + # manifest -> directory -> romfs -> device + # then can have shortcuts that do everything at once + # can have auto-mpy-cross + # no need to do the first step (manifest) now + "romfs": ( + do_romfs, + argparse_romfs, + ), } # Additional commands aliases. diff --git a/tools/mpremote/mpremote/romfs.py b/tools/mpremote/mpremote/romfs.py new file mode 100644 index 0000000000000..2e848c0f96858 --- /dev/null +++ b/tools/mpremote/mpremote/romfs.py @@ -0,0 +1,170 @@ +# MIT license; Copyright (c) 2022 Damien P. George + +import struct, sys, os + +try: + from mpy_cross import run as mpy_cross_run +except ImportError: + mpy_cross_run = None + + +class VfsRomWriter: + ROMFS_HEADER = b"\xd2\xcd\x31" + + ROMFS_RECORD_KIND_UNUSED = 0 + ROMFS_RECORD_KIND_PADDING = 1 + ROMFS_RECORD_KIND_DATA_VERBATIM = 2 + ROMFS_RECORD_KIND_DATA_POINTER = 3 + ROMFS_RECORD_KIND_DIRECTORY = 4 + ROMFS_RECORD_KIND_FILE = 5 + + def __init__(self): + self._dir_stack = [(None, bytearray())] + + def _encode_uint(self, value): + encoded = [value & 0x7F] + value >>= 7 + while value != 0: + encoded.insert(0, 0x80 | (value & 0x7F)) + value >>= 7 + return bytes(encoded) + + def _pack(self, kind, payload): + return self._encode_uint(kind) + self._encode_uint(len(payload)) + payload + + def _extend(self, data): + buf = self._dir_stack[-1][1] + buf.extend(data) + return len(buf) + + def finalise(self): + _, data = self._dir_stack.pop() + encoded_kind = VfsRomWriter.ROMFS_HEADER + encoded_len = self._encode_uint(len(data)) + if (len(encoded_kind) + len(encoded_len) + len(data)) % 2 == 1: + encoded_len = b"\x80" + encoded_len + data = encoded_kind + encoded_len + data + return data + + def opendir(self, dirname): + self._dir_stack.append((dirname, bytearray())) + + def closedir(self): + dirname, dirdata = self._dir_stack.pop() + dirdata = self._encode_uint(len(dirname)) + bytes(dirname, "ascii") + dirdata + self._extend(self._pack(VfsRomWriter.ROMFS_RECORD_KIND_DIRECTORY, dirdata)) + + def mkdata(self, data): + assert len(self._dir_stack) == 1 + return self._extend(self._pack(VfsRomWriter.ROMFS_RECORD_KIND_DATA_VERBATIM, data)) - len( + data + ) + + def mkfile(self, filename, filedata): + filename = bytes(filename, "ascii") + payload = self._encode_uint(len(filename)) + payload += filename + if isinstance(filedata, tuple): + sub_payload = self._encode_uint(filedata[0]) + sub_payload += self._encode_uint(filedata[1]) + payload += self._pack(VfsRomWriter.ROMFS_RECORD_KIND_DATA_POINTER, sub_payload) + else: + payload += self._pack(VfsRomWriter.ROMFS_RECORD_KIND_DATA_VERBATIM, filedata) + self._dir_stack[-1][1].extend(self._pack(VfsRomWriter.ROMFS_RECORD_KIND_FILE, payload)) + + +def copy_recursively(vfs, src_dir, print_prefix, mpy_cross): + assert src_dir.endswith("/") + DIR = 1 << 14 + mpy_cross_missed = 0 + dir_contents = sorted(os.listdir(src_dir)) + for name in dir_contents: + src_name = src_dir + name + st = os.stat(src_name) + + if name == dir_contents[-1]: + # Last entry in the directory listing. + print_entry = "\\--" + print_recurse = " " + else: + # Not the last entry in the directory listing. + print_entry = "|--" + print_recurse = "| " + + if st[0] & DIR: + # A directory, enter it and copy its contents recursively. + print(print_prefix + print_entry, name + "/") + vfs.opendir(name) + mpy_cross_missed += copy_recursively( + vfs, src_name + "/", print_prefix + print_recurse, mpy_cross + ) + vfs.closedir() + else: + # A file. + did_mpy = False + name_extra = "" + if mpy_cross and name.endswith(".py"): + name_mpy = name[:-3] + ".mpy" + src_name_mpy = src_dir + name_mpy + if not os.path.isfile(src_name_mpy): + if mpy_cross_run is not None: + did_mpy = True + proc = mpy_cross_run(src_name) + proc.wait() + else: + mpy_cross_missed += 1 + if did_mpy: + name_extra = " -> .mpy" + print(print_prefix + print_entry, name + name_extra) + if did_mpy: + name = name_mpy + src_name = src_name_mpy + with open(src_name, "rb") as src: + vfs.mkfile(name, src.read()) + if did_mpy: + os.remove(src_name_mpy) + return mpy_cross_missed + + +def make_romfs(src_dir, *, mpy_cross): + if src_dir.endswith(".py"): + sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../..")) + import manifestfile + + VARS = {} + VARS["MPY_LIB_DIR"] = os.path.abspath("../../lib/micropython-lib") + manifest = manifestfile.ManifestFile(manifestfile.MODE_FREEZE, VARS) + try: + manifest.execute(src_dir) + except manifestfile.ManifestFileError as er: + print('freeze error executing "{}": {}'.format(src_dir, er.args[0])) + sys.exit(1) + + manifest_dir_structure = {} + for result in manifest.files(): + components = result.target_path.split("/") + s = manifest_dir_structure + for x in components[:-1]: + s = s.setdefault(x, {}) + s[components[-1]] = result + return + + if not src_dir.endswith("/"): + src_dir += "/" + + vfs = VfsRomWriter() + + # Build the filesystem recursively. + print("Building romfs filesystem, source directory: {}".format(src_dir)) + print("/") + try: + mpy_cross_missed = copy_recursively(vfs, src_dir, "", mpy_cross) + except OSError as er: + print("Error: OSError {}".format(er), file=sys.stderr) + sys.exit(1) + + if mpy_cross_missed: + print("Warning: `mpy_cross` module not found, .py files were not precompiled") + mpy_cross = False + + return vfs.finalise() 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