我们喜欢 CircuitPython,并希望看到它出现在更多的微控制器平台上。自 3.0 以来,我们重新设计了 CircuitPython,使其比以往任何时候都更容易添加支持。虽然端口之间存在一些主要差异,但本页面涵盖了使 CircuitPython 成为现实的相似之处,以及该内核如何适合各种微控制器。
建筑学¶
CircuitPython 有三个核心部分:
第一个是出色的 MicroPython 开发人员创建的 Python VM。这些 VM 被编写为可移植的,因此在移动到不同的微控制器时不需要太多,特别是如果它是基于 ARM 的。
第二个是围绕这些 VM 的基础设施,它提供超级基本的操作系统功能,例如初始化硬件、运行 USB、准备文件系统和在启动时自动运行用户代码。在 CircuitPython 中,我们将此组件称为主管,因为它监视并促进运行用户 Python 代码的 VM。移植涉及主管,因为它在与硬件接口时执行许多任务。一旦完成,REPL 就可以工作并且调试可以迁移到基于 Python 的方法而不是 C。
第三个核心部分是 CircuitPython 提供的大量低级 API,作为包括设备驱动程序在内的高级库的基础。这些 API 是通过shared-bindings
. 这些绑定依赖底层
common_hal
C API 来实现 Python API 所需的功能。通过将两者分开,我们努力确保标准功能,这意味着库和示例以最小的更改跨端口应用。
移植¶
第 1 步:开始建造¶
移植到新微控制器的第一步是运行构建。它的主要目标应该是 main.c
在supervisor/supervisor.mk
文件的帮助下进行编译。端口特定代码应与端口目录隔离(在顶级目录中,直到该ports
目录存在)。这包括 Makefile 和任何 C 库资源。确保这些资源与其余代码的 MIT 许可证兼容!
Circuitpython 在
py/circuitpy_mpconfig.mk
. 大多数这些模块需要在mpconfigboard.mk
移植的早期阶段被禁用 才能编译。随着模块支持端口的进展,这个列表可以被精简为一个自然的“TODO”列表。下面显示了一个示例最小构建列表:
# These modules are implemented in ports/<port>/common-hal:
# Typically the first module to create
CIRCUITPY_MICROCONTROLLER = 0
# Typically the second module to create
CIRCUITPY_DIGITALIO = 0
# Other modules:
CIRCUITPY_ANALOGIO = 0
CIRCUITPY_BUSIO = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_PULSEIO = 0
CIRCUITPY_OS = 0
CIRCUITPY_NVM = 0
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_AUDIOIO = 0
CIRCUITPY_ROTARYIO = 0
CIRCUITPY_RTC = 0
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0
# Requires SPI, PulseIO (stub ok):
CIRCUITPY_DISPLAYIO = 0
# These modules are implemented in shared-module/ - they can be included in
# any port once their prerequisites in common-hal are complete.
# Requires DigitalIO:
CIRCUITPY_BITBANGIO = 0
# Requires DigitalIO
CIRCUITPY_GAMEPADSHIFT = 0
# Requires neopixel_write or SPI (dotstar)
CIRCUITPY_PIXELBUF = 0
# Requires OS
CIRCUITPY_RANDOM = 0
# Requires OS, filesystem
CIRCUITPY_STORAGE = 0
# Requires Microcontroller
CIRCUITPY_TOUCHIO = 0
# Requires USB
CIRCUITPY_USB_HID = 0
CIRCUITPY_USB_MIDI = 0
# Does nothing without I2C
CIRCUITPY_REQUIRE_I2C_PULLUPS = 0
# No requirements, but takes extra flash
CIRCUITPY_ULAB = 0
第 2 步:初始化¶
一旦您的构建设置完成,下一步应该是让您的时钟按照您对主管的期望。主管调用port_init
以允许在 main 开始时进行初始化。该函数还具有请求安全模式状态的能力,该状态可防止主管运行用户代码,同时仍允许访问 REPL 和其他资源。
核心端口初始化和复位方法在中定义
supervisor/port.c
并且应该首先被实现。要求它们supervisor
在端口目录中的目录中实现。这样,它们总是在预期的位置。
监督员还使用了三个变量连接器,_ezero
, _estack
并
_ebss
确定堆栈溢出检查内存布局。
第 3 步:REPL¶
让 REPL 运行是一个巨大的进步。它涉及一系列要正确完成的初始化,这是一个好兆头,您在移植方面做得很好。要使 REPL 运行,您必须
supervisor/serial.h
使用 supervisor/serial.c
port 目录中的相应函数和定义来实现 。这涉及通过某种串行连接发送和接收字符。例如,它可以是 UART 或 USB。