移植micropython最小工程到mm32f3270微控制器

2023-11-09

移植micropython最小工程到mm32f3270微控制器

苏勇, 2021-08

Introduction

micropython v1.6发布已经有一段时间, 相比于之前的v1.3, 在内核中增强了一些功能并修复了一些bug, 支持的芯片也多了一些. 特别注意的是, micropython除了对STM32继续投入主要支持资源的同时, 加强了对NXP MIMXRT支持资源, 在MIMXRT移植的micropython大量增加了新的模块.

完成的changelog可见:

https://micropython.org/resources/micropython-ChangeLog.txt

这里面比较让我惊喜的是, 我竟然发现了SAMD的CM0P内核的微控制器. 从changelog上看, 实际在v1.2就已经支持了Microchip SAMD的CM4和CM0, 并且后续并没有继续更新, 但我之前的重点都在CM4F上, 并没有特别关注它. 但目前我手上只有CM3内核的芯片, 这让我不得不再看看CM4F和CM7F之外的移植. 既然CM0P也能支持(实际上circuitpython就是针对CM0P平台的衍生版), 那么CM3从理论上讲也是可行的.

我在之前对micropython的开发经历中, 已经移植过NXP KE18F(CM4F, micropython v1.3)和NXP LPC5500(CM33, micropython v1.4), 这次移植到MindMotion MM32F3270平台, 还是遵循老套路.

初试micropython v1.6

从micropython官网上下载代码包, 而不是从github上clone代码仓库. 这是因为之前的代码仓库中引用了很多submodule, 有一些submodule的地址已经失效了(例如lwip), 所以总是不能下载到完整的代码仓库. 但是从changelog上看, 至少关于lwip的引用地址已经改到了github上的镜像地址, 似乎已经解决了部分无效外链仓库的问题.

在Windows 10上搭建好Linux的工作环境, 参见我之前的文章, https://blog.csdn.net/suyong_yq/article/details/112797556 , 准备好msys2, make, python3, gcc和armgcc编译器.

先编一下mpy-corss, 无误.

再编一下minimal试试. 原本只是手贱, 做个double check, 结果竟然真的报错 !!!

在这里插入图片描述
原版代码报错, 还是在python内核里, 我自问目前还没有闲心调python内核. 只能寄希望于内核更新没有同步到minimal工程的makefile里. 但无论如何, 可以用来做最小工程的参考样例少了一个, 同时, 我的心中也飘过一道阴霾, 颇有点出师不利的兆头.

那就再试着编一下bare-arm, 心惊胆战啊. 还好, 编过了.

在这里插入图片描述
继续随手编几个工程. stm32的不用编, 那是micropython投入支持资源最多的, 我不想耽误时间, 毕竟编一次micropython还是挺长时间的. 试试mimxrt和samd的, 都没有报错. 终于拉高了点平均分.

我通常会找一个比较简单的工程作为模板开始移植, minimal已经阵亡了, MIMXRT的移植工程里增加了很多模块, 代码也扩充得比较复杂, 不再适合作为模板了. 我特别留意了SAMD的移植工程, SAMD移植的main.c代码结构同MIMXRT很像, 看来除了早期的STM32, 后来增加的移植都已经开始建立开发规范. SAMD移植的文件组织结构也同MIMXRT保持一致, 在ports目录下还有boards文件夹, 然后是各个板子相关的代码. 既然已经有了这样的规范, 那么这次我在移植MM32的时候也尽量遵循规范.

增加MM32的移植

从MM32 SDK中提取ARMGCC版本的MM32F3270的相关源码文件, 包含芯片头文件、启动汇编文件、设备驱动源文件, 以及一个简单的BSP(board_init.c, pin_init.c和clock_init.c). 集成到micropython之前, 先原地build一下, 确保代码无误.

  1. 向lib目录下新建"mm32"目录, 添加平台级的代码, 包括芯片头文件、启动汇编文件、设备驱动源文件, 同时要为以后新增其它MM32微控制器芯片支持文件预留位置. 并且直接使用lib自带的cmsis目录, 不再另外添加MM32 SDK中的CMSIS.

在这里插入图片描述

  1. 在ports目录下新建"mm32"目录, 在"mm32"目录下创建"boards"目录,
    在"boards"目录下创建"MB_F3270"目录.

