-MicroPython原理浅析

MicroPython包含了诸如交互式提示,任意精度整数,关闭,列表解析,生成器,异常处理等高级功能。 足够精简,适合运行在只有256k的代码空间和16k的RAM的芯片上。

Micropython技术是依赖Byte Code的执行,在编译阶段就将py文件先转换成mpy文件,在通过mpy-tool.py生成Byte Code,Byte Code在执行时会依赖Virtual Machine入口表,找到对应的Module入口,最终找到对应的Funcion binary code执行。其中所有的Function都通过Dictionary的形式存储,而每一个Dictionary都有自己的QSTR,Micropython有buildin的QSTR和用户扩展的QSTR。具体流程可参考如下图一。

MicroPython原理浅析
图一

QSTR的定义

QDEF(MP_QSTR___main__, (const byte*)"\x8e\x13\x08" "__main__")

其中x8ex13是dbj2 hash算法计算出来,x08是QSTR "main"的长度

def dbj2_hash(qstr, bytes_hash):
    hash = 5381
    for b in qstr:
        hash = (hash * 33) ^ b
    # Make sure that valid hash is never zero, zero means "hash not com    puted"
    return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1
通过dbj2 hash值和子串长度作为一个QSTR的ID。
  • Build in QSTR

Micropython支持常用的build in的QSTR,包括基本整形类型和运算符等。比如

QDEF(MP_QSTR_ptr32, (const byte*)"\xb2\xca\x05" "ptr32")
QDEF(MP_QSTR_s32i, (const byte*)"\x3e\x34\x04" "s32i")
QDEF(MP_QSTR_float, (const byte*)"\x35\x44\x05" "float")
QDEF(MP_QSTR_add, (const byte*)"\x44\x32\x03" "add")
QDEF(MP_QSTR_sub, (const byte*)"\x21\x8d\x03" "sub")
QDEF(MP_QSTR_xor, (const byte*)"\x20\x93\x03" "xor")
QDEF(MP_QSTR_max, (const byte*)"\xb1\x43\x03" "max")
QDEF(MP_QSTR_min, (const byte*)"\xaf\x42\x03" "min")
QDEF(MP_QSTR___eq__, (const byte*)"\x71\x3e\x06" "__eq__")
QDEF(MP_QSTR___ge__, (const byte*)"\xa7\x46\x06" "__ge__")
QDEF(MP_QSTR___gt__, (const byte*)"\xb6\x82\x06" "__gt__")
  • Extend QSTR

除了常用的Build in QSTR外,Micropython还支持扩展的QSTR,从而添加用户自己的应用功能。比如

 // 添加mbedtls udp socket接口
QDEF(MP_QSTR_uselect, (const byte*)"\x58\x8e\x07" "uselect")
QDEF(MP_QSTR_usocket, (const byte*)"\x75\x00\x07" "usocket")
QDEF(MP_QSTR_ussl, (const byte*)"\x1c\xf2\x04" "ussl")
// 添加http socket服务    
QDEF(MP_QSTR_uwebsocket, (const byte*)"\xe5\x33\x0a" "uwebsocket")
// 添加密码学算法服务
QDEF(MP_QSTR_ucryptolib, (const byte*)"\x34\xda\x0a" "ucryptolib")
// 添加随机数服务
QDEF(MP_QSTR_urandom, (const byte*)"\xab\xae\x07" "urandom")
// 添加Json包服务
QDEF(MP_QSTR_ujson, (const byte*)"\xe8\x30\x05" "ujson")

QSTR的生成

无论是Build in QSTR还是Extend QSTR, 都是通过makemodulesdefs.py, makeqstrdefs.py, makeqstrdata.py脚本生成,存放在qstrdefs.generated.h文件里。用户自行扩展的QSTR是否添加成功,可以通过在QSTR AUTO GENERATOR后通过查看该文件。

ByteStream的生成

Python源文件首先经过mpy_cross.elf工具转成mpy文件,例如Top.py转成的Top.mpy二进制如下:

