在Raspberry Pi Pico上为MicroPython提供C语言扩展
这是一份关于如何在Raspberry Pi Pico上编写和运行MicroPython的基本C语言扩展的指南。我将介绍扩展MicroPython的原因,如何编写扩展模块,如何编译以及如何在Pico上安装它。如果你想阅读更多关于这个主题的内容,请参考 https://docs.micropython.org/en/latest/develop/extendingmicropython.html
简介
为什么要扩展MicroPython?
你可能想扩展MicroPython,这可能有多种原因。由于MicroPython是Python的精简版,当涉及到计算量大的任务时(类似于Python),MicroPython的表现不是很好。另一方面,C语言确实很适合此类任务。Micropython的C语言扩展使你能够通过C语言进行这些计算,并在MicroPython中使用这些结果。这可以使一些程序的速度提高一个数量级。
第二个原因可能是,你想在MicroPython中连接一些使用C语言API的硬件。
MicroPython C语言扩展的类型
有几种不同的方式来扩展MicroPython:外部C模块和.py文件中的本地机器代码。
要运行一个外部C模块,你需要把它重新编译到MicroPython固件中。这是一个相当复杂的过程,这就是为什么本指南将重点介绍第二种方法。如果你对这种方法感兴趣,你可以在这些网页上阅读更多信息。 https://docs.micropython.org/en/latest/develop/cmodules.html https://www.raspberrypi.org/forums/viewtopic.php?t=300352
.py是一个存储已编译的本地机器代码的文件,可以动态链接。这使得它更加灵活,因为你不需要重新编译整个MicroPython固件。
编写扩展模块
编写扩展模块是扩展MicroPython的最简单的部分。我将通过一个简单的例子来告诉你如何做。首先,我们将创建一个新的目录,名为 事实fib.打开一个新的终端窗口,cd进入新目录,并创建一个新的文件,名为 事实fib.c.如果你在Dekstop下的Raspberry Pi上创建了该目录,该命令看起来像这样。
cd ~/Desktop/factfib
touch factfib.c
开放式 事实fib.c 在你喜欢的文本编辑器中,输入以下代码:
#include "py/dynruntime.h
STATIC mp_int_t factorial_helper(mp_int_t x) {
if (x < 1) {
return 1;
}
return x*factorial_helper(x-1);
}
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = factorial_helper(x);
return rslt;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
STATIC mp_int_t fibonacci_helper(mp_int_t x) {
if (x <= 0) {
return 0;
}
else if (x == 1) {
return 1;
}
else {
return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
}
}
STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj);
mp_int_t rslt = fibonacci_helper(x);
return mp_obj_new_int(rslt);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));
MP_DYNRUNTIME_INIT_EXIT
}
让我解释一下上面的代码。在MicroPython和Python中,每个变量都是一个对象。因此在C语言中,我们把它们表示为 mp_obj_t.但是C程序只能使用C类型的变量,这就是为什么我们需要将对象转化为C类型。这就是所谓的Marshalling,MicroPython提供了从一个对象中提取任何C类型的函数。
奥利弗-罗布森的这个网页对法警工作很有帮助。 https://mpy-c-gen.oliverrobson.tech/.此外,你可以在MicroPython文档中找到调集的例子 https://docs.micropython.org/en/latest/develop/natmod.html.如果你需要进一步解释,我建议你阅读这篇文章。
构建扩展
我们通过使用Makefile将扩展程序构建成一个.mpy文件。但我们需要先设置一些东西。确保你的终端仍然打开在 事实fib 目录。然后克隆MicroPython的GitHub仓库。
sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi
git clone --recurse-submodules https://github.com/micropython/micropython.git
pip3 install 'pyelftools>=0.25'
这些安装会花费一些时间,如果你想节省时间并且知道自己在做什么,你只需要从micropython仓库克隆/py和/tools目录,然后把它们放在一个 微软 文件夹内的 事实fib 文件夹(跳过第二个命令)。
在安装过程中,我们可以利用这段时间来编写Makefile。只需执行
touch Makefile
并在一个文本编辑器中打开新创建的文件。
MPY_DIR = micropython
MOD = factfib
SRC = factfib.c
ARCH = armv7m
include $(MPY_DIR)/py/dynruntime.mk
你可能已经注意到,我们将 ARCH 变量为 armv7m 虽然皮克是 armv6m.我们必须这样做,因为 armv6m 架构(在我写这篇文章的时候)不支持 dynruntime.mk 工具。
但幸运的是,我们仍然可以为Pico编译一个有效的扩展。我们只需要修改 dynruntime.mk 文件,它应该位于 micropython/py/dynruntime.mk。 打开它并在armv7m的架构配置下找到CFLAGS变量(应该是第64行)。改变 -mcpu=cortex-m3 至 -mcpu=cortex-m0 并保存该文件。
然后在一切安装完毕后,执行
make
和 事实fib.mpy 文件将被创建。
安装并测试该扩展
最后一步是安装和测试。为此我们利用Micropython在Raspberry Pi Pico上创建的文件系统。首先,我们需要用MicroPython固件闪过Pico。最简单的方法是使用Thonny IDE(预装在Raspbian/Raspberry Pi OS上)。
如果你没有使用Raspberry Pi为你的Pico编程,或者你以前从未在Pico上使用过MicroPython,那么请参考Raspberry Pi的MicroPython入门指南。 https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython
如果你使用的是Windows,你应该看看这篇关于Raspberry Pi Pico和MicroPython在Windows上的博文。 https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/
在你用MicroPython固件刷新你的Pico后,关闭Thonny,并安装rshell。我们使用rshell来从命令行访问文件系统。
sudo pip3 install rshell
rshell --version
如果一切设置正确,这将打印出rhsell版本。然后拔掉pico的插头,再插上(不按BOOTSEL按钮),以确保没有任何东西在试图访问文件系统。现在我们需要执行
rshell -p /dev/ttyACM0 --buffer-size 512
cp factfib.mpy /pyboard/factfib.mpy
为了测试安装,你可以使用rshell或Thonny IDE来保存你的 .py 文件,但我将演示如何在minicom上使用MicroPython解释器。
因此,首先按 Ctrl+c 来离开rshell,然后通过以下方式安装minicom
sudo apt install minicom
现在我们可以访问Picos REPL(读取-评估-打印循环)。
minicom -o -D /dev/ttyACM0
三个结尾的角括号>>表示MicroPython解释器正在运行。现在我们可以导入我们的扩展并像往常一样使用它。
>>> import factfib as ff
>>> ff.factorial(5)
>>> 120
>>> ff.fibonacci(7)
>>> 13
恭喜你!你已经为Pico创建了第一个MicroPython C语言扩展!你已经为Pico创建了你的第一个MicroPython C语言扩展!下一步是学习如何编写和编译更复杂的模块。一个好的开始是测试列表和数据集的工作方式(见上面的 Marshalling 网页)。
如果你对这个帖子有任何疑问,欢迎写下评论。
除了c程序中的错误外,它工作得很好。谢谢。
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj)。
mp_int_t rslt = factorial_helper(x);
返回mp_obj_new_int(rslt)。
}
谢谢你的反馈 🙂
如何配置可以从 mysql 获取数据的 joomla?
我试着做了上述工作,但各种事情都不像描述的那样进行。
- 我按照上面的指示,得到了micropython,按照描述修改了makefile文件
- 我做了(但我得到的是factfib.native.mpy文件,而不是factfib.mpy)。
- 我将 factfib.native.mpy 文件复制到 pico,作为 factfib.mpy。
(我试着用rshell,但得到的结果是 "超时或传输到远程时出错:b"",但我可以用Thonny把它复制过来)
- 我可以导入模块(在thonny或rshell中--相同的)而没有错误
- 我试着运行 "ff.fibonacci(5)",但我得到了。
"回溯(最近的一次调用)。
文件"",第1行,在
AttributeError: 'module' object has no attribute 'fibonacci'"
我做错了什么?
你最终让它工作了吗?
现在,您可以编译为 armv6 版本,因此只需修改 Makefile 中的这一行,而无需修改 microropython 代码
ARCH = armv6m
我在编译 factfib.c 时遇到了一些错误,请问修复方法是什么:
// 缺少了最后的"......"。
#include "py/dynruntime.h"
// 将返回值转换为 mp_obj_t
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
mp_int_t x = mp_obj_get_int(x_obj)。
mp_int_t rslt = factorial_helper(x);
返回mp_obj_new_int(rslt)。
}
感谢您提供的信息,保罗!
我按照所有说明进行了操作,最终生成了 facfib.mpy 文件。我使用了
ARCH = armv6m
加载到 Pico 时,我遇到了这个错误:
ValueError:不兼容 .mpy 文件
我的 Pico 需要以下 mpy 值:
mpy 版本: 6
mpy 子版本: 2
mpy 标志:-march=armv6m
通过检查文件的前两个字节,可以得到版本 6 和子版本 6。
请问有什么办法可以纠正这种情况吗?