在这里插入图片描述
这里特别讲一下这些文件的功能:

  • "ports/mm32/boards/MB_F3270"目录下的文件(board_init、pin_init、clock_init)直接来自于MM32 SDK样例工程, 主要实现BOARD_Init()函数, 用以对芯片的系统时钟和通信UART串口初始化.

  • 新增的"mpconfigboard.h"文件, 是按照micropython的移植规范添加的, 但其实在里面仅仅定义了板子和芯片的名字.

#define MICROPY_HW_BOARD_NAME "MB_F3270"
#define MICROPY_HW_MCU_NAME   "MM32F3277G7P"
  • 新增的"mpconfigboard.mk"文件, 指定了芯片的系列, 型号, 以及链接命令文件相对于"ports/mm32"目录的位置.

  • "ports/mm32/boards"目录下放置了链接命令文件, 放在这里的意义在于, 它可以被多个使用相同芯片的不同板子引用. 若以后还有不同的芯片, 或者相同芯片的不同链接配置, 都可以放在同级目录下, 供更多的板子引用.

  • “ports/mm32"根目录下的"mpconfigport.h”, 是直接从SAMD的移植中复制过来的,是对py核心的裁剪. 之前的移植都是从minimal或者mimxrt中拿过来,但现在minimal已阵亡,mimxrt也已经变得庞大,不适合用来做最小工程。

  • “ports/mm32"根目录下的"qstrdefsport.h”, 也是直接从SAMD的移植中复制过来的, 这个文件将被用于在build之前传入python脚本用于自动生成关键字清单的, 移植的时候别动它, 让makefile照例处理。这个文件里面实际是空的,但是保存了给后期字符串处理的标签.

// qstrs specific to this port
// *FORMAT-OFF*

  • "mphalport.h"和"mphalport.c"顾名思义是micropython系统对硬件平台提出的移植需求. 目前主要在mphalport.c中实现了串口终端到硬件平台的重映射, mphalport.h用内联函数的方式实现定时器的底层函数. 实际上, micropython最小工程中还应该包含一个核心模块utimer, 做定时器用的, 可以在这里简单支持一下(基于Systic即可). 但我为了精简, 竟然连这个模块也给移除了,真的是能简尽简了. 在此处, 对定时器底层的实现都是空的.

"mphalport.c"文件内容如下:

#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"

#include "board_init.h"
#include "hal_uart.h"

int mp_hal_stdin_rx_chr(void)
{
    while ( 0u == (UART_STATUS_RX_DONE & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
    {}
    return UART_GetData(BOARD_DEBUG_UART_PORT);
}

void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len)
{
    while (len--)
    {
        while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
        {}
        UART_PutData(BOARD_DEBUG_UART_PORT, *str++);
    }
}

/* EOF. */

"mphalport.h"内容如下:

static inline mp_uint_t mp_hal_ticks_ms(void) {
    return 0;
}
static inline void mp_hal_set_interrupt_char(char c) {
}

  • “modmachine.c”, 这个文件里, 是实现micropyhton中"machine"模块的根类, 就是可以import的模块. 原型文件来自于MIMXRT的移植, 但我为了简化, 减少不必要的麻烦, 仅剩下了"machine"类的定义.

#include "py/runtime.h"
#include "py/obj.h"
#include "extmod/machine_mem.h"

//STATIC mp_obj_t machine_reset(void) {
//    NVIC_SystemReset();
//    return mp_const_none;
//}
//MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);

STATIC mp_obj_t machine_freq(void) {
    //return MP_OBJ_NEW_SMALL_INT(CLOCK_GetFreq(kCLOCK_CpuClk));
    return MP_OBJ_NEW_SMALL_INT(96000000);
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);

STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__),            MP_ROM_QSTR(MP_QSTR_umachine) },
//    { MP_ROM_QSTR(MP_QSTR_reset),               MP_ROM_PTR(&machine_reset_obj) },
    { MP_ROM_QSTR(MP_QSTR_freq),                MP_ROM_PTR(&machine_freq_obj) },
    { MP_ROM_QSTR(MP_QSTR_mem8),                MP_ROM_PTR(&machine_mem8_obj) },
    { MP_ROM_QSTR(MP_QSTR_mem16),               MP_ROM_PTR(&machine_mem16_obj) },
    { MP_ROM_QSTR(MP_QSTR_mem32),               MP_ROM_PTR(&machine_mem32_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);

const mp_obj_module_t mp_module_machine = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t *)&machine_module_globals,
};

  • “main.c"是顶级应用, 程序入口. 之前mimxrt的移植是比较简单的, 但仍有pyexec_frozen_module()函数的调用. 现在看SAMD的移植比较清爽, 所以这次直接从SAMD的移植拿来. 去掉关于tusb的部分, 在main()函数里最开始的位置插入"BOARD_Init()”, 调用函数对具体板子进行初始化.

  • “Makefile”. Makefile是整个移植过程中最耽误时间的, 我曾经花费了很多时间想把makefile改成可视化的keil或者iar工程, 至少是方便阅读的CMakeLists.txt也行啊. 奈何我对Makefile的各种灵活用法实在搞不定, 所以还是老老实实改. SAMD的Makefile写得还是很清爽的, 之前MIMXRT也曾经清爽过, 但现在已经开始变得庞大了. 关于Makefile, 实在需要一整章来说明.

