samd: Add support for VfsRom filesystem for SAMD21 and SAMD51.

The flash driver is update to support the new `mp_vfs_rom_ioctl()`
function, and the buffer protocol is added to `samd_flash_type` (it is
needed for VfsRom on devices without external flash).

For SAMD21, only boards with external SPI flash have VfsRom enabled, due
to size constraints.  For such boards, the VfsRom filesystem has a size of
12k and is placed at the upper end of the flash.  The `onewire`, `ds18x20`
and `dht` drivers have been removed from frozen bytecode as they can be
placed into the VfsRom files when needed.

For SAMD51, the VfsRom filesystem has a default size of 64k for SAMD51x19
and 256K for SAMD51x20.  It is placed at the upper end of the flash.
For boards with external SPI flash, the code size is reduced from 496K to
432K.  If that is not sufficient for some boards or configurations, it can
be changed for each board or board variant.

Tested with ADAFRUIT_ITSYBITSY_M0_EXPRESS, ADAFRUIT_ITSYBITSY_M4_EXPRESS,
SPARKFUN_SAMD51_THING_PLUS, SEEED_XIAO_SAMD21, SAMD_GENERIC_D51X19, and
SAMD_GENERIC_D51X20.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
robert-hh
2024-11-19 08:48:29 +01:00
committed by Damien George
parent b857a9131e
commit c07b178dbd
26 changed files with 197 additions and 62 deletions

View File

@@ -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=_micropy_hw_romfs_part0_size=$(MICROPY_HW_ROMFS_BYTES)
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_ROMFS_BYTES),0)
CFLAGS += -DMICROPY_VFS_ROM=0
endif
# Flags for optional C++ source code
CXXFLAGS += $(filter-out -std=c99,$(CFLAGS))

View File

@@ -5,4 +5,4 @@ TEXT0 = 0x2000
# The ?='s allow overriding in mpconfigboard.mk.
# MicroPython settings
MICROPY_HW_CODESIZE ?= 248K
MICROPY_HW_CODESIZE ?= 236K

View File

@@ -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_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 432K

View File

@@ -5,4 +5,4 @@ TEXT0 = 0x2000
# The ?='s allow overriding in mpconfigboard.mk.
# MicroPython settings
MICROPY_HW_CODESIZE ?= 248K
MICROPY_HW_CODESIZE ?= 236K

View File

@@ -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_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 432K

View File

@@ -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_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 432K

View File

@@ -1,2 +1,2 @@
CFLAGS += -DMICROPY_HW_SPIFLASH=1
MICROPY_HW_CODESIZE ?= 232K
MICROPY_HW_CODESIZE ?= 236K

View File

@@ -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_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 432K

View File

@@ -3,4 +3,4 @@ CMSIS_MCU = SAMD21J18A
LD_FILES = boards/samd21x18a.ld sections.ld
TEXT0 = 0x2000
MICROPY_HW_CODESIZE ?= 248K
MICROPY_HW_CODESIZE ?= 236K

View File

@@ -6,6 +6,6 @@ TEXT0 = 0x4000
# The ?='s allow overriding in mpconfigboard.mk.
# MicroPython settings
# The size of a MCU flash filesystem will be
# 496k - MICROPY_HW_CODESIZE - MICROPY_HW_VFSROMSIZE
# The default for MICROPY_HW_VFSROMSIZE is 64K
# 496k - MICROPY_HW_CODESIZE - MICROPY_HW_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 368K

View File

@@ -7,5 +7,6 @@ TEXT0 = 0x4000
# MicroPython settings
# The size of a MCU flash filesystem will be
# 1008k - MICROPY_HW_CODESIZE
# The default for MICROPY_HW_VFSROMSIZE is 64K
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 752K
MICROPY_HW_ROMFS_BYTES ?= 256K

View File

@@ -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_ROMFS_BYTES
# The default for MICROPY_HW_ROMFS_BYTES is 64K
MICROPY_HW_CODESIZE ?= 432K

View File

@@ -5,4 +5,4 @@ TEXT0 = 0x2000
# The ?='s allow overriding in mpconfigboard.mk.
# MicroPython settings
MICROPY_HW_CODESIZE ?= 232K
MICROPY_HW_CODESIZE ?= 236K

View File

@@ -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_ROMFS_BYTES
MICROPY_HW_CODESIZE ?= 752K
MICROPY_HW_ROMFS_BYTES ?= 256K

View File

@@ -3,8 +3,8 @@
*/
/*
_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as
MICROPY_HW_CODESIZE and is set in Makefile
_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk
as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile.
*/
_flashsize = 256K; /* The physical flash size */
@@ -21,8 +21,17 @@ MEMORY
_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
_sstack = _estack - 8K;
_oflash_fs = ORIGIN(FLASH) + _codesize;
_sflash_fs = _flashsize - _codesize - _bootloader;
/*
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 and
the origin beyond the end of the flash. That does not matter since
these devices do not use the MCU flash file system.
*/
_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size;
_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size;
_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize;
_sheap = _ebss;
_eheap = _sstack;

