如上一篇文章所述,唯一经认证可运行 Azure Sphere OS 的设备是 MT3620。它包含三个处理内核:一个通用 Cortex-A7 内核和两个实时 Cortex-M4 微控制器内核。Azure Sphere OS 在 Cortex-A7 内核上运行。
因为有两种类型的内核,开发人员可以编写两种类型的应用程序。高级应用程序以Cortex-A7 为目标,而实时应用程序或RTApp
以其中一个 Cortex-M4 内核为目标。高级应用程序在 Azure Sphere OS 上运行,实时应用程序在裸机或实时操作系统 (RTOS) 上运行。
您可以在没有任何实时代码的情况下编写高级应用程序,但所有实时代码都必须打包在高级应用程序中。准确地说,构建过程会生成一个名为image package的文件,该文件部署到 MT3620。
为了演示这一点,本文的第一部分将介绍一个打开和关闭 LED 的项目的编译和部署。本文的第二部分更深入,并解释了如何编写和配置使用按钮按下来控制 LED 的高级应用程序。
为 Azure Sphere 构建映像包是一个复杂的过程,因此最好先处理现有项目,然后再创建自己的项目。为此,Visual Studio Code 提供了 Blink 项目,本节介绍构建和部署该项目所需的任务,首要任务是准备开发板。
默认情况下,您无法在 MT3620 上调试应用程序。要将板子配置为运行/调试代码,您需要在命令行中输入以下命令:
<span style="color:#000000"><span style="background-color:#fbedbb">azsphere device enable-development</span></span>
这允许为设备部署高级应用程序。正如我将在后面的文章中解释的那样,您需要添加一个配置标志来启用实时应用程序的部署。
要在 Visual Studio Code 中创建 Blink 项目,需要六个步骤:
此时,Visual Studio 代码会将文件和文件夹添加到项目中。其中包括:
CMakeLists.txt尤其重要,因为它定义了构建项目所需的步骤。它标识了项目的名称 (Blink)、编程语言 (C)、可执行文件的名称 (Blink) 以及构建可执行文件所需的库(libapplibs.so、libpthread.so和libgcc_s.so)。它还使用以下行标识目标硬件:
<span style="color:#000000"><span style="background-color:#fbedbb">azsphere_target_hardware_definition(${PROJECT_NAME}
TARGET_DIRECTORY "HardwareDefinitions/mt3620_rdb"
TARGET_DEFINITION "template_appliance.json")</span></span>
这表明硬件定义可以在HardwareDefinitions/mt3620_rdb文件夹中找到。如果您使用的是参考开发板,这很好,但如果您不是,则需要更改它。如果您使用的是 Avnet 的 MT3620 入门套件,您需要将mt3620_rdb更改为avnet_mt3620_sk。如果您使用的是 Seeed Studio 的迷你开发板,您需要将mt3620_rdb更改为seeed_mt3620_mdb。
确定目标硬件后,您可以通过打开命令面板 ( Ctrl - Shift-P ) 并执行CMake: Build来构建 Blink 项目。构建操作包括四个步骤:
azsphere image-package pack-application
命令创建镜像包。最后一步很重要,要理解。要创建映像包,该azsphere image-package pack-application
命令接受多个标志,包括:
input
- 包含已编译源文件的目录 ( *.o )output
-要创建的图像包 ( *.imagepackage ) 的名称和位置application-manifest
- 提供项目信息的文件hardware-definitions
- 将板的外围设备映射到值的文件在这个项目中,output
标志设置为out/ARM-Debug/Blink.imagepackage。因此,构建过程会在项目的out/ARM-Debug文件夹中生成一个名为Blink.imagepackage的文件。
要将映像包部署到开发板,请通过按F5或在主菜单中选择Run > Start Debugging来启动调试会话。这将删除板上运行的应用程序并使用所需的库部署映像包。部署完成后,板上的 LED 将开始闪烁。
此过程还将 gdbserver 部署到开发板上。这允许您设置断点并单步执行项目代码,就好像它在您的计算机上运行一样。
现在您可以让 LED 闪烁,是时候查看一个自定义编码的应用程序了,该应用程序会在用户按下按钮时切换 LED。本文随附的buttonpress.zip文件包含该ButtonPress
项目。这不是很令人兴奋,但很容易理解和测试。
本节介绍ButtonPress
项目的工作原理。但在展示源代码之前,我需要解释一下Applibs
库提供的功能。特别是,我需要解释如何访问开发板的通用输入/输出 (GPIO) 引脚。
链接过程将编译后的代码与称为库的预构建代码文件相结合。在版本 11 中,SDK 在Sysroots\11\usr\lib文件夹中提供了用于高级应用程序的库。最重要的库是libapplibs.so,它提供了访问 MT3620 和开发板功能的函数。
要访问这些函数,源文件需要在Sysroots\11\usr\include\applibs目录中包含一个或多个头文件。总共有 34 个头文件,它们的名称标识了它们声明的函数的类型。例如,log.h包含用于记录的函数,wificonfig.h包含配置 WiFi 的函数,adc.h包含访问模数转换器 (ADC) 的函数。
每个开发板都提供可配置为读取输入和/或写入输出的引脚。这些被称为通用输入/输出 (GPIO) 引脚。板上的所有 LED 和按钮都连接到 GPIO 引脚,要访问它们,我们需要调用gpio.h中的函数。表 1 列出了这些函数中的每一个。
表 1:gpio.h 中的 GPIO 函数
函数名称 | 描述 |
GPIO_OpenAsInput(GPIO_Id, gpioId) | 配置 GPIO 引脚以接收输入 |
GPIO_OpenAsOutput(GPIO_Id, gpioId, GPIO_OutputMode_Type outputMode, GPIO_Value_Type initialValue) | 配置 GPIO 引脚以提供输出 |
GPIO_GetValue(int gpioFd, GPIO_Value_Type *outValue) | 读取输入引脚的值 |
GPIO_SetValue(int gpioFd, GPIO_Value_Type value) | 设置输出引脚的值 |
ButtonPress
应用程序读取按钮的状态并使用它来设置 LED 的状态。因此,按钮的 GPIO 引脚应配置为输入,LED 的 GPIO 引脚应配置为输出。配置引脚后,应用程序应调用GPIO_GetValue
以访问按钮的状态并GPIO_SetValue
设置 LED 的状态。
您可以通过查看Blink 项目中的main.c文件来了解其工作原理。以下代码将 LED 引脚配置为输出引脚:
<span style="color:#000000"><span style="background-color:#fbedbb">GPIO_OpenAsOutput(TEMPLATE_LED, GPIO_OutputMode_PushPull, GPIO_Value_High);</span></span>
GPIO_OpenAsInput
和的第一个参数GPIO_OpenAsOutput
标识要配置的引脚。在此代码中,引脚用 标识TEMPLATE_LED
,在template_appliance.h头文件中声明。此标头是从template_appliance.json生成的,它是项目的硬件定义文件。
每个项目都需要一个硬件定义文件,以便源代码可以访问开发板的功能。文件的名称和位置必须在CMakeLists.txtazsphere_target_hardware_definition
的命令中设置。在 Blink 项目中,这个命令给出如下:
TARGET_DIRECTORY
设置包含硬件定义文件的目录并TARGET_DEFINITION
设置其名称。每个硬件定义文件都使用 JSON 进行格式化,并定义了四个属性:
Metadata
- 文件的类型和版本Description
- 董事会名称和标题评论Imports
- 开发板的SDK定义文件Peripherals
- 可在代码中访问的开发板功能前两个属性很简单,但第三个和第四个值得解释。SDK 的安装目录包含一个名为HardwareDefinitions的文件夹,其中包含每个支持的开发板的 JSON 文件。这些文件与项目的硬件定义文件具有相同的结构,因此我将它们称为低级定义文件。
该Imports
属性标识目标开发板的低级定义文件。例如,Avnet 的 MT3620 Starter Kit 的文件是avnet_mt3620_sk.json,所以该Imports
属性必须设置如下:
<span style="color:#000000"><span style="background-color:#fbedbb"><span style="color:#800080">"</span><span style="color:#800080">Imports"</span> : [ {<span style="color:#800080">"</span><span style="color:#800080">Path"</span>: <span style="color:#800080">"</span><span style="color:#800080">avnet_mt3620_sk.json"</span>} ]</span></span>
该Peripherals
属性标识需要访问开发板的哪些功能。这被分配给一个元素数组,每个元素都有四个字段:
Name
- 在源代码中使用的用户定义 IDType
- 外围设备的类型(Gpio
、PWM
、Adc
等)Mapping
- 在低级定义文件中定义的特征 IDComments
- 要作为注释插入代码中的文本和字段在低级定义文件中给出Type
。Mapping
例如,avnet_mt3620_sk.json文件通过以下方式定义蓝色 LED:
低级定义文件avnet_mt3620_sk.json表示蓝色 LED 引脚的类型Gpio
和名称为AVNET_MT3620_SK_USER_LED_BLUE
. 要在代码中访问此引脚,项目的硬件定义文件必须包含将 LED 映射到用户定义 ID 的条目。以下条目显示了如何做到这一点:
如图所示,Mapping
硬件定义文件中的Name
字段与低级定义文件的字段相匹配。此外,两个条目都将 设置Type
为Gpio
。因此,可以通过名称在源代码中访问蓝色 LED BLUE_LED
。