为新移植创建Makefile

以SAMD移植项目下的Makefile作为模板, 改写.

最重要的事情写在前面, 不要手贱把TAB键换成4个空格, Makefile会报错! 我因为这事郁闷了一个晚上, 能想到改回来真tmd是天意.

  1. 改板子的名字
BOARD ?= MB_F3270
BOARD_DIR ?= boards/$(BOARD)
BUILD ?= build-$(BOARD)

CROSS_COMPILE ?= arm-none-eabi-
# UF2CONV ?= $(TOP)/tools/uf2conv.py

ifeq ($(wildcard $(BOARD_DIR)/.),)
$(error Invalid BOARD specified: $(BOARD_DIR))
endif
  1. 添加芯片相关源文件的路径引用
MCU_DIR = lib/mm32/$(MCU_SERIES)

Makefile后面好像没有直接指定相对路径的, 总是在前面要加个$(xxx), 我之前曾经试过类似如下的写法, 但总是觉得有点怪怪的, 同时考虑到这个路径可能会在个地方用到, 定义个变量复用字符串也不错.

INC += -Iboards/MB_F3270

这就是最终写的看起来不错并验证正确的做法.

INC += -I$(BOARD_DIR)

另外, 在设定路径的时候, 有时是以micropython的根目录作为相对路径, 有时又以具体移植项目根目录作为相对路径的. 瑞祥随俗吧. 实际上, 这也是micropython的makefile搞得鬼, make会把编号的obj文件放到另外创建的目录中, 这个目录已经不是原始代码所在目录了, 所以后来还导致了用ozone调试elf时看不到同源代码的映射.

  1. 增加源文件搜索路径
# includepath.
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
INC += -I$(BOARD_DIR)
INC += -I$(TOP)/lib/cmsis/inc
# INC += -I$(TOP)/lib/asf4/$(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]')/include
INC += -I$(TOP)/$(MCU_DIR)/devices/$(CMSIS_MCU)
INC += -I$(TOP)/$(MCU_DIR)/drivers
# INC += -I$(TOP)/lib/tinyusb/src

  1. CFLAGS

这是SAMD移植中最良心的地方了. 我一直很头大armgcc编译器的CFLAGS, 这个不像keil或者iar提供可视化的选项, 没有典型配置可以使用, 文档解释又简单难懂. 但是SAMD的makefile同时提供了CM0P和CM4F的FLAGS组合, 我对照着改了一个CM3的版本, 竟然通了, 不可抑制地庆幸, 开心!

# flags.
CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU_$(MCU_SERIES)) -fsingle-precision-constant -Wdouble-promotion

CFLAGS_MCU_CM3    = -mtune=cortex-m3 -mcpu=cortex-m3 -msoft-float
CFLAGS_MCU_CM0P   = -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float

ifeq ($(MCU_SERIES), mm32f3270)
CFLAGS += $(CFLAGS_MCU_CM3)
else
CFLAGS += $(CFLAGS_MCU_CM0P)
endif

CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__
LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)

