概述
总体的思路是:
自顶向下逐步启用mpy-cross编译,将Python程序集成到固件中
自底向上逐步添加sfud组件并启用lfs
合龙,创建mm32f3.flash模块,封装sfud,并由集成到固件中的Python程序调用mm32f3.flash模块。
启用frozen_module
MicroPython加载lfs使用了同之前加载fatfs不同的方式,通过向固件程序中集成Python语言编写的脚本来加载lfs文件系统。在C语言编写的MicroPython固件中加载Python语言程序的机制,就是所谓的“frozen”。在本节中,期望实现frozen机制,先引导一个普通的Python脚本文件,实现在启动REPL之前闪烁电路板小灯的功能。在后续准备好底层文件系统后,再将引导Python文件中的内容替换成加载文件系统的脚本。
新建manifest.py文件
在ports/mm32f3-lfs-spiflash/boards目录下创建manifest.py文件,指定编译工程的过程中,预先处理ports/mm32f3-lfs-spiflash/modules目录下的Python源文件。实际上,ports/mm32f3-lfs-spiflash/modules目录下已经创建了_boot.py文件。
编写manifest.py文件内容有:
freeze("$(PORT_DIR)/modules")
更新mpconfigboard.mk文件
在ports/mm32f3-lfs-spiflash/boards/plus-f3270/mpconfigboard.mk文件中,添加脚本,引用新建的manifest.py文件,将其集成在编译工程的过程中。
在已有mpconfigboard.mk文件中添加脚本:
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
更新mpconfigport.h文件
在现有移植项目的mpconfigport.h文件中,添加配置宏,启用MicroPython内核中的frozen机制:
#define MICROPY_MODULE_FROZEN (1) /* enable pyexec_frozen_module() in pyexec.c */
#define MICROPY_MODULE_FROZEN_MPY (1)
更新main.c文件
在现有移植项目中的main.c文件中,删除原有从sd卡加载文件系统相关的代码,在固件的执行过程中添加执行_boot.py脚本的语句:
#include "lib/mp-readline/readline.h"
...
int main(void)
{
...
for (;;)
{
...
// Initialise sub-systems.
readline_init0();
// Execute _boot.py to set up the filesystem.
pyexec_frozen_module("_boot.py");
...
}
}
实验
试着编一下整个项目,应该是能编通的:
MindMotion@PF2LD92H MSYS /d/_git_repos/micropython-su/micropython-1.16/ports/mm32f3-lfs-spiflash
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
GEN build-plus-f3270/genhdr/qstrdefs.collected.h
QSTR not updated
mkdir -p build-plus-f3270/build-plus-f3270/
MPY _boot.py
GEN build-plus-f3270/frozen_content.c
CC build-plus-f3270/frozen_content.c
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
135084 860 3396 139340 2204c build-plus-f3270/firmware.elf
从输出的信息中可以看到,编译过程已经处理了_boot.py文件,生成并编译了fromzen_content.c文件。
再试着改写_boot.py文件,控制板子上的小灯闪烁,以验证frozen的功能已经启用。
改写_boot.py文件内容如下:
import time
from machine import Pin
led0 = Pin('PH2', mode=Pin.OUT_PUSHPULL, value=1)
for i in range(10):
time.sleep_ms(100)
led0(1-led0())
重新编译,下载,运行。实际可以看到板子上的LED灯闪了5次,之后进入REPL。验证frozen功能已经正常启用。
添加和移植sfud组件
sfud组件是一个开源的管理spiflash存储芯片的组件,面向市面上主流的spiflash存储芯片,提供一系列例如初始化、擦除块、读块、写块等标准操作接口。使用sfud访问spiflash存储芯片,而不是直接使用spiflash存储芯片的驱动程序,可以提高上层应用对底层设备的抽象程度,便于复用代码。在很多基于微控制器的SDK软件包中,都提供了sfud的移植样例工程,这就为在MicroPython中通过sfud使用spiflash存储芯片提供了便利。
添加sfud组件源码
在MicroPython代码包的\lib目录下创建sfud目录,将sfud组件的源码复制在其中:
sfud.c
sfud_sfdp.c
sfud.h
sfud_def.h
sfud_flash_def.h
添加移植sfud组件源码
另外,还需要在具体移植板子项目的目录\ports\mm32f3-lfs-spiflash\boards\plus-f3270下,添加sfud组件的移植源程序文件:
sfud_port.c
sfud_cfg.h
新添加的这两个文件在MindSDK中plus-f3270板子的spiflash_sfud_spi样例工程中都可以找到。
还有一个细节,需要更新\ports\mm32f3-lfs-spiflash\boards\plus-f3270目录下配置板子相关的文件。
board_init.h文件,定义SPI接口的映射:
/* SPI3. */
#define BOARD_FLASH_SPI_PORT SPI2
#define BOARD_FLASH_SPI_BAUDRATE 400000u /* 400khz. */
#define BOARD_FLASH_SPI_FREQ CLOCK_APB1_FREQ
#define BOARD_FLASH_CS_GPIO_PORT GPIOE
#define BOARD_FLASH_CS_GPIO_PIN GPIO_PIN_3
clock_init.c文件,启用总线访问SPI外设的时钟:
void BOARD_InitBootClocks(void)
{
...
/* SPI2. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI2, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI2);
}
pin_init.c文件,配置SPI外设引脚复用功能:
void BOARD_InitPins(void)
{
...
/* PE3 - SPI_CS. */
gpio_init.Pins = GPIO_PIN_3;
gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &gpio_init);
GPIO_PinAFConf(GPIOE, gpio_init.Pins, GPIO_AF_15);
GPIO_SetBits(GPIOE, gpio_init.Pins);
/* PB10 - SPI_SCK. */
gpio_init.Pins = GPIO_PIN_10;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);
/* PB14 - SPI_MISO. */
gpio_init.Pins = GPIO_PIN_14;
gpio_init.PinMode = GPIO_PinMode_In_PullUp;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);
/* PB15 - SPI_MOSI. */
gpio_init.Pins = GPIO_PIN_15;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);
}
更新Makefile
将新增sfud组件及移植源程序的文件添加到Makefile文件中,进入编译过程。
# includepath.
...
INC += -I$(TOP)/lib/sfud
...
SRC_BRD_C += \
...
$(BOARD_DIR)/sfud_port.c \
...
...
SRC_C += \
...
lib/sfud/sfud.c \
lib/sfud/sfud_sfdp.c \
...
...
实验
编译一下工程,确保当前添加到MicroPython中的代码不会产生编译错误。
MindMotion@PF2LD92H MSYS /d/_git_repos/micropython-su/micropython-1.16/ports/mm32f3-lfs-spiflash
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
GEN build-plus-f3270/genhdr/qstrdefs.collected.h
QSTR not updated
CC boards/plus-f3270/sfud_port.c
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
135056 860 3396 139312 22030 build-plus-f3270/firmware.elf
启用lfs组件
MicroPython的lfs文件系统,实际上仅仅是一个文件系统框架,并没有像fatfs一样,通过源代码静态绑定。因此,可以独立启用lfs组件,而暂不实现具体的移植。
更新mpconfigboard.mk文件
lfs组件相关的源码,已经存放在MicroPython代码仓库的\extmod目录下。在现有工程的mpconfigboard.mk文件中,添加 配置开关,让编译过程能够编译lfs相关的源代码。
MICROPY_VFS_LFS2 ?= 1
更新mpconfigport.h文件
在现有移植项目的mpconfigport.h文件中,添加配置宏,启用MicroPython内核中的lfs组件,并添加部分映射对象:
// Use VfsLfs2's types for fileio/textio
#define mp_type_fileio mp_type_vfs_lfs2_fileio
#define mp_type_textio mp_type_vfs_lfs2_textio
这是为了在os类模块中,向vfs(虚拟文件系统,virtual file system)绑定io过程使用lfs相关的方法。
更新moduos.c文件
在后面集成实验时,发现os类模块的几个函数尚未实现,赶紧在这里补充说明。
在现有移植项目的moduos.c文件中,解锁os类模块中与vfs相关的属性方法,特别是mount()和VfsLfs2()。
...
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
#include "extmod/vfs_lfs.h"
...
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
//{ MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
{ MP_ROM_QSTR(MP_QSTR_rename),MP_ROM_PTR(&mp_vfs_rename_obj)},
{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
{ MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },
#if 1 /* unlock for vfs and lfs. */
/// \constant sep - separation character used in paths
{ MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
#if MICROPY_HW_ENABLE_RNG
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
#endif
// these are MicroPython extensions
//{ MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) },
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
#endif
#if MICROPY_VFS_FAT
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
#endif
#if MICROPY_VFS_LFS1
{ MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
#endif
#if MICROPY_VFS_LFS2
{ MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
#endif
};
实验
试着编译一下当前的移植工程,报错,说在lfs_get_mtime函数中引用的mp_hal_time_ns函数未被定义。
CC mphalport.c
CC ../../lib/mp-readline/readline.c
CC ../../lib/utils/gchelper_native.c
CC ../../lib/utils/pyexec.c
CC ../../lib/utils/stdout_helpers.c
CC ../../lib/timeutils/timeutils.c
CC fatfs_port.c
CC boards/plus-f3270/machine_pin_board_pins.c
CC ../../drivers/bus/softspi.c
LINK build-plus-f3270/firmware.elf
C:\msys64\usr\gcc-arm-none-eabi-10-2020-q4-major\bin\arm-none-eabi-ld.exe: build-plus-f3270/extmod/vfs_lfs.o: in function `lfs_get_mtime':
vfs_lfs.c:(.text.lfs_get_mtime+0x4): undefined reference to `mp_hal_time_ns'
make: *** [Makefile:213: build-plus-f3270/firmware.elf] Error 1
顾名思义,lfs_get_mtime函数是为lfs创建文件时提供时间戳信息的,对主要功能影响不大,所以可以用一个“假”的实现消除错误。在mphalport.h文件中定义mp_hal_time_ns函数:
/* return the current ns from very start. */
static inline uint64_t mp_hal_time_ns(void)
{
return 0u;
}
再编译一次,就应该通过了。
MindMotion@PF2LD92H MSYS /d/_git_repos/micropython-su/micropython-1.16/ports/mm32f3-lfs-spiflash
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
CC ../../py/mpprint.c
CC ../../py/modmicropython.c
CC ../../extmod/moduasyncio.c
CC ../../extmod/machine_pulse.c
CC ../../extmod/machine_i2c.c
CC ../../extmod/machine_spi.c
CC ../../extmod/modbluetooth.c
CC ../../extmod/vfs_posix.c
CC ../../extmod/vfs_posix_file.c
CC ../../extmod/vfs_fat_diskio.c
CC ../../extmod/vfs_lfs.c
CC ../../extmod/utime_mphal.c
CC ../../lib/utils/printf.c
CC modmachine.c
CC machine_spi.c
CC machine_i2c.c
CC mphalport.c
CC ../../lib/mp-readline/readline.c
CC ../../lib/utils/pyexec.c
CC ../../lib/utils/stdout_helpers.c
CC boards/plus-f3270/machine_pin_board_pins.c
CC ../../drivers/bus/softspi.c
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
174792 988 10572 186352 2d7f0 build-plus-f3270/firmware.elf
创建flash类模块
这里需要创建一个同具体芯片平台相关的类模块,用以包含flash子类。实际上,这个flash可以是片内flash,也可以是片外flash。早期的MicroPython是运行在使用STM32F4微控制器作为主控芯片的PyBoard上,PyBoard板子没有搭载片外flash,就是用片内flash加载文件系统,因此,将flash作为芯片平台子类的做法就作为传统保留了下来。
创建mm32f3_flash.c文件
在\ports\mm32f3-lfs-spiflash目录下创建mm32f3_flash.c文件,用于实现flash子类。flash子类中必须要实现的几个函数,包括make_new()、readblocks()、writeblocks()和ioctl,内部都是通过调用sfud组件的接口访问底层的spiflash存储芯片。spiflash存储芯片的差异性已经被sfud覆盖掉了,所以实际上,当我从mm32f5移植项目(一个使用sfud组件访问qspiflash存储芯片的项目)中复制出mm32f5_flash.c文件时,只是将其中的mm32f5的字符串改成了mm32f3,并停用了其中一个激活4线SPI功能的sfud调用而已。
...
STATIC const mp_rom_map_elem_t mm32f3_flash_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&mm32f3_flash_readblocks_obj) },
{ MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&mm32f3_flash_writeblocks_obj) },
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mm32f3_flash_ioctl_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mm32f3_flash_locals_dict, mm32f3_flash_locals_dict_table);
const mp_obj_type_t mm32f3_flash_type = {
{ &mp_type_type },
.name = MP_QSTR_Flash,
.make_new = mm32f3_flash_make_new,
.locals_dict = (mp_obj_dict_t *)&mm32f3_flash_locals_dict,
};
至于xxxx_flash.c文件中各个属性方法的实现方法和内容,可以参阅具体的代码。
创建modmm32f3.c/.h文件
前文提到,flash类模块需要作为同主控芯片相关的一个类的子类集成在MicroPython内核中。这里就创建一个仅包含flash类模块的mm32f3类模块。
创建modmm32f3.c文件,并编写代码:
#include "py/runtime.h"
#include "modmm32f3.h"
STATIC const mp_rom_map_elem_t mm32f3_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mm32f3) },
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&mm32f3_flash_type) },
};
STATIC MP_DEFINE_CONST_DICT(mm32f3_module_globals, mm32f3_module_globals_table);
const mp_obj_module_t mp_module_mm32f3 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mm32f3_module_globals,
};
创建modmm32f3.h文件,并编写代码:
#ifndef MICROPY_INCLUDED_MM32F3_MODMM32F3_H
#define MICROPY_INCLUDED_MM32F3_MODMM32F3_H
#include "py/obj.h"
extern const mp_obj_type_t mm32f3_flash_type;
extern const mp_obj_module_t mp_module_mm32f3;
#endif // MICROPY_INCLUDED_MM32F3_MODMM32F3_H
更新mpconfigport.h文件
将新建的mm32f3模块添加到MicroPython内核的内建模块当中。
在当前移植项目的mpconfigport.h文件中,添加源代码:
...
extern const struct _mp_obj_module_t mp_module_mm32f3;
#define MICROPY_PORT_BUILTIN_MODULES \
...
{ MP_ROM_QSTR(MP_QSTR_mm32f3), MP_ROM_PTR(&mp_module_mm32f3) }, \
...
更新Makefile文件
在当前移植项目的Makefile中,添加新建文件:
...
SRC_C += \
...
modmm32f3.c \
mm32f3_flash.c \
...
# list of sources for qstr extraction
SRC_QSTR += modmachine.c \
...
modmm32f3.c \
mm32f3_flash.c \
...
实验
试着编译一下当前的移植工程,应该是可以编通不报错的。
MindMotion@PF2LD92H MSYS /d/_git_repos/micropython-su/micropython-1.16/ports/mm32f3-lfs-spiflash
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
GEN build-plus-f3270/genhdr/qstr.i.last
GEN build-plus-f3270/genhdr/qstr.split
GEN build-plus-f3270/genhdr/qstrdefs.collected.h
QSTR updated
...
CC mm32f3_flash.c
CC modmm32f3.c
...
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
141004 988 3916 145908 239f4 build-plus-f3270/firmware.elf
此时,可以将固件下载到板子上,然后试着手工在REPL中逐行输入脚本加载文件系统。在REPL中输入Python脚本进行单步调试,如下:
MicroPython v1.16 on 2022-07-30; PLUS-F3270 with MM32F3277G9P
Type "help()" for more information.
>>>
>>>
>>>
>>>
>>> import os
>>> dir(os)
['__name__', 'remove', 'sep', 'VfsFat', 'VfsLfs2', 'chdir', 'getcwd', 'ilistdir', 'listdir', 'mkdir', 'mount', 'rename', 'rmdir', 'stat', 'statvfs', 'sync', 'umount', 'unlink']
>>> import mm32f3
>>> dir(mm32f3)
['__name__', 'Flash']
>>> bdev=mm32f3.Flash()
[SFUD](../../lib/sfud/sfud.c:116) Start initialize Serial Flash Universal Driver(SFUD) V1.1.0.
[SFUD](../../lib/sfud/sfud.c:117) You can get the latest version on https://github.com/armink/SFUD .
[SFUD](../../lib/sfud/sfud.c:865) The flash device manufacturer ID is 0xFF, memory type ID is 0xFF, capacity ID is 0xFF.
[SFUD](../../lib/sfud/sfud_sfdp.c:131) Check SFDP header is OK. The reversion isV1.0, NPN is 0.
[SFUD](../../lib/sfud/sfud_sfdp.c:173) Check JEDEC basic flash parameter headeris OK. The table id is 0, reversion is V1.0, length is 9, parameter table pointer is 0x000080.
[SFUD](../../lib/sfud/sfud_sfdp.c:203) JEDEC basic flash parameter table info:
[SFUD](../../lib/sfud/sfud_sfdp.c:204) MSB-LSB 3 2 1 0
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0001] 0xFF 0xF1 0x20 0xE5
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0002] 0x07 0xFF 0xFF 0xFF
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0003] 0x6B 0x08 0xEB 0x44
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0004] 0xBB 0x42 0x3B 0x08
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0005] 0xFF 0xFF 0xFF 0xFE
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0006] 0x00 0x00 0xFF 0xFF
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0007] 0xEB 0x21 0xFF 0xFF
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0008] 0x52 0x0F 0x20 0x0C
[SFUD](../../lib/sfud/sfud_sfdp.c:206) [0009] 0x00 0x00 0xD8 0x10
[SFUD](../../lib/sfud/sfud_sfdp.c:215) 4 KB Erase is supported throughout the device. Command is 0x20.
[SFUD](../../lib/sfud/sfud_sfdp.c:234) Write granularity is 64 bytes or larger.
[SFUD](../../lib/sfud/sfud_sfdp.c:245) Target flash status register is non-volatile.
[SFUD](../../lib/sfud/sfud_sfdp.c:271) 3-Byte only addressing.
[SFUD](../../lib/sfud/sfud_sfdp.c:305) Capacity is 16777216 Bytes.
[SFUD](../../lib/sfud/sfud_sfdp.c:311) Flash device supports 4KB block erase. Command is 0x20.
[SFUD](../../lib/sfud/sfud_sfdp.c:311) Flash device supports 32KB block erase. Command is 0x52.
[SFUD](../../lib/sfud/sfud_sfdp.c:311) Flash device supports 64KB block erase. Command is 0xD8.
[SFUD]Find a flash chip. Size is 16777216 bytes.
[SFUD](../../lib/sfud/sfud.c:844) Flash device reset success.
[SFUD]SPI Flash flash device is initialize success.
>>> os.VfsLfs2.mkfs(bdev, progsize=256)
>>> vfs=os.VfsLfs2(bdev, progsize=256)
>>> os.mount(vfs,'/')
>>> os.listdir()
[]
>>> with open('hello', 'w') as f:
... f.write('hello')
...
5
>>> os.listdir()
['hello']
>>> os.sync()
>>> os.listdir()
['hello']
>>>
看起来,文件系统已经准备好了。接下来就是让MicroPython启动的时候自动加载文件系统。
改写_boot.py文件加载lfs
将上述手动加载文件系统的脚本写到之前创建的_boot.py文件中:
import os
import mm32f3
bdev = mm32f3.Flash()
try:
vfs = os.VfsLfs2(bdev, progsize=256)
except:
os.VfsLfs2.mkfs(bdev, progsize=256)
vfs = os.VfsLfs2(bdev, progsize=256)
os.mount(vfs, "/")
重新编译工程,正常情况下应该通过编译,无错误。
此时整个工程已经基本移植成功了,可以关掉sfud的调试选项。重新编译工程,下载固件到开发板,在REPL中可以看到,在欢迎信息之前没有报错信息,系统正常被加载。
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
GEN build-plus-f3270/genhdr/qstrdefs.collected.h
QSTR not updated
CC mm32f3_flash.c
CC ../../lib/sfud/sfud.c
CC ../../lib/sfud/sfud_sfdp.c
CC boards/plus-f3270/sfud_port.c
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
169528 988 10316 180832 2c260 build-plus-f3270/firmware.elf
下载代码运行。
使用Thonny IDE建立连接
尝试通过Thonny创建Python脚本文件,保存到MicroPython设备上。
图1 使用Thonny查看flash文件系统
如图1所示,当要使用Thonny保存Python脚本文件时,Thonny的文件浏览器已经可以看到之前实验中创建的hello文件了。尝试保存新脚本为main.py文件,是成功的。至此,说明移植成功。大功告成。
后记
启用文件系统之后,为了方便用户使用,还需要继续做两件事:
芯片上电之后,MicroPython能自动运行到main.py函数。
为了防止在main.py中进入无限循环后无法再同Thonny建立连接,需要在文件系统中创建boot.py文件,选择启动模式,在必要的情况下跳过main.py直接进入REPL。
改写main.c文件
在MicroPython的启动过程中,添加执行boot.py和main.py文件的流程,位于进入REPL之前:
pyexec_file_if_exists("boot.py");
重新编译工程,并下载到开发板中。
MindMotion@PF2LD92H MSYS /d/_git_repos/micropython-su/micropython-1.16/ports/mm32f3-lfs-spiflash
$ make
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
GEN build-plus-f3270/genhdr/qstrdefs.collected.h
QSTR not updated
CC main.c
LINK build-plus-f3270/firmware.elf
text data bss dec hex filename
169588 988 10316 180892 2c29c build-plus-f3270/firmware.elf
注意,这里不能在main.c中直接执行main.py文件,需要通过boot.py有条件地引导进入main.py。
创建boot.py文件
在Thonny IDE中新建boot.py文件,并保存到MicroPython设备中。boot.py文件源码如下:
from machine import Pin
btn = Pin('PG15', mode=Pin.IN_PULLUP)
if 0==btn():
print('skip main.py')
else:
if 'main.py' in os.listdir():
import main
else:
print('no main.py in filesystem')
现在可以通过开发板上的拨码开关选择启动MicroPython之后,在进入REPL之前,是否跳过可能包含无限循环的main.py。
图2 PLUS-F3270开发板上的拨码开关
最后,附送预编译好的MicroPython可执行文件:https://download.csdn.net/download/suyong_yq/86267405
完整的项目源代码,见gitee.com上的开源代码库:https://gitee.com/suyong_yq/micropython-su,其中的ports/mm32f3-lfs-spiflash。
|
|