MicroPython原理浅析

红色部分就是Top文件功能可执行代码,mpy_tool.py工具会提取该功能可执行代码生成 frozen mpy的C语言文件,与该Top.py对应的的ByteStream数组如下:

MicroPython原理浅析

通过比较,fun_data_Top__lt_module_gt__process_apdu的数组内容实际上就是Top.py文件的功能可执行代码。利用mpy_tool.py工具可以将Python语言脚本转换成C语言数组,而该数组内容实际上就是该Python文件的功能可执行代码,也称为ByteStream。

一旦Python文件调用另一个python文件,mpy_tool.py工具的做法是通过叫做mp_raw_code_t的数据接口将不同的python文件调用关系连接起来,例如如下mp_raw_code_t的数组将Top.py和Applet_AID1234567890.py文件连接起来,其源于Top.py文件调用了Applet_AID1234567890.py文件里的process_apdu接口。

MicroPython原理浅析
MicroPython原理浅析

Virutal Machine Entry Table

  • Byte Code定义
Name Value
MP_BC_LOAD_CONST_FALSE 0x10
MP_BC_LOAD_CONST_NONE 0x11
MP_BC_LOAD_CONST_TRUE 0x12
MP_BC_LOAD_CONST_SMALL_INT 0x14
MP_BC_LOAD_CONST_STRING 0x16
MP_BC_LOAD_CONST_OBJ 0x17
MP_BC_LOAD_NAME 0x1b
MP_BC_LOAD_ATTR 0x1d
MP_BC_STORE_NAME 0x24
MP_BC_STORE_ATTR 0x26
MP_BC_POP_JUMP_IF_TRUE 0x36
MP_BC_POP_JUMP_IF_FALSE 0x37
MP_BC_BUILD_MAP 0x53
MP_BC_BUILD_SET 9x56
MP_BC_YIELD_VALUE 0x5d
MP_BC_YIELD_FROM 0x5e
MP_BC_MAKE_FUNCTION 0x60
MP_BC_MAKE_FUNCTION_DEFARGS 0x61
MP_BC_CALL_FUNCTION 0x64
MP_BC_CALL_FUNCTION_VAR_KW 0x65
MP_BC_CALL_METHOD 0x66
MP_BC_CALL_METHOD_VAR_KW 0x67
MP_BC_IMPORT_NAME 0x68
MP_BC_IMPORT_FROM 0x69
MP_BC_IMPORT_STAR 0x6a
MP_BC_LOAD_CONST_SMALL_INT_MULTI 0x70
MP_BC_LOAD_FAST_MULTI 0xb0
MP_BC_UNARY_OP_MULTI 0xd0
MP_BC_BINARY_OP_MULTI 0xd7

上述表格定义了部分Byte Code,这些Byte Code在mpy_tool.py工具里同样定义了一套。用于将Python文件转换成Byte Stream数组,在执行Byte Stream时,Micropython会解析其中的Byte Code, 执行相应的Byte Code处理服务函数。在执行Byte Code处理服务函数里,根据QSTR在字典数据结构里的查找到对应的C语言接口,从而实现真正的python执行脚本功能。

MicroPython SDK

SDK里的主要部件如下:

  • py/ – the core Python implementation, including compiler, runtime, and,library.
  • mpy-cross/ – the MicroPython cross-compiler which is used to turn scripts, precompiled bytecode.
  • ports/unix/ – a version of MicroPython that runs on Unix.
  • ports/csky/ – a version of MicroPython that runs on the PyBoard and similar Hobbit1-2 boards.
  • tests/ – test framework and test scripts.
  • docs/ – user documentation in Sphinx reStructuredText format.
  • extmod/ – additional (non-core) modules implemented in C.
  • tools/ – various tools, including the pyboard.py module.
  • examples/ – a few example Python scripts.

mpy_cross tool

Micropython的移植首先需要编译生成MicroPython cross-compiler工具,该工具可以将Python 源文件预编译成mpy文件。

$ cd mpy-cross
$ make

