多天艰苦尝试,无数次失败后终于成功踏出的第一步
一般情况下,Arduino项目和Micropython项目是不能同时运行在同一块esp32开发板上的
因为一个项目烧写进esp32时会擦除并覆写flash
我们的工作就是要将Micropython嵌入Arduino项目中,同时获得两者的特性
在前几年,很多前辈做过类似的尝试,如将Micropython嵌入到ESP-IDF,将Micropython嵌入到Linux C项目中
幸运的是Micropython官方看到了这个issue,并为这个嵌入工作做了很大的帮助
Micropython github地址: https://github.com/micropython/micropython
可以看到ports/embed和examples/embedding文件夹,其中官方给出了一个例子:
Example of embedding MicroPython in a standalone C application
将Micropython嵌入到一个单独的main.c中
我的工作就是参考这个例子,将Micropython嵌入到Arduino项目中
在Linux中:
git clone https://github.com/micropython/micropython.
进入micropython/examples/embedding目录
make -f micropython_embed.mk
make
然后能看到多了个文件夹micropython_embed,这是micropython嵌入c项目中所要用到的必须文件,复制到Windows系统待用
将mpconfigport.h复制到Windows系统待用
然后在Windows下的C:\Users\Administrator\.platformio(Administrator替换为你的系统名)下新建文件夹lib\micropython_embed
将刚才复制到windows的micropython_embed下的所有内容复制到C:\Users\Administrator\.platformio\lib\micropython_embed中
然后再将mpconfigport.h复制到micropython_embed下
打开VScode,创建Arduino项目,board选择Espressif esp32 dev
将main.cpp的内容替换如下
#include <Arduino.h>
extern "C"{
#include "port/micropython_embed.h"
}
// This is example 1 script, which will be compiled and executed.
static const char *example_1 =
"print('hello world!', list(x + 1 for x in range(10)), end='eol\\n')";
// This is example 2 script, which will be compiled and executed.
static const char *example_2 =
"for i in range(10):\n"
" print('iter {:08}'.format(i))\n"
"\n"
"try:\n"
" 1//0\n"
"except Exception as er:\n"
" print('caught exception', repr(er))\n"
"\n"
"print('finish')\n"
;
void setup() {
// Initialise MicroPython.
//mp_embed_init(&heap[0], sizeof(heap));
mp_embed_init();
// Run the example scripts (they will be compiled first).
mp_embed_exec_str(example_1);
mp_embed_exec_str(example_2);
// Deinitialise MicroPython.
mp_embed_deinit();
}
void loop() {
}
example_1和example_2就是执行的micropython语句,也可以替换为其他语句
注意,我们刚才复制的C:\Users\Administrator\.platformio\lib\micropython_embed下的文件是需要根据项目需求修改的
micropython有一个特性是grabage collect(gc)
但由于刚才复制的依赖文件没有针对esp32进行设置,导致编译时会因为garbage collect出错,所以我将这些文件所有关于gc的部分都注释掉了
要启用的话需要将注释的所有gc的内容恢复,然后再阅读micropython/ports/esp32下的代码,然后进行一些针对的配置修改
在编译项目的过程中我经历了无数次的编译失败,下面挑选一些作为案例:
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x10): undefined reference to `mp_embed_init(void*, unsigned int)'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x14): undefined reference to `mp_embed_exec_str(char const*)'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x18): undefined reference to `mp_embed_deinit()'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: .pio\build\esp32dev\src\main.cpp.o: in function `setup()':
E:\Code\MicroPythonEmbedded2/src/main.cpp:26: undefined reference to `mp_embed_init(void*, unsigned int)'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: E:\Code\MicroPythonEmbedded2/src/main.cpp:29: undefined reference to `mp_embed_exec_str(char const*)'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: E:\Code\MicroPythonEmbedded2/src/main.cpp:30: undefined reference to `mp_embed_exec_str(char const*)'
c:/users/administrator/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/l
d.exe: E:\Code\MicroPythonEmbedded2/src/main.cpp:33: undefined reference to `mp_embed_deinit()'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1
错误信息为"undefined reference to xxx_function",可我明明导入了头文件,这些函数已经有定义了才对?
经过查询,原来是“作为一种面向对象的语言,C支持函数重载,而过程式语言C则不支持。函数被C编译后在符号库中的名字与C语言的不同”
注意到micropython的所有文件其实是C文件而不是C文件,而我们的Arduino项目内都是C文件,这样引用时自然会报错
所以将
#include "port/micropython_embed.h"
修改为
extern "C"{
#include "port/micropython_embed.h"
}
就能解决这个问题
可以对照main.cpp的代码,看到micropython的代码成功执行
由于这是第一个micropython嵌入Arduino项目的Demo,复制的依赖文件只是micropython的子集
本Demo仅仅是一个嵌入的简单展示
所以想要使用micropython的某些特性暂时还无法使用(如上文提到的gc,还有我们需要的webrepl等其他功能)
要使用其他功能的话还需要阅读micropython的项目源代码,然后引入合适的文件,也可能需要对文件进行一定修改
我已经将嵌入所需的库文件和这个Demo项目都上传到gitlab上
分别为lib/micropython-embed和MicroPythonEmbed-Demo
http://www.jtext.cn:23080/zhdyz/neoplc-plus/tree/master
本文章使用limfx的vscode插件快速发布