• 在MicroPython中启用基于spiflash的LFS挂载文件系统


    在MicroPython中启用基于spiflash的LFS挂载文件系统

    相对于上一篇调试日志,本文会在mm32f3平台上重现mm32f5平台上的操作,并且梳理一下文档。之前的调试日志记录的是试验的过程,本文直接讲述实践方法。

    概述

    总体的思路是:

    • 自顶向下逐步启用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")
    
    • 1

    更新mpconfigboard.mk文件

    在ports/mm32f3-lfs-spiflash/boards/plus-f3270/mpconfigboard.mk文件中,添加脚本,引用新建的manifest.py文件,将其集成在编译工程的过程中。

    在已有mpconfigboard.mk文件中添加脚本:

    FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
    
    • 1

    更新mpconfigport.h文件

    在现有移植项目的mpconfigport.h文件中,添加配置宏,启用MicroPython内核中的frozen机制:

    #define MICROPY_MODULE_FROZEN          (1) /* enable pyexec_frozen_module() in pyexec.c */
    #define MICROPY_MODULE_FROZEN_MPY      (1)
    
    • 1
    • 2

    更新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");
            ...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    实验

    试着编一下整个项目,应该是能编通的:

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    从输出的信息中可以看到,编译过程已经处理了_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())
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    重新编译,下载,运行。实际可以看到板子上的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目录下配置板子相关的文件。

    1. 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. clock_init.c文件,启用总线访问SPI外设的时钟:
    void BOARD_InitBootClocks(void)
    {
        ...
    
        /* SPI2. */
        RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI2, true);
        RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    更新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 \
    	...
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    实验

    编译一下工程,确保当前添加到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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    启用lfs组件

    MicroPython的lfs文件系统,实际上仅仅是一个文件系统框架,并没有像fatfs一样,通过源代码静态绑定。因此,可以独立启用lfs组件,而暂不实现具体的移植。

    更新mpconfigboard.mk文件

    lfs组件相关的源码,已经存放在MicroPython代码仓库的\extmod目录下。在现有工程的mpconfigboard.mk文件中,添加 配置开关,让编译过程能够编译lfs相关的源代码。

    MICROPY_VFS_LFS2 ?= 1
    
    • 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
    
    • 1
    • 2
    • 3

    这是为了在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
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    实验

    试着编译一下当前的移植工程,报错,说在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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    顾名思义,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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再编译一次,就应该通过了。

    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    创建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,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    至于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,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    更新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) }, \
    
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    更新Makefile文件

    在当前移植项目的Makefile中,添加新建文件:

    ...
    SRC_C += \
    	...
    	modmm32f3.c \
    	mm32f3_flash.c \
    ...
    
    # list of sources for qstr extraction
    SRC_QSTR += modmachine.c \
    			...
    			modmm32f3.c \
    			mm32f3_flash.c \
    			...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实验

    试着编译一下当前的移植工程,应该是可以编通不报错的。

    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    此时,可以将固件下载到板子上,然后试着手工在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']
    >>>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    看起来,文件系统已经准备好了。接下来就是让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, "/")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    重新编译工程,正常情况下应该通过编译,无错误。

    此时整个工程已经基本移植成功了,可以关掉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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    下载代码运行。

    使用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");
    
    • 1

    重新编译工程,并下载到开发板中。

    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注意,这里不能在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')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    现在可以通过开发板上的拨码开关选择启动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。

    • END
  • 相关阅读:
    stl 容器内存
    树莓派4B无屏幕连接Wi-Fi/启用ssh/创建用户
    Linux命令(102)之less
    CDN是什么,能起到什么作用
    逆向分析:还原 App protobuf 协议加密
    ARM——综合作业
    【API 管理】什么是 API 管理,为什么它很重要?
    前端笔试记录(三)-代码输出题
    史上最全,接口测试-用例设计总结(案例分析实例)一篇策底打通...
    从JVM角度理解Java并发(下)
  • 原文地址:https://blog.csdn.net/suyong_yq/article/details/126078840