如何创建一个Python对象和方法

该实例创建了了一个名为example的python对象,同时也支持add_ints的一个方法。

  • Step 1

创建一个example.c的文件, 包含python系统头文件。

#include "py/obj.h"
#include "py/runtime.h"
#include "py/builtin.h"
  • Step 2

定义add_ints 方法。

 STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
    // Extract the ints from the micropython input objects
    int a = mp_obj_get_int(a_obj);
    int b = mp_obj_get_int(b_obj);

    // Calculate the addition and convert to MicroPython object.
    return mp_obj_new_int(a + b);
}
  • Step 3

定义example 对add_ints方法的引用。

STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
  • Step 4

定义example对象的属性,利用key/value方式作为example对象的入口查找方式。

 STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) },
    { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
  • Step 5

定义example对象。

const mp_obj_module_t example_user_cmodule = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t*)&example_module_globals,
};
  • Step 6

注册example对象到MicroPython对象库里。

MP_REGISTER_MODULE(MP_QSTR_example, example_user_cmodule, MODULE_EXAMPLE_ENABLED);
  • Step 7

写python脚本对example对象的访问

import example
print(example.add_ints(1, 3))

总结

Micrypython为嵌入式系统的跨平台应用开发提供了一种可能,特别是资源受限的物联网设备。利用其跨平台的特性,能够快速的移植应用到嵌入式平台上。和Javacard相比,其安全性没有得到证明,像Byte Code的定义都没有形成标准规范,对Global Platform的SE规范没有支持,这些都需要进一步的完善。

- 本文内容来自网络,如有侵权,请联系本站处理。

2022-03   阅读(107)   评论(0)
 标签: embedded MicroPython

涨知识
RISC-V

RISC-V(发音为“risk-five”)是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。RISC-V指令集可以自由地用于任何目的,允许任何人设计、制造和销售RISC-V芯片和软件。

评论:
相关文章
小鹏物联网 MicroPython 智能浇花方案

相信很多人都有把绿植给养死的经历,可能是浇水过多、忘记浇水、较长时间不在家不能浇水等,本文介绍一种可以灵活定制的智能浇花方案。


MicroPython 开发ESP32应用之线程介绍及实例分析

MicroPython 在 ESP32 上支持线程(Thread)功能,通过_thread模块实现。线程允许程序并发执行多个任务,适合处理需要同时运行的场景,例如传感器数据采集和网络通信。


ESP32 MicroPython采集模拟传感器数值

使用了 MicroPython 库,通过 定时器(Timer) 和 ADC(模数转换器) 功能来实时读取传感器数据。使用定时器可以实现高精度、非阻塞、低资源消耗的周期性任务,保证实时性和可靠性,特别适用于嵌入式系统中的多任务处理和低功耗场景。


MicroPython PWM类

machine.pwm是MicroPython中用于控制PWM输出的模块之一,它提供了一些方法和属性,用于设置和控制PWM输出的频率、占空比等参数,从而实现对各种应用场景的控制。


Micropython Pin类

Pin 类是 machine 模块下面的一个硬件类,用于对引脚的配置和控制,提供对 GPIO 的操作方法。


Micropython基于ESP32的多线程开发

本文学习如何使用ESP32开发板来进行多线程的开发。


MicroPython SPI类

MicroPython的SPI是一个用于进行串行外设接口总线协议的类。


ESP32 使用 MicroPython:I2C 总线

本文以一个简单的例程帮助大家在 MicroPython 下使用 I2C


binascii – 二进制/ASCII 转换模块

binascii模块实现了相应 CPython 模块的一个子集。


Thonny 4.1.3 下载

Thonny是一款免费的、开源的、易于使用的编程语言,旨在为初学者提供简单易用的编程环境。 Thonny的语法简洁易懂,同时还支持自动补全和语法高亮,使得编程变得更加便捷。

搜索
小鹏STEM教研服务

专属教研服务系统,助您构建STEM课程体系,打造一站式教学环境。