View File

@@ -3,8 +3,8 @@
*/
/*
_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as
MICROPY_HW_CODESIZE and is set in Makefile
_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk
as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile.
*/
_flashsize = 512K; /* The physical flash size */
@@ -21,8 +21,17 @@ MEMORY
_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
_sstack = _estack - 16K;
_oflash_fs = ORIGIN(FLASH) + _codesize;
_sflash_fs = _flashsize - _codesize - _bootloader;
/*
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 and
the origin beyond the end of the flash. That does not matter since
these devices do not use the MCU flash file system.
*/
_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size;
_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size;
_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize;
_sheap = _ebss;
_eheap = _sstack;

View File

@@ -3,8 +3,8 @@
*/
/*
_codesize is defined in mpconfigmcu.mk or mpconfigboard.mk as
MICROPY_HW_CODESIZE and is set in Makefile
_codesize and _micropy_hw_romfs_part0_size are defined in mpconfigmcu.mk or mpconfigboard.mk
as MICROPY_HW_CODESIZE and MICROPY_HW_ROMFS_BYTES and are set in Makefile.
*/
_flashsize = 1024K; /* The physical flash size */
@@ -21,8 +21,17 @@ MEMORY
_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
_sstack = _estack - 16K;
_oflash_fs = ORIGIN(FLASH) + _codesize;
_sflash_fs = _flashsize - _codesize - _bootloader;
/*
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 and
the origin beyond the end of the flash. That does not matter since
these devices do not use the MCU flash file system.
*/
_oflash_fs = ORIGIN(FLASH) + _codesize + _micropy_hw_romfs_part0_size;
_sflash_fs = _flashsize - _codesize - _bootloader - _micropy_hw_romfs_part0_size;
_micropy_hw_romfs_part0_start = ORIGIN(FLASH) + _codesize;
_sheap = _ebss;
_eheap = _sstack;

View File

@@ -1,5 +1,2 @@
include("$(PORT_DIR)/boards/manifest.py")
include("$(MPY_DIR)/extmod/asyncio")
require("onewire")
require("ds18x20")
require("dht")

View File

@@ -2,11 +2,6 @@
#include "samd21.h"
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES)
#if MICROPY_HW_CODESIZE == 248
#define SAMD21_EXTRA_FEATURES 1
#else
#define SAMD21_EXTRA_FEATURES 0
#endif
// MicroPython emitters
#define MICROPY_EMIT_THUMB (SAMD21_EXTRA_FEATURES)

View File

@@ -6,8 +6,13 @@ MPY_CROSS_MCU_ARCH = armv6m
MICROPY_HW_CODESIZE ?= 184K
ifeq ($(MICROPY_HW_CODESIZE), 248K)
ifeq ($(MICROPY_HW_CODESIZE), 236K)
FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py
MICROPY_HW_ROMFS_BYTES ?= 12K
CFLAGS_MCU += -DSAMD21_EXTRA_FEATURES=1
else
MICROPY_HW_ROMFS_BYTES ?= 0
CFLAGS_MCU += -DSAMD21_EXTRA_FEATURES=0
endif
MICROPY_VFS_LFS1 ?= 1

View File

@@ -1,5 +1,2 @@
include("$(PORT_DIR)/boards/manifest.py")
include("$(MPY_DIR)/extmod/asyncio")
require("onewire")
require("ds18x20")
require("dht")

View File

@@ -21,10 +21,10 @@ unsigned long trng_random_u32(void);
#endif
// 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 (2048) //

View File

@@ -5,6 +5,7 @@ CFLAGS_MCU += -DCFG_TUSB_MCU=OPT_MCU_SAMD51
MPY_CROSS_MCU_ARCH = armv7m
MICROPY_HW_CODESIZE ?= 368K
MICROPY_HW_ROMFS_BYTES ?= 64K
MICROPY_VFS_LFS2 ?= 1
MICROPY_VFS_FAT ?= 1

View File

@@ -86,6 +86,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

View File

@@ -26,11 +26,13 @@
#include <stdio.h>
#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,23 +100,14 @@ 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;
}
@@ -131,7 +146,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 +191,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 _micropy_hw_romfs_part0_start, _micropy_hw_romfs_part0_size;
#define MICROPY_HW_ROMFS_BASE ((uint32_t)&_micropy_hw_romfs_part0_start)
#define MICROPY_HW_ROMFS_BYTES ((uint32_t)&_micropy_hw_romfs_part0_size)
#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

View File

@@ -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_I2C_TARGET || MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_UART