# Tune for Debugging or Optimization
ifeq ($(DEBUG),1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -Os -DNDEBUG
LDFLAGS += --gc-sections
CFLAGS += -fdata-sections -ffunction-sections
endif

从后面的代码可以看到, micropython可能天然就支持CM3吧, 即使CM4F和CM7F, 甚至是我曾经移植成功过的CM33, 使用的都是gchelper_m3.s文件.

# also use cm3 as gchelper_m3.s
ifeq ($(MCU_SERIES),mm32f3270)
SRC_S = lib/utils/gchelper_m3.s
else
SRC_S = lib/utils/gchelper_m0.s
endif
  1. 加源文件

略.

  1. QSTR扫描文件清单

micropython的make在启动编译之前, 会用python脚本扫描源代码, 提取其中的关键字, 生成专门包含关键字的头文件.

后续添加模块是, 必然包含了micropython需要调用的关键字, 一定要在这里加上对应的源文件.

# List of sources for qstr extraction
SRC_QSTR += modmachine.c
  1. 编译OBJ文件输出路径及规则

这里特别加了大写S后缀的汇编文件的规则, 用了"SRC_SS", 专门为了兼容xxxxx_startup.S文件. 我在早期移植KE18F的时候, 曾经使用过用c代码内嵌汇编的方式, 把S文件改写成c文件, 这样就可以省却此处的麻烦了. 后面抽空可以试试再改一次.

OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_SS:.S=.o))
  1. 创建规则

真是良心啊, 不仅仅可以生成elf文件, 把bin和hex的脚本也写好了.

all: $(BUILD)/firmware.bin

$(BUILD)/firmware.elf: $(OBJ)
	$(ECHO) "LINK $@"
	$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
	$(Q)$(SIZE) $@

$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
	$(Q)$(OBJCOPY) -O binary $^ $@

$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
	$(Q)$(OBJCOPY) -O ihex -R .eeprom $< $@
  1. 包含其它mk文件

文件结尾的

include $(TOP)/py/mkrules.mk

和文件开始的

include ../../py/mkenv.mk
include $(BOARD_DIR)/mpconfigboard.mk

就这么放着吧, 别乱动.

附件

最后, 附上完整的项目压缩包:

https://download.csdn.net/download/suyong_yq/20969468

还有一个简单的演示视频:

mm32

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

移植micropython最小工程到mm32f3270微控制器 的相关文章

