程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

在MicroPython中啟用基於spiflash的LFS掛載文件系統

編輯:Python

在MicroPython中啟用基於spiflash的LFS掛載文件系統

相對於上一篇調試日志,本文會在mm32f3平台上重現mm32f5平台上的操作,並且梳理一下文檔。之前的調試日志記錄的是試驗的過程,本文直接講述實踐方法。

文章目錄

  • 在MicroPython中啟用基於spiflash的LFS掛載文件系統
    • 概述
    • 啟用frozen_module
      • 新建manifest.py文件
      • 更新mpconfigboard.mk文件
      • 更新mpconfigport.h文件
      • 更新main.c文件
      • 實驗
    • 添加和移植sfud組件
      • 添加sfud組件源碼
      • 添加移植sfud組件源碼
      • 更新Makefile
      • 實驗
    • 啟用lfs組件
      • 更新mpconfigboard.mk文件
      • 更新mpconfigport.h文件
      • 更新moduos.c文件
      • 實驗
    • 創建flash類模塊
      • 創建mm32f3_flash.c文件
      • 創建modmm32f3.c/.h文件
      • 更新mpconfigport.h文件
      • 更新Makefile文件
      • 實驗
    • 使用Thonny IDE建立連接
    • 後記
      • 改寫main.c文件
      • 創建boot.py文件

概述

總體的思路是:

  • 自頂向下逐步啟用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");
...
}
}

實驗

試著編一下整個項目,應該是能編通的:

[email protected] 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目錄下配置板子相關的文件。

  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. clock_init.c文件,啟用總線訪問SPI外設的時鐘:
void BOARD_InitBootClocks(void)
{

...
/* SPI2. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI2, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI2);
}
  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);
}

更新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中的代碼不會產生編譯錯誤。

[email protected] 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;
}

再編譯一次,就應該通過了。

[email protected] 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 \
...

實驗

試著編譯一下當前的移植工程,應該是可以編通不報錯的。

[email protected] 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");

重新編譯工程,並下載到開發板中。

[email protected] 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。

  • END

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved