65.9K
CodeProject 正在变化。 阅读更多。
Home

将 EspMon 移植到 ZephyrOS 并运行在 STM32 板上(或其他板子上,只需稍作修改)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2023年7月25日

MIT

10分钟阅读

viewsIcon

4525

downloadIcon

51

使用 Zephyr RTOS 和我的 IoT 生态系统的速成课程。

Zephyr_Mon

引言

前方可能有危险。

请仔细阅读本文,因为它非常重要。例如,在“子清单”部分,有些内容必须从文章中复制并粘贴到 Zephyr 根目录之外的一个文件中。

如果您从未进行过任何物联网或嵌入式编程,甚至您使用过 Arduino 但对其不熟悉,那么这篇文章不适合您。您将无法使用 fancy IDE,也无法依赖庞大而有用的社区,尽管至少可以通过一些对 .cpp_properties 文件进行修改来使用 VS Code 的 Intellisense。这里没有任何东西是轻松就能获得的。您已被警告。

如果您想继续在 Zephyr 平台上的开发,可以考虑加入 zephyrproject Discord 服务器和 /r/embedded subreddit。这两个平台都有一些乐于助人的人,尽管这方面文档稀少,用户群和社区都相对较小(至少公开的)。

必备组件

获取一些 VS Code 的优势。如果您喜欢其他编辑器,也可以使用,但本文假定您使用 VS Code。

购买一块 STM32 Nucleo H723GZ 板。您可以尝试在其他板子上运行,方法是创建一个新的覆盖文件,其中包含适当的设备引用和总线设置。我尝试过我的 Nucleo H745ZI,但不幸的是,Zephyr 尚未为其提供完整的板级支持,因此目前不支持 SPI - 这是我们的显示屏所必需的。更新:GitHub 仓库还包含了对 Nucleo F767ZI 的支持,我认为这款板子更受欢迎。接线方式与所有 Nucleo 144(较大尺寸)板子相同。

找到一块 ILI9341 显示屏,采用 3 线或 4 线 SPI 格式(MISO 将不被使用)。

您需要从 EspMon Reboot 文章中获取配套应用程序。

作为对您能力的考验,请设置 Zephyr 开发环境和 West 构建系统。如果您做不到,请将其视为本文其余部分的验证码。除非您能跨过这道坎,否则无人能继续。请注意,我在 Windows 11 上通过 Chocolatey 安装 "dtc-msys2" 组件时遇到了一个错误。它继续安装,并且我在后续完整构建项目时收到一个警告,但我尚未发现它导致任何问题。另外,pip 或其他组件可能会抱怨有新版本,但我建议保持不变。CMake 和您通过 Zephyr 和/或 West 安装的任何其他组件也是如此。请注意,令人不安的是,它似乎会在根目录下的“zephyr”中创建一个看起来像是自身的副本,如果您按照所有说明操作,它会变成 zephyrproject/zephyr。它实际上不是副本,尽管可能只是部分副本。请保留它。您可能需要创建一个批处理文件,在构建环境 shell 中调用 python。我在 zephyrproject 下创建了一个 zephyr.cmd

为了熟悉,请阅读 EspMon Reboot 文章 这里(上面也有链接),但请注意,我将更贴近 GitHub 代码进行跟进,因为它更新。我没有更新文章和代码中的最新内容,因为它们更复杂。概念和流程是相同的。只是结构略有不同,并且进行了重构以支持更多平台和框架。

也就是说,我们不会直接扩展那个项目,而是在 zephyrproject/zephyr/applications/zepyhr_mon 下创建一个新的 zephyr 项目,并基本上将代码从另一个项目复制过来 - 我已经完成了这项工作,并提供了完整的项目。您可能需要创建 applications 文件夹。我将我的项目放在 zephyr 结构下,因为文档建议这样做,而且我不想混淆本已复杂的构建系统。您可以下载本文顶部的 zip 文件,但我建议从提供的 Github 链接克隆到 zephyrproject/zephyr/applications/zephyr_mon

理解这个项目

我们不会过多地介绍代码,因为它与 esp_mon2 GitHub 代码基本相同,并且与相关文章的代码密切相关,甚至比之前的 GitHub 代码稍有简化。

设备树 (Devicetree)

任何项目的核心都是 设备树 - 以 .dts 文件表示,一种混合了 JSON 和 C++ 的奇怪的混合语言。在成功构建一次后,您的项目会在 build/zephyr 下有一个名为 zephyr.dts 的主设备树文件。您将主要参考它来获取设备名称和设置。

您可以通过“覆盖”来覆盖、增强甚至删除主文件的部分内容。这是 Zephyr 中初始化和配置所需设备的标准方法。默认情况下,您的主板的大部分功能将被禁用,等待您通过 devicetree 条目启用它,您将在其中配置设备的属性并使其可供您的代码访问。

#include <zephyr/dt-bindings/display/ili9xxx.h>
/ {
    aliases {
        command-serial = &usart3;
    };
    chosen {
        zephyr,display = &ili9340;
    };
    zephyr,user {
        // backlight
        bl_gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>;
    };    
};
&usart3 {
    compatible = "st,stm32-usart", "st,stm32-uart";
    status = "okay";
    current-speed = <115200>;
};
&arduino_spi {
    status = "okay";
    cs-gpios = <&gpioa 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
    ili9340: ili9340@0 {
        compatible = "ilitek,ili9340";
        spi-max-frequency = <20000000>;
        reg = <0>;
        reset-gpios = <&gpiof 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
        cmd-data-gpios = <&gpiod 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
        width = <320>;
        height = <240>;
        pixel-format = <ILI9XXX_PIXEL_FORMAT_RGB565>;
        rotation = <270>;
        frmctr1 = [00 18];
        pwctrl1 = [23 00];
        vmctrl1 = [3e 28];
        vmctrl2 = [86];
        pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00];
        ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f];
    };
};

第一行是一个 include,它的工作方式与 C++ 中的一样。实际上,它会被复制到从该设备树信息集生成的 C++ 代码中。

之后,我们用一些内容来增强根 / 节点。

首先,我们为我们的串行 UART 声明一个别名 - 我们将其命名为 command-serial。这使得在代码中引用它变得容易,同时也可以在 devicetree 中为不同的板子进行配置。

第二个块使用 ili9340 设备设置显示子系统,该设备在文件更下方被声明。我们也可以使用控制台子系统来包装 UART,但由于我们使用的是二进制数据,并且我遇到过它们在至少一个区域没有按照规范实现 stdio.h 的问题,所以我直接使用了 UART 本身。

第三个块是用于用户定义属性的部分。由于 GPIO 不是设备,我们无法使用上述任何块来声明它。我们为此创建一个用户属性,并在代码中通过该属性引用它。

在设置显示屏之前,我们必须配置我们的 UART。我们使用 usart3,因为在此特定板子上,它连接到嵌入式 ST-Link 硬件暴露的虚拟 COM 端口。其他真正重要的部分是启用设备(status = "okay")和设置当前波特率。compatible 属性必须与它引用的给定设备匹配,否则该节点将被忽略(我猜是这样 - 我从未实际测试过这个假设)。

现在来看两件事 - 配置我们的 SPI 设备以及 ILI9340 设备驱动程序。您会看到我们引用了 &arduino-spi,在我们的板子上,它是 Arduino 扩展板接口上暴露的 SPI 总线的别名。主要部分是设置 CS 线,因为在这个板子上它有两个可能的值之一,以及设置通过总线通信的速度。

您会看到 ILI9340 驱动程序嵌套在 SPI 总线声明中。这样您就可以告诉 devicetree 给定的设备是通过某个总线连接的。在 ILI9340 驱动程序内部,有 几个属性,用于配置显示屏的各种方面。它们的作用大多是显而易见的,但超出了本文的范围。很多属性对于使用过这些显示屏的人来说应该很熟悉。

您可以为任何给定的板子创建一个新的覆盖文件,只要它具有必要的硬件,代码应该就能正常工作。代码无需更改,除非您做了类似更改显示控制器硬件的操作。

我通过在线查找示例以及我在上面提到的 Discord 服务器上获得的一些帮助来弄清楚了这一切。目前我对这方面的知识还有很多不足,所以提供上述信息是为了让您知道在哪里可以找到更多信息。直接搜索 Google 可能找不到太多内容,因此 Discord 是无价的。

通过 prj.conf 配置您的项目

除了创建项目时的覆盖文件外,prj.conf 文件也非常重要。它包含大量潜在属性,以 CONFIG_ 开头,通常以 =y 结尾。这些属性用于启用项目的各种功能。它的文档不是很好,其中一部分原因是这些属性是由单个模块定义的,而这些模块是任意的,因此属性本身也是任意的,类似于 C 头文件中的 #defines。我建议将此项目中的文件复制到您开始的任何新项目中,然后删除您不需要的部分。

其中一些很重要但并不明显,例如 CONFIG_NEWLIB_LIBC。这个属性尤其关键,再加上与 C++ 相关的属性,才能使用我的图形库。默认情况下,使用的 C 库是最小化的,并且不符合 C99 标准,因为其中很多内容都被删除了。上述配置属性启用了符合完整规范的 C 库。此外,我的库要求 C++17。

以下是启用我整个 Zephyr 化生态系统(包括需要其余组件的 UIX)所需的内容

CONFIG_HTCW_BITS=y
CONFIG_HTCW_IO=y
CONFIG_HTCW_ML=y
CONFIG_HTCW_DATA=y
CONFIG_HTCW_GFX=y
CONFIG_HTCW_UIX=y
CONFIG_CPP=y
CONFIG_STD_CPP17=y
CONFIG_PICOLIBC=y