随机推荐

  • ROS-常用组件

    学习资料参考 ROS机器人开发实践 胡春旭 Launch 启动文件 通过XML文件实现多节点的配置和启动 真的好用 简化一个节点一个终端的复杂情况 Launch File 同时启动多个节点 自动启动ROS Matser 每个节点的配置 基本
  • Python——to_csv去除空行

    我们使用csv模块写入数据到csv文件中时 无论是使用writerow 方法还是writerows csv文件中的每一行数据总是相隔一空行 import csv data 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1
  • Apache Log4j2 远程代码执行漏洞复现

    靶场 Vulfocus 靶场环境 目前 Vulfocus 已经集成 Log4j2 环境 可通过以下链接启动环境测试 http vulfocus fofa so dashboard image id 3b8f15eb 7bd9 49b2 a6
  • Android webview支持获取本地图片或拍照

    Android webview支持获取本地图片或拍照 package com wshoto user anyong ui activity public class BBSActivity extends InitActivity Bind
  • 计算机经典书籍(转载,难以找到出处)

    学计算机也有几年了 眼看明年就要毕业 在这里总结一下我看过的书 并推荐一些我认为好的书 还有一些是我听说好的但没看过的 也写在这里 对于下面的书 如果看过的我会按自己的读后感打一个分和一些评价 评分及供参考 如有问题 欢迎讨论 好的 现在开
  • python机器学习----模型选择1(方法、指标)

    一 模型选择的方法及相关指标 1 损失函数通常有0 1损失 平方损失 绝对值损失和对数损失 2 通常用测试集对模型评估 评估的方法有留出法 交叉验证法 留一法 自助法 留出法 直接将数据分为对立的三部分 也可以是两部分 此时训练集也是验证集
  • 网页爬虫逆向与AST入门系列教程(三、使用工具生成和可视化AST)

    网页爬虫逆向与AST入门系列教程 第三部分 使用工具生成和可视化AST 在前两篇文章中 我们学习了什么是AST以及它在网页爬虫逆向中的应用 本篇将介绍一些工具和方法 帮助我们生成和可视化AST 1 AST生成工具 为了生成AST 我们可以使
  • 多重背景图片(background属性缩写)

    多重背景图片 格式 background url images animal1 png no repeat url images animal2 png no repeat 加入定位属性分开图片 background url images
  • BUUCTF——Basic

    Linux Labs 启动靶机 根据题目与ssh有关 并且给出了用户名和密码 使用kail进行渗透 SSH是一种网络协议 用于计算机之间的加密登录 它通常用于Linux系统之间的远程登录 文件传输和其他网络服务 SSH工作原理简单来说是 客
  • 【Qt编程笔记】采用遍历方式删除QList中全部元素的方法

    QList类是Qt提供的链表模板类 在日常工作和学习中经常会用到 虽然QList操作十分便利 但是在用遍历方式删除全部元素时很可能会因为疏忽造成没有将元素全部删除 从而给程序留下隐患 下面小结一下采用遍历方式删除QList中全部元素的方法
  • 由于找不到d3dx9_43.dll,有什么可靠的修复方法?

    由于找不到d3dx9 43 dll 无法继续执行代码 这种情况大家是否有遇见过 其实就算没遇到过 大家应该也有遇到别的dll文件丢失吧 道理都一样 都是dll文件丢失 我们只需要把它给修复就可以了 不同的dll只是负责的功能不一样而已 下面
  • Css层叠优先级只会这两招还远远不够

    作为一个玩前端的 ps软件中的图层都知道吧 多个图层层叠就可以组成丰富多彩的图片 所以图层就有层叠顺序了 Css的层叠原理也是差不多 只不过Css是通过多个盒子层叠形成丰富多彩的图片 Css层叠优先级设置不就是z index和 import
  • linux 测试网络连通性方法

    一 telnet 方法 telnet 协议是 TCP IP 协议族中的一员 是 Internet 远程登陆服务的标准协议和主要方式 它为用户提供了在本地计算机上完成远程主机工作的能力 因此我们可以使用telnet 来测试远程机器的连通性 t
  • VMware安装RHEL 8.2(红帽)

    一 创建虚拟机 打开VMware 点击 创建新的虚拟机 点击自定义 下一步 选择兼容性 15 x 兼容性选VMware的版本 稍后安装操作系统 选择镜像对应的操作系统类型及版本 系统镜像按自己准备的选择即可 自定义虚拟机名称及安装的位置 名
  • 数组的方法以及特征

    数组变成一个字符串 1 join 可以在每一个元素中加一个字符串 2 toString pop 删除数组最后一个元素 push 增加数组 reverse 反转 slice 从下标开始取 sort 对数组进行排序 splice 删除数组的某几
  • 取消全部呼叫转移代码_中国移动的卡取消呼叫转移的快捷方式是什么?

    展开全部 取消已设置的所有呼转可用手机拨打 002 取62616964757a686964616fe59b9ee7ad9431333365663562消关机或无信号时转移可用手机拨打 62 取消无人接听时转移可用手机拨打 61 取消遇忙音占
  • 即时通讯(IM)开源项目OpenIM对WebAssembly支持,提升web端体验

    WebAssembly 是什么 2019 年 12 月 W3C 标准批准了第四种官方语言 WebAssembly Wasm 这种语言在结构 使用和功能方面与以前的语言有很大不同 WebAssembly 是一种新的编码方式 可以在现代的Web
  • [1138]java中json的使用和解析

    文章目录 1 创建json对象 1 1 创建JSONObject对象 1 2 创建JSONArray对象 2 解析json 2 1 官方json包解析 2 2 fastjson解析 2 3 jackson解析 1 创建json对象 1 1
  • 关于时区的时间的详解,比如UTC\GMT等

    来源 UTC 和 GMT 及 北京时间的关系 UTC和GMT 这两者几乎是同一概念 它们都是指的格林尼治标准时间 只不过UTC的称呼更为正式一点 两者的区别在于前者是一个天文 上的概念 而 后者是基于一个原子钟 在UTC中 每一年或两年会有
  • 移植micropython最小工程到mm32f3270微控制器

    移植micropython最小工程到mm32f3270微控制器 苏勇 2021 08 文章目录 移植micropython最小工程到mm32f3270微控制器 Introduction 初试micropython v1 6 增加MM32的移