在CircuitPython中整合BSEC(正在进行的工作)。

关于使用USER_C_MODULES构建标志的一些指导意见

这篇博文将涉及到两个不同的主题。一方面,我将谈论在你的自定义构建的C语言中包含和测试你自己的C代码的一般方法。 循环器(CircuitPython .另一方面,我将谈及在使用《中国国家图书馆》方面的具体挑战。 BME688分线板该项目基于博世的BME688传感器,具体的分线板由我们设计,并在RP2040上使用他们的BSEC库。该库允许对BME688提供的传感器数据进行高级分析,并基于该传感器数据进行计算。

用CircuitPython包装你自己的C代码或静态库的好处是相当明显的。很多微控制器板,在本例中是基于RP2040的Raspberry Pi Pico,允许执行C代码。编写纯C语言可能是令人生畏的,特别是对于那些还没有花很多时间使用这种语言的程序员。另一方面,CircuitPython通过Python语法提供了方便的访问,有很多写得很好的库和一个伟大的社区来帮助你。

我们的目标是测试理论上是否有可能包住BSEC库。这个库提供给众多的平台和编译器,包括Cortex M0+和 arm-none-eabi-gcc编译器.

虽然围绕BSEC的工作可能是针对我们的情况,但我将提供一些更普遍的指导,即如何在CircuitPython中包含一个自定义编写的C-Module以快速测试其功能,如何链接一个额外的二进制库,以及如何构建CircuitPython以便同时包含C-Module和库。在这一过程中,有一些小的陷阱,我希望这篇博文能涵盖这些陷阱。

如果你想编写自己的CircuitPython模块,目前有两种不同的方法。你可以在官方指南中读到第一种方法,即 Adafruit网站 这本书目前已经过时了,但仍然包含很多有用的信息。因此,推荐的方法是看一下CircuitPython的源代码,并以它为例。在不做过多说明的情况下,这是基于将你的头文件和源代码文件分别放入 "shared-bindings "和 "shared-module "目录,同时使用提供的封装方法。

如果你的目标是长期使用或为正式版本做贡献,你应该遵循这些准则。如果你首先想看看代码是否能在一个特定的平台上运行,或者做一些快速测试,这里描述的方法会更容易一些,工作强度也更小。

如何使用USER_C_MODULES?

首先,我们通过使用官方说明来构建CircuitPython的过程,这些说明可以找到 这里.在确保一切按计划进行,CircuitPython在你的目标平台上构建和运行后,我们可以开始工作,包括我们自己的代码。这是通过USER_C_MODULES构建标志完成的。这个功能是从MicroPython继承来的。如果你有兴趣,你可以看一下官方的 MicroPython文档 这似乎也适用于CircuitPython。

首先,我们在CircuitPython目录下创建一个新的文件夹,并将必要的文件填入其中。

电路图
├──circuitpython/。
| ├──数据
| ├──设备
| ├──docs/
... ...
|
└──外部模块
        └──BSEC_Test
                ├── bsec_datatypes.h
                ├── bsec_interface.h
                ├── libalgobsec.a
                ├── micropython.mk
                └── testingBSEC.c

在这种情况下,'bsec_datatypes.h'、'bsec_interface.h'和'ibalgobsec.a'是由Bosh提供。我们只需要担心mircopython.mk和testingBSEC.c。

事实证明,CircuitPython已经包括了一个C(和C++)的例子和它各自的Makefile在源代码中。你可以在下面找到它。

circuitpython/examples/usercmodule/cexample/。

我们可以简单地把代码复制过来,然后根据自己的需要进行编辑。要做到这一点,我们要包括我们要使用的库的头文件(在我们的例子中是#include "bsec_interface.h"),并修改其中的代码。examplemodule.c "是一个很好的例子,因为它包含一个非常基本的函数,它接受整数输入并产生整数输出。根据我们的要求对其进行编辑,主要是改变输入变量的数量和重命名一些函数。如果你的目标仅仅是测试大规模集成的可行性,这可能就足够了。这可以通过返回错误代码和一些样本输出并检查其是否符合预期来轻松实现。否则,添加新的函数或对现有的函数进行更根本的改变并不十分困难,在MicroPython文档中也有很好的描述。

你已经可以把它留在那里了。根据你的测试案例的复杂性,可能有必要添加更多的功能,但在我们的案例中,主要目标只是看看代码是否运行。

此外,我们修改Makefile - micropython.mk - 看起来像这样。

bsec_test_dir := $(usermod_dir)
# 将我们的C文件添加到SRC_USERMOD。
SRC_USERMOD += $(BSEC_TEST_DIR)/testingBSEC.c
# 将预编译的库添加到SRC_USERMOD。
SRC_USERMOD += $(BSEC_TEST_DIR)/libalgobsec.a

然后,我们只需像官方文档中描述的那样,继续构建CircuitPython。

  • 1.进入你想要构建的端口的目录(在我们的例子中是 circuitpython/ports/raspberrypi)。
  • 2. Make BOARD=raspberry_pi_pico USER_C_MODULES=./././externalCmodules

构建标志指向我们将代码和库放入的目录。

构建过程中的问题

如果你到目前为止非常严格地按照说明行事,你会遇到第一个问题。构建系统没有找到库(ibalgobsec.a)。

在构建过程中,构建系统似乎在两个不同的地方寻找它。在我们的例子中,是在以下两个地方。

电路图
├──circuitpython/。
| ├──数据
| ├──设备
| ├──docs/
| └──BSEC_Test
| └── libalgobsec.a
...
|
└──externalCmodules/?
        └──BSEC_Test
                ├── bsec_datatypes.h
                ├── bsec_interface.h
                ├── libalgobsec.a
                ├── micropython.mk
                └── testingBSEC.c

这个障碍显然起源于构建系统与USER_C_MODULE构建标志的交互方式。即使花了不少时间来研究它,我尝试的每一个解决方案都在某些方面存在缺陷,或者引入了更多的复杂性。如果有人读到这篇文章并找到了一个更简洁的解决方案,我将非常感谢你的分享在这种情况下,我将相应地编辑文本。

值得庆幸的是,这个问题可以通过复制库并将其放置在第二个位置而轻松避免。虽然这显然不是最干净的解决方案,但在最终的构建中没有大小差异。

如果你试图让你自己的代码工作,这应该是你所需要的全部,以允许进一步的测试。通过规避这个小问题,你自己的代码和库应该已经编译、正确链接、构建并可调用。

但我们的测试案例,即黑海经济合作组织呢?

如果你遵循这个过程,你很快就会感到失望。你会发现自己面对的是关于未定义函数的错误信息。

/home/hanno/System/bin/ARM_GCC/gcc-arm-one-eabi-10-2020-q4-major/bin/./lib/gcc/arm-one-eabi/10.2.1/./././arm-one-eabi/bin/ld:IaqEstimator.c:(.text+0xea): 未定义对`fminf'的引用
/home/hanno/System/bin/ARM_GCC/gcc-arm-one-eabi-10-2020-q4-major/bin/./lib/gcc/arm-one-eabi/10.2.1/./././arm-one-eabi/bin/ld:IaqEstimator.c:(.text+0x112): 对`fmaxf'未定义的引用
/home/hanno/System/bin/ARM_GCC/gcc-arm-one-eabi-10-2020-q4-major/bin/./lib/gcc/arm-one-eabi/10.2.1/./././arm-one-eabi/bin/ld:IaqEstimator.c:(.text+0x162): 对`fmaxf'未定义的引用
/home/hanno/System/bin/ARM_GCC/gcc-arm-one-eabi-10-2020-q4-major/bin/./lib/gcc/arm-one-eabi/10.2.1/./././arm-one-eabi/bin/ld:IaqEstimator.c:(.text+0x190): 对`fmaxf'未定义的引用
/home/hanno/System/bin/ARM_GCC/gcc-arm-one-eabi-10-2020-q4-major/bin/./lib/gcc/arm-one-eabi/10.2.1/./././arm-one-eabi/bin/ld:IaqEstimator.c:(.text+0x198): undefined reference to `fminf'.
........

嗯,事实证明,目前存在一个主要障碍。由于CircuitPython是为了在微控制器上运行,而这些微控制器的内存往往相当有限,所以开发人员编写并使用他们自己的数学库。虽然这可能是没有问题的,取决于你的个人使用情况,但BSEC使用标准C数学库提供的功能。虽然有一个buildflag可以用标准C数学库来构建CircuitPython(circuitpython/ports/raspberrypi/mpconfigport.mk → INTERNAL_LIBM),但它目前似乎已经失效了。让它再次工作需要额外的时间,需要对构建系统有很好的了解,而且对于我们的小测试案例来说,走得有点远了。

但是有一个(有点 "黑 "的)解决方案,至少可以让BSEC初始化并给出一些基本信息,证明它的用法在理论上可能是可以整合的。我们或者简单地在我们的C代码中通过使用internal_libm提供的内置数学函数来包装或重新实现缺少的函数。这可以看起来像下面这样。

float fminf ( float x, float y ) {
    如果(isan(x))
		返回y。
	如果(isan(y))
		返回x。
	//处理有符号的零,见C99附件F.9.9.2
	如果 (signbit(x) != signbit(y))
		返回 signbit(x) ? x : y;
	返回 x < y ? x : y。
}

在大多数情况下,代码来自或略微改编自 arm-none-eabi-gcc编译器 它是开放源码的,可以毫无问题地查看。

现在CircuitPython建立起来了,BSEC可以被调用并返回适当的值。尽管如此,在尝试使用某些功能时仍然存在一些问题。看起来这些问题很可能是CircuitPython构建过程的结果,因为如果BSEC与C语言一起使用,这些问题就会消失。为了使BSEC能够完整地运行,并且能够从CircuitPython内部轻松调用,有必要进行一些协调,以获得BSEC的正确版本(目前使用ARM GNU工具链的9-2019-q4-major版本构建,而CircuitPython使用10-2020-q4-major版本),并对CircuitPython的构建过程进行轻微修改和适应。未来我们是否会这样做还有待观察,但我希望这篇博文可以为那些有兴趣通过使用USER_C_MODULES buildflag测试自己的代码并希望避免一些陷阱的开发者提供一些方向。

如果我们的进展有任何更新,本页面将相应更新。

如果你有进一步的问题,而我没有足够详细地介绍(或根本没有),请随时留言或通过电子邮件联系我!我很乐意回答。我很乐意回答。

发表评论

你必须是登录才能发表评论。