过渡到子清单 (Submanifests)

这里没有合适的位置放置它,因为它属于带外内容,所以将放在文章中。

某些库(例如我的 htcw 物联网和嵌入式生态系统)与 Zephyr 兼容,但它们不在官方模块存储库中。因此,为了使用它们,您必须通过在 zephyrproject/zephyr/submanifests 中创建一个 .yaml 文件来添加它们。您必须创建 submanifests 文件夹。这些 yaml 文件由构建系统用来获取库的本地副本。要使用我的生态系统,您需要以下文件,我将其命名为 htcw.yaml

manifest:
  projects:
    - name: htcw_bits
      url: https://github.com/codewitch-honey-crisis/htcw_bits
      revision: master
    - name: htcw_io
      url: https://github.com/codewitch-honey-crisis/htcw_io
      revision: master
    - name: htcw_ml
      url: https://github.com/codewitch-honey-crisis/htcw_ml
      revision: master
    - name: htcw_data
      url: https://github.com/codewitch-honey-crisis/htcw_data
      revision: master
    - name: htcw_gfx
      url: https://github.com/codewitch-honey-crisis/gfx
      revision: master
    - name: htcw_uix
      url: https://github.com/codewitch-honey-crisis/uix
      revision: master 

要实际下载它们,您需要调用

west update

在 zephyrproject/zephyr 内部执行此操作。

不幸的是,VS Code 不会自动为这些文件找到包含文件。因此,您必须将每个子模块的包含文件夹路径添加到 .cpp_properties 中,如下所示

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "windowsSdkVersion": "10.0.22000.0",
            "compilerPath": "cl.exe",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "windows-msvc-x64"
        },
        {
            "name": "ARM",
            "includePath": [
                "C:/Users/username/zephyrproject/**",
                "C:/Users/username/zephyrproject/zephyr/**",
                "${workspaceFolder}/**",
                "C:/Users/username/zephyrproject/htcw_bits/include",
                "C:/Users/username/zephyrproject/htcw_io/include",
                "C:/Users/username/zephyrproject/htcw_ml/include",
                "C:/Users/username/zephyrproject/htcw_data/include",
                "C:/Users/username/zephyrproject/htcw_gfx/include",
                "C:/Users/username/zephyrproject/htcw_uix/include",
                "${workspaceFolder}"
            ],
            "defines": [],
            "windowsSdkVersion": "10.0.22000.0",
            "compilerPath": "C:/mingw64/bin/g++.exe",
            "cStandard": "c99",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "windows-gcc-arm64",
            "compileCommands": "C:/Users/username/zephyrproject/zephyr/build/compile_commands.json"
        }
    ],
    "version": 4
}

您可以在 includePath 下看到所有路径。如果您有更好的方法,请告知我。

为了实际加载模块并在您的项目中使用它们,在第一次构建之前,在您的虚拟环境和您的项目目录中执行以下命令

west update

CMakeLists.txt

您的项目文件夹中需要一个这样的文件。内容大致如下

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(zephyr_mon)
target_sources(app PRIVATE src/main.cpp src/ui.cpp)

这大部分是样板代码。只需确保在 project() 中设置项目名称,并在 target_sources() 中保持 C 和 C++ 源文件列表的最新。

使用这个烂摊子

按照 wiring.txt 中的说明接线。

从前面链接的 EspMon Reboot 文章中下载项目。您将需要 .NET 配套应用程序来使用此项目。

然后从项目目录中刷写板子

(.venv) C:\Users\username\zephyrproject\zephyr\applications\zephyr_mon\west build -b nucleo_h723zg
(.venv) C:\Users\username\zephyrproject\zephyr\applications\zephyr_mon\west flash

它应该显示一个白色屏幕上的断开连接图标 - 实际上它是一个 SVG 文档,但这无关紧要。

运行 PC 配套应用程序(它会请求提升的权限 - 允许它们),然后检查/选择与板子关联的 ST-Link 虚拟 COM 端口。勾选“started”复选框,您应该会看到设备上的屏幕变为一个监视器屏幕,显示 CPU 和 GPU 的使用率和温度。

Bug

Zephyr 可以使用的 newlib 中存在一些 bug。例如,控制台子系统的 getchar() 函数在没有输入时返回 0 而不是 -1。我已将项目切换到 picolib,尽管我之前已经解决了这个问题。Picolib 由 Zephyr 项目维护。如我所说,前面可能有危险。

结论

Zephyr 有相当陡峭的学习曲线,而且文档还可以改进。话虽如此,它是在不同板子上快速切换的最好选择,这可以极大地帮助解决硬件采购问题。

历史

  • 2023年7月25日 - 首次提交
© . All rights reserved.