diff options
-rw-r--r-- | ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h | 1 | ||||
-rw-r--r-- | ports/stm32/boards/PYBD_SF2/mpconfigboard.h | 1 | ||||
-rwxr-xr-x | ports/stm32/mboot/Makefile | 7 | ||||
-rw-r--r-- | ports/stm32/mboot/fsload.c | 71 | ||||
-rw-r--r-- | ports/stm32/mboot/fwupdate.py | 13 | ||||
-rw-r--r-- | ports/stm32/mboot/mboot.h | 8 | ||||
-rw-r--r-- | ports/stm32/mboot/vfs.h | 55 | ||||
-rw-r--r-- | ports/stm32/mboot/vfs_fat.c | 4 | ||||
-rw-r--r-- | ports/stm32/mboot/vfs_lfs.c | 177 |
9 files changed, 309 insertions, 28 deletions
diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h index eb622cd29..71af3ce03 100644 --- a/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/mpconfigboard.h @@ -83,3 +83,4 @@ #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_NONE) #define MBOOT_BOOTPIN_ACTIVE (0) #define MBOOT_FSLOAD (1) +#define MBOOT_VFS_FAT (1) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index 757dacf9a..f6e130eb5 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -188,6 +188,7 @@ extern struct _spi_bdev_t spi_bdev2; #define MBOOT_USB_AUTODETECT_PORT (1) #define MBOOT_FSLOAD (1) +#define MBOOT_VFS_FAT (1) #define MBOOT_I2C_PERIPH_ID 1 #define MBOOT_I2C_SCL (pin_B8) diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 9ab186412..c901dfb33 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -70,6 +70,8 @@ CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>' CFLAGS += -DBOARD_$(BOARD) CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) CFLAGS += -DFFCONF_H=\"ports/stm32/mboot/ffconf.h\" +CFLAGS += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT +CFLAGS += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT CFLAGS += -DBUILDING_MBOOT=1 CFLAGS += -DBOOTLOADER_DFU_USB_VID=$(BOOTLOADER_DFU_USB_VID) -DBOOTLOADER_DFU_USB_PID=$(BOOTLOADER_DFU_USB_PID) @@ -91,6 +93,10 @@ endif $(BUILD)/lib/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN) LIB_SRC_C = \ lib/libc/string0.c \ + lib/littlefs/lfs1.c \ + lib/littlefs/lfs1_util.c \ + lib/littlefs/lfs2.c \ + lib/littlefs/lfs2_util.c \ lib/oofatfs/ff.c \ lib/oofatfs/ffunicode.c \ extmod/uzlib/crc32.c \ @@ -104,6 +110,7 @@ SRC_C = \ fsload.c \ gzstream.c \ vfs_fat.c \ + vfs_lfs.c \ drivers/bus/softspi.c \ drivers/bus/softqspi.c \ drivers/memory/spiflash.c \ diff --git a/ports/stm32/mboot/fsload.c b/ports/stm32/mboot/fsload.c index dc40a28ea..1e1ad7a04 100644 --- a/ports/stm32/mboot/fsload.c +++ b/ports/stm32/mboot/fsload.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019-2020 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 @@ -32,6 +32,10 @@ #if MBOOT_FSLOAD +#if !(MBOOT_VFS_FAT || MBOOT_VFS_LFS1 || MBOOT_VFS_LFS2) +#error Must enable at least one VFS component +#endif + static int fsload_program_file(bool write_to_flash) { // Parse DFU uint8_t buf[512]; @@ -183,27 +187,58 @@ int fsload_process(void) { if (elem[0] == mount_point) { uint32_t base_addr = get_le32(&elem[2]); uint32_t byte_len = get_le32(&elem[6]); + int ret; + union { + #if MBOOT_VFS_FAT + vfs_fat_context_t fat; + #endif + #if MBOOT_VFS_LFS1 + vfs_lfs1_context_t lfs1; + #endif + #if MBOOT_VFS_LFS2 + vfs_lfs2_context_t lfs2; + #endif + } ctx; + const stream_methods_t *methods; + #if MBOOT_VFS_FAT if (elem[1] == ELEM_MOUNT_FAT) { - vfs_fat_context_t ctx; - int ret = vfs_fat_mount(&ctx, base_addr, byte_len); + ret = vfs_fat_mount(&ctx.fat, base_addr, byte_len); + methods = &vfs_fat_stream_methods; + } else + #endif + #if MBOOT_VFS_LFS1 + if (elem[1] == ELEM_MOUNT_LFS1) { + ret = vfs_lfs1_mount(&ctx.lfs1, base_addr, byte_len); + methods = &vfs_lfs1_stream_methods; + } else + #endif + #if MBOOT_VFS_LFS2 + if (elem[1] == ELEM_MOUNT_LFS2) { + ret = vfs_lfs2_mount(&ctx.lfs2, base_addr, byte_len); + methods = &vfs_lfs2_stream_methods; + } else + #endif + { + // Unknown filesystem type + return -1; + } + + if (ret == 0) { + ret = fsload_validate_and_program_file(&ctx, methods, fname); + } + + // Flash LEDs based on success/failure of update + for (int i = 0; i < 4; ++i) { if (ret == 0) { - ret = fsload_validate_and_program_file(&ctx, &vfs_fat_stream_methods, fname); + led_state_all(7); + } else { + led_state_all(1); } - // Flash LEDs based on success/failure of update - for (int i = 0; i < 4; ++i) { - if (ret == 0) { - led_state_all(7); - } else { - led_state_all(1); - } - mp_hal_delay_ms(100); - led_state_all(0); - mp_hal_delay_ms(100); - } - return ret; + mp_hal_delay_ms(100); + led_state_all(0); + mp_hal_delay_ms(100); } - // Unknown filesystem type - return -1; + return ret; } elem += elem[-1]; } diff --git a/ports/stm32/mboot/fwupdate.py b/ports/stm32/mboot/fwupdate.py index b44ed772c..dab5fa663 100644 --- a/ports/stm32/mboot/fwupdate.py +++ b/ports/stm32/mboot/fwupdate.py @@ -1,9 +1,13 @@ # Update Mboot or MicroPython from a .dfu.gz file on the board's filesystem -# MIT license; Copyright (c) 2019 Damien P. George +# MIT license; Copyright (c) 2019-2020 Damien P. George import struct, time import uzlib, machine, stm +# Constants to be used with update_mpy +VFS_FAT = 1 +VFS_LFS1 = 2 +VFS_LFS2 = 3 FLASH_KEY1 = 0x45670123 FLASH_KEY2 = 0xCDEF89AB @@ -152,7 +156,7 @@ def update_mboot(filename): print("Programming finished, can now reset or turn off.") -def update_mpy(filename, fs_base, fs_len): +def update_mpy(filename, fs_base, fs_len, fs_type=VFS_FAT): # Check firmware is of .dfu.gz type try: with open(filename, "rb") as f: @@ -166,11 +170,8 @@ def update_mpy(filename, fs_base, fs_len): ELEM_TYPE_END = 1 ELEM_TYPE_MOUNT = 2 ELEM_TYPE_FSLOAD = 3 - ELEM_MOUNT_FAT = 1 mount_point = 1 - mount = struct.pack( - "<BBBBLL", ELEM_TYPE_MOUNT, 10, mount_point, ELEM_MOUNT_FAT, fs_base, fs_len - ) + mount = struct.pack("<BBBBLL", ELEM_TYPE_MOUNT, 10, mount_point, fs_type, fs_base, fs_len) fsup = struct.pack("<BBB", ELEM_TYPE_FSLOAD, 1 + len(filename), mount_point) + bytes( filename, "ascii" ) diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h index ef9af7854..37929665e 100644 --- a/ports/stm32/mboot/mboot.h +++ b/ports/stm32/mboot/mboot.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019-2020 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 @@ -23,6 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef MICROPY_INCLUDED_STM32_MBOOT_MBOOT_H +#define MICROPY_INCLUDED_STM32_MBOOT_MBOOT_H #include <stdint.h> #include <stddef.h> @@ -42,6 +44,8 @@ enum { enum { ELEM_MOUNT_FAT = 1, + ELEM_MOUNT_LFS1, + ELEM_MOUNT_LFS2, }; extern uint8_t _estack[ELEM_DATA_SIZE]; @@ -55,3 +59,5 @@ int do_write(uint32_t addr, const uint8_t *src8, size_t len); const uint8_t *elem_search(const uint8_t *elem, uint8_t elem_id); int fsload_process(void); + +#endif // MICROPY_INCLUDED_STM32_MBOOT_MBOOT_H diff --git a/ports/stm32/mboot/vfs.h b/ports/stm32/mboot/vfs.h index 9ee1c5ff3..6cf883a13 100644 --- a/ports/stm32/mboot/vfs.h +++ b/ports/stm32/mboot/vfs.h @@ -26,8 +26,12 @@ #ifndef MICROPY_INCLUDED_STM32_MBOOT_VFS_H #define MICROPY_INCLUDED_STM32_MBOOT_VFS_H -#include "lib/oofatfs/ff.h" #include "gzstream.h" +#include "mboot.h" + +#if MBOOT_VFS_FAT + +#include "lib/oofatfs/ff.h" typedef struct _vfs_fat_context_t { uint32_t bdev_base_addr; @@ -40,4 +44,53 @@ extern const stream_methods_t vfs_fat_stream_methods; int vfs_fat_mount(vfs_fat_context_t *ctx, uint32_t base_addr, uint32_t byte_len); +#endif + +#if MBOOT_VFS_LFS1 + +#include "lib/littlefs/lfs1.h" + +#define LFS_READ_SIZE (32) +#define LFS_PROG_SIZE (32) +#define LFS_LOOKAHEAD_SIZE (32) + +typedef struct _vfs_lfs1_context_t { + uint32_t bdev_base_addr; + struct lfs1_config config; + lfs1_t lfs; + struct lfs1_file_config filecfg; + uint8_t filebuf[LFS_PROG_SIZE]; + lfs1_file_t file; +} vfs_lfs1_context_t; + +extern const stream_methods_t vfs_lfs1_stream_methods; + +int vfs_lfs1_mount(vfs_lfs1_context_t *ctx, uint32_t base_addr, uint32_t byte_len); + +#endif + +#if MBOOT_VFS_LFS2 + +#include "lib/littlefs/lfs2.h" + +#define LFS_READ_SIZE (32) +#define LFS_PROG_SIZE (32) +#define LFS_CACHE_SIZE (4 * LFS_READ_SIZE) +#define LFS_LOOKAHEAD_SIZE (32) + +typedef struct _vfs_lfs2_context_t { + uint32_t bdev_base_addr; + struct lfs2_config config; + lfs2_t lfs; + struct lfs2_file_config filecfg; + uint8_t filebuf[LFS_CACHE_SIZE]; // lfs2 specific + lfs2_file_t file; +} vfs_lfs2_context_t; + +extern const stream_methods_t vfs_lfs2_stream_methods; + +int vfs_lfs2_mount(vfs_lfs2_context_t *ctx, uint32_t base_addr, uint32_t byte_len); + +#endif + #endif // MICROPY_INCLUDED_STM32_MBOOT_VFS_H diff --git a/ports/stm32/mboot/vfs_fat.c b/ports/stm32/mboot/vfs_fat.c index 20994c8b4..20de074f0 100644 --- a/ports/stm32/mboot/vfs_fat.c +++ b/ports/stm32/mboot/vfs_fat.c @@ -30,7 +30,7 @@ #include "mboot.h" #include "vfs.h" -#if MBOOT_FSLOAD +#if MBOOT_FSLOAD && MBOOT_VFS_FAT #if FF_MAX_SS == FF_MIN_SS #define SECSIZE (FF_MIN_SS) @@ -119,4 +119,4 @@ const stream_methods_t vfs_fat_stream_methods = { vfs_fat_stream_read, }; -#endif // MBOOT_FSLOAD +#endif // MBOOT_FSLOAD && MBOOT_VFS_FAT diff --git a/ports/stm32/mboot/vfs_lfs.c b/ports/stm32/mboot/vfs_lfs.c new file mode 100644 index 000000000..dec7c015f --- /dev/null +++ b/ports/stm32/mboot/vfs_lfs.c @@ -0,0 +1,177 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 <string.h> + +#include "py/mphal.h" +#include "mboot.h" +#include "vfs.h" + +#if MBOOT_FSLOAD && (MBOOT_VFS_LFS1 || MBOOT_VFS_LFS2) + +#if MBOOT_VFS_LFS1 +#if MBOOT_VFS_LFS2 +#error Unsupported +#endif + +#define LFSx_MACRO(s) LFS1##s +#define LFSx_API(x) lfs1_ ## x +#define VFS_LFSx_CONTEXT_T vfs_lfs1_context_t +#define VFS_LFSx_MOUNT vfs_lfs1_mount +#define VFS_LFSx_STREAM_METHODS vfs_lfs1_stream_methods + +#define SUPERBLOCK_MAGIC_OFFSET (40) +#define SUPERBLOCK_BLOCK_SIZE_OFFSET (28) +#define SUPERBLOCK_BLOCK_COUNT_OFFSET (32) + +static uint8_t lfs_read_buffer[LFS_READ_SIZE]; +static uint8_t lfs_prog_buffer[LFS_PROG_SIZE]; +static uint8_t lfs_lookahead_buffer[LFS_LOOKAHEAD_SIZE / 8]; + +#else + +#define LFSx_MACRO(s) LFS2##s +#define LFSx_API(x) lfs2_ ## x +#define VFS_LFSx_CONTEXT_T vfs_lfs2_context_t +#define VFS_LFSx_MOUNT vfs_lfs2_mount +#define VFS_LFSx_STREAM_METHODS vfs_lfs2_stream_methods + +#define SUPERBLOCK_MAGIC_OFFSET (8) +#define SUPERBLOCK_BLOCK_SIZE_OFFSET (24) +#define SUPERBLOCK_BLOCK_COUNT_OFFSET (28) + +static uint8_t lfs_read_buffer[LFS_CACHE_SIZE]; +static uint8_t lfs_prog_buffer[LFS_CACHE_SIZE]; +static uint8_t lfs_lookahead_buffer[LFS_LOOKAHEAD_SIZE]; + +#endif + +static int dev_read(const struct LFSx_API (config) * c, LFSx_API(block_t) block, LFSx_API(off_t) off, void *buffer, LFSx_API(size_t) size) { + VFS_LFSx_CONTEXT_T *ctx = c->context; + if (0 <= block && block < ctx->config.block_count) { + do_read(ctx->bdev_base_addr + block * ctx->config.block_size + off, size, buffer); + return LFSx_MACRO(_ERR_OK); + } + return LFSx_MACRO(_ERR_IO); +} + +static int dev_prog(const struct LFSx_API (config) * c, LFSx_API(block_t) block, LFSx_API(off_t) off, const void *buffer, LFSx_API(size_t) size) { + return LFSx_MACRO(_ERR_IO); +} + +static int dev_erase(const struct LFSx_API (config) * c, LFSx_API(block_t) block) { + return LFSx_MACRO(_ERR_IO); +} + +static int dev_sync(const struct LFSx_API (config) * c) { + return LFSx_MACRO(_ERR_OK); +} + +int VFS_LFSx_MOUNT(VFS_LFSx_CONTEXT_T *ctx, uint32_t base_addr, uint32_t byte_len) { + // Read start of superblock. + uint8_t buf[48]; + do_read(base_addr, sizeof(buf), buf); + + // Verify littlefs and detect block size. + if (memcmp(&buf[SUPERBLOCK_MAGIC_OFFSET], "littlefs", 8) != 0) { + return -1; + } + uint32_t block_size = get_le32(&buf[SUPERBLOCK_BLOCK_SIZE_OFFSET]); + uint32_t block_count = get_le32(&buf[SUPERBLOCK_BLOCK_COUNT_OFFSET]); + + // Verify size of volume. + if (block_size * block_count != byte_len) { + return -1; + } + + ctx->bdev_base_addr = base_addr; + + struct LFSx_API (config) *config = &ctx->config; + memset(config, 0, sizeof(*config)); + + config->context = ctx; + + config->read = dev_read; + config->prog = dev_prog; + config->erase = dev_erase; + config->sync = dev_sync; + + config->read_size = LFS_READ_SIZE; + config->prog_size = LFS_PROG_SIZE; + config->block_size = block_size; + config->block_count = byte_len / block_size; + + #if MBOOT_VFS_LFS1 + config->lookahead = LFS_LOOKAHEAD_SIZE; + config->read_buffer = lfs_read_buffer; + config->prog_buffer = lfs_prog_buffer; + config->lookahead_buffer = lfs_lookahead_buffer; + #else + config->block_cycles = 100; + config->cache_size = LFS_CACHE_SIZE; + config->lookahead_size = LFS_LOOKAHEAD_SIZE; + config->read_buffer = lfs_read_buffer; + config->prog_buffer = lfs_prog_buffer; + config->lookahead_buffer = lfs_lookahead_buffer; + #endif + + int ret = LFSx_API(mount)(&ctx->lfs, &ctx->config); + if (ret < 0) { + return -1; + } + return 0; +} + +static int vfs_lfs_stream_open(void *stream_in, const char *fname) { + VFS_LFSx_CONTEXT_T *ctx = stream_in; + memset(&ctx->file, 0, sizeof(ctx->file)); + memset(&ctx->filecfg, 0, sizeof(ctx->filecfg)); + ctx->filecfg.buffer = &ctx->filebuf[0]; + LFSx_API(file_opencfg)(&ctx->lfs, &ctx->file, fname, LFSx_MACRO(_O_RDONLY), &ctx->filecfg); + return 0; +} + +static void vfs_lfs_stream_close(void *stream_in) { + VFS_LFSx_CONTEXT_T *ctx = stream_in; + LFSx_API(file_close)(&ctx->lfs, &ctx->file); +} + +static int vfs_lfs_stream_read(void *stream_in, uint8_t *buf, size_t len) { + VFS_LFSx_CONTEXT_T *ctx = stream_in; + LFSx_API(ssize_t) sz = LFSx_API(file_read)(&ctx->lfs, &ctx->file, buf, len); + if (sz < 0) { + return -1; + } + return sz; +} + +const stream_methods_t VFS_LFSx_STREAM_METHODS = { + vfs_lfs_stream_open, + vfs_lfs_stream_close, + vfs_lfs_stream_read, +}; + +#endif // MBOOT_FSLOAD && (MBOOT_VFS_LFS1 || MBOOT_VFS_LFS2) |