C
创建NXP MCUXpresso IDE项目
本主题提供了创建一个NXP MCUXpresso IDE项目,并集成您的应用程序和平台源代码的逐步指南。
您需要MCUXpresso SDK版本2.14.0或更高版本,包括MCUXpresso IDE和ARM GCC工具链。您可以使用Qt在线安装程序提供的SDK,或者自行下载SDK。
如果您想自己构建SDK,请安装以下组件
- 所有工具链(这确保了包括ARM GCC和MCUXpresso文件)
- FreeRTOS
- VG-Lite GPU库
创建新项目
将SDK解压缩到您选择的一个目录,并遵循以下说明
- 启动MCUXpresso IDE并安装下载的SDK
- 通过选择窗口 > 显示视图 > 安装SDK来确保您可以看到SDK视图。
- 转到安装的SDK。
- 在视图中右键单击并选择导入文件夹...。如果您有SDK存档,也可以选择导入存档...。
- 选择文件夹/存档,然后选择打开将SDK导入到IDE中。
- 使用文件 > 新建 > 创建新的C/C++项目为i.MX RT1170 EVKB创建新项目。
- 选择evkbmimxrt1170板并选择下一步。
- 在下一屏中,选择MIMXRT1176DVMAA设备包。项目应具有以下设置
- 核心:将cm7核心设置为独立角色。
- 板:使用默认板文件
- 项目类型:使用C++项目
- 项目选项:将SDK调试控制台设置为UART。已选择复制源和导入其他文件。
请从以下列表中选择组件
- 操作系统
- RTOS > 核心 > FreeRTOS内核
- 驱动程序
- 设备 > SDK驱动程序
- anatop_ai
- clock
- common
- dcdc_soc
- elcdif
- gpio
- i2c
- iomuxc
- lcdifv2
- lpuart
- memory
- mipi_dsi
- nic301
- pmu
- pxp
- soc_mipi_csi2rx
- xip_device
- 设备 > SDK驱动程序
- CMSIS包含
- CMSIS > 核心 > CMSIS_Include_CM
- 设备 > CMSIS > MIMXRT1176_CMSIS
- 设备 > CMSIS > MIMXRT1176_system
- 实用工具
- 设备 > SDK 驱动 > lpuart_adapter
- 设备 > SDK 工具
- 断言
- 调试控制台
- 串行管理器
- 串行管理器 UART
- 板级组件
- 板级支持 > SDK 驱动 > xip_board
- 设备 > SDK驱动程序
- display-hx8394
- display-rm68191
- display-rm68200
- xmcd
- 抽象层
- 设备 > SDK驱动程序
- dc-fb-common
- dc-fb-elcdif
- dc-fb-lcdifv2
- display-common
- 设备 > SDK驱动程序
- 软件组件
- 设备 > SDK驱动程序
- display-mipi-dsi-cmd
- 列表
- 视频通用
- 设备 > SDK驱动程序
- 项目模板
- 板级支持 > SDK 项目模板 > evkbmimxrt1170
- 其他
- 设备 > 启动 > MIMXRT1176_startup
选择 下一步 以转到下一屏幕。
- 在 高级项目设置 中更改以下设置
- 设置浮点类型: FPv5-D16 (Hard ABI)
- 语言标准: GNU C++14 (-std=gnu++14)
选择 完成 以完成项目设置。
配置引脚并导入额外的 SDK 组件
- 使用 ConfigTools > 引脚 选项配置 NXP i.MX RT1170 引脚。有关更多信息,请参阅配置 NXP i.MX RT1170 引脚。
- 导入额外的 SDK 组件
- 右键单击项目并选择 导入。
- 选择 文件系统。
- 将
<SDK_PATH>/components/gt911
添加到 从目录 字段,并选择fsl_gt911.h/*.c
文件。 - 将
<PROJECT_NAME>/gt911
添加到 到文件夹 字段并选择 完成。 - 从
<SDK_PATH>/middleware/vglite
将以下目录(包括其文件和子目录)导入到<PROJECT_NAME>/vglite
inc
VGLite
VGLiteKernel
- 从
<SDK_PATH>/devices/MIMXRT1176/gcc
将startup_MIMXRT1176_cm7.S
导入到<PROJECT_NAME>/startup
。从项目中删除<PROJECT_NAME>/startup/startup_mimxrt1176_cm7.c/.cpp
。 - 从
<SDK_PATH>/rtos/freertos/freertos-kernel/portable/MemMang
将heap_4.c
导入到<PROJECT_NAME>/freertos/freertos-kernel/portable/MemMang
。
开发应用程序后端
- 创建 UI 通信器结构体
后端允许应用程序的 UI 与平台通信并从硬件获取所需信息。在这种情况下,通信器获取板上 LED 的状态。以下图表描述了两个组件之间的工作流程
- 在 项目资源管理器 中右键单击 源 文件夹并选择 新建 > 类。
- 将 UICommunicator 添加到 类名 字段。将 头文件 和 源文件 分别重命名为
uicommunicator.h
和uicommunicator.cpp
,然后选择 完成。 - 打开 uicommunicator.h 并修改它,如下所示
#ifndef UICOMMUNICATOR_H #define UICOMMUNICATOR_H #include <qul/singleton.h> #include <qul/property.h> #include <qul/eventqueue.h> struct UICommunicator : public Qul::Singleton<UICommunicator> { friend struct Qul::Singleton<UICommunicator>; enum Command { LED1State }; Qul::Property<bool> led1Status; void sendFromUI(Command command, bool commandData); void receiveToUI(Command command, bool commandData); private: UICommunicator(); UICommunicator(const UICommunicator &); UICommunicator &operator=(const UICommunicator &); }; struct CommandEvent { UICommunicator::Command command; bool commandData; }; class CommandEventQueue : public Qul::EventQueue<struct CommandEvent, Qul::EventQueueOverrunPolicy_Discard, 10> { public: void onEvent(const CommandEvent &commandEvent); }; namespace UI { void sendToThread(bool led1Data); } #endif // UICOMMUNICATOR_H
头文件声明了继承自
Qul::Singleton
的UICommunicator
结构体,使它与 UI 代码的集成变得简单易行。有关更多信息,请参阅Singleton 类参考。头文件还声明了定义一系列命令的
Command
枚举和用于管理队列的CommandEventQueue
。枚举使 UI 和应用程序之间的通信成为可能。UICommunicator
声明了led1Status
属性,用于指示板上 LED 的状态。此属性在 QML 上下文中可用,以确定按钮的颜色。《UICommunicator》类有
sendFromUI
和receiveToUI
方法用于发送和接收命令。它还有用于以线程安全方式与UI线程通信的CommandEventQueue
。不是从应用程序线程调用receiveToUI
,而是将命令添加到CommandEventQueue
。Qt Quick Ultralite 线程通过调用receiveToUI
来处理队列。 - 打开 uicommunicator.cpp 并将其修改如下
#include "uicommunicator.h" #include "app_thread.h" UICommunicator::UICommunicator() { led1Status.setValue(false); } void UICommunicator::sendFromUI(Command command, bool commandData) { QUL_UNUSED(command) App::sendToThread(commandData); } void UICommunicator::receiveToUI(Command command, bool commandData) { switch (command) { case LED1State: led1Status.setValue(commandData); break; default: break; } } void CommandEventQueue::onEvent(const CommandEvent &commandEvent) { UICommunicator::instance().receiveToUI(commandEvent.command, commandEvent.commandData); } static CommandEventQueue commandEventQueue; void UI::sendToThread(bool led1Data) { CommandEvent commandEvent; commandEvent.command = UICommunicator::LED1State; commandEvent.commandData = led1Data; commandEventQueue.postEvent(commandEvent); }
UICommunicator
类将led1Status
初始化为false
。其成员函数sendFromUI()
发送一个布尔值,指示LED的新状态到应用程序线程。receiveToUI()
成员函数使用命令参数来确定是否需要更新属性。接下来,
CommandEventQueue
类重写了onEvent()
函数,该函数在UICommunicator
实例上调用receiveToUI()
并传递参数command
和commandData
。此外,还创建了一个静态实例的CommandEventQueue
,该实例用于由UI::sendToThread()
函数来发布事件。UI::sendToThread()
从给定的布尔值构造了一个CommandEvent
并将其添加到commandEventQueue
以进行处理。这通常在LED的状态改变时从应用程序线程中调用。
创建一个适用于MCU的Qt CMSIS-Pack
CMSIS-Pack是一个不依赖于IDE的包,它包含在MCUXpresso IDE项目内设置Qt for MCUs应用程序所需的信息和文件。
- 使用
qmlprojectexporter
工具创建一个CMSIS-Pack。将
UICommunicator
接口添加到UI项目中- 打开
path/to/YourProject.qmlproject
- 在
Project
中添加以下内容InterfaceFiles { files: ["path/to/mcuxpresso/project/source/uicommunicator.h"] }
export QUL_ROOT=/path/to/QtMCUs/2.8.0 export QMLPROJECT_FILE=/path/to/YourProject.qmlproject export PLATFORM_METADATA=$QUL_ROOT/lib/QulPlatformTargets_mimxrt1170-evkb-freertos_32bpp_Linux_armgcc-export.json export BOARDDEFAULTS=$QUL_ROOT/platform/boards/nxp/mimxrt1170-evkb-freertos/cmake/BoardDefaults_32bpp.qmlprojectconfig export CMSIS_EXPORT_DIR=/output/dir/of/your/choice $QUL_ROOT/bin/qmlprojectexporter $QMLPROJECT_FILE --platform=mimxrt1170-evkb-freertos --toolchain=GCC --platform-metadata=$PLATFORM_METADATA --boarddefaults=$BOARDDEFAULTS --outdir=$CMSIS_EXPORT_DIR --project-type=cmsis
set QUL_ROOT=C:\path\to\QtMCUs\2.8.0 set QMLPROJECT_FILE=C:\path\to\YourProject.qmlproject set PLATFORM_METADATA=%QUL_ROOT%\lib\QulPlatformTargets_mimxrt1170-evkb-freertos_32bpp_Linux_armgcc-export.json set BOARDDEFAULTS=%QUL_ROOT%\platform\boards\nxp\mimxrt1170-evkb-freertos\cmake\BoardDefaults_32bpp.qmlprojectconfig set CMSIS_EXPORT_DIR=C:\output\dir\of\your\choice %QUL_ROOT%\bin\qmlprojectexporter.exe %QMLPROJECT_FILE% --platform=mimxrt1170-evkb-freertos --toolchain=GCC --platform-metadata=%PLATFORM_METADATA% --boarddefaults=%BOARDDEFAULTS% --outdir=%CMSIS_EXPORT_DIR% --project-type=cmsis
- 打开
- 将创建的CMSIS包导入到MCUXpresso IDE项目中
- 转到 CMSIS-Pack Manager 视图。
- 在 Packs 选项卡中,选择 Import Existing Packs... 按钮。
- 导航到由qmlprojectexporter指定的输出文件夹。包文件应在
CMSIS
文件夹中,命名为<YourProject>-mimxrt1170-evkb-freertos-<OS>-armgcc-cmsis.pack
。选择 Open。Pack应该显示在CMSIS-Packs列表中。 - 回到 Develop 视图。
- 在 Project Explorer 中右键点击项目名称。
- 转到 SDK Management > Add Open-CMSIS Components。
- 选择以下组件
- Graphics(变体:Qt for MCUs)
- Platform DeviceLink library(变体:FreeRTOS)
- Platform sources(变体:FreeRTOS)
- Qt Quick Ultralite头文件
- Qt Quick Ultralite库
- 项目
- Qt for MCU应用程序
- Graphics(变体:Qt for MCUs)
- 选择 Qt for MCUs Application 复选框旁边的较小按钮。这将启动 qmlprojectexporter,将Qt Quick Ultralite应用程序导出到项目中。
- 选择 应用并保存更改。
配置MCUXpresso IDE项目
- 选择项目并选择 文件 > 属性 以进行以下更改
- 选择 C/C++ General > Paths and Symbols > Source Location 并将以下内容添加到列表中
gt911
vglite
- 在 C/C++ General > Paths and Symbols > Includes 下的C++包含目录列表中添加以下包含路径。选择 添加到所有配置 和 添加到所有语言。对于此应用程序,添加以下包含目录
- 从工作区添加
gt911
- 从工作区添加
vglite/inc
- 从工作区添加
vglite/VGLite/rtos
vglite/VGLiteKernel
来自工作空间vglite/VGLiteKernel/rtos
来自工作空间
- 从工作区添加
- 选择 C/C++ General > Paths and Symbols > Symbols 并添加以下预处理器定义
- 适用于所有配置和语言
BOARD_MIPI_PANEL_TOUCH_IRQ GPIO2_Combined_16_31_IRQn
BOARD_MIPI_PANEL_TOUCH_IRQ_HANDLER GPIO2_Combined_16_31_IRQHandler
CPP_NO_HEAP
这将通过在cpp_config.cpp
中引入空实现来禁用默认的malloc
和free
实现。FSL_RTOS_FREE_RTOS
PRINTF_ADVANCED_ENABLE 0
PRINTF_FLOAT_ENABLE 0
SCANF_ADVANCED_ENABLE 0
SCANF_FLOAT_ENABLE 0
SKIP_SYSCLK_INIT
USE_SDRAM
SDK_I2C_BASED_COMPONENT_USED 1
XIP_BOOT_HEADER_ENABLE 1
.XIP_EXTERNAL_FLASH 1
.XIP_BOOT_HEADER_DCD_ENABLE 1
.- 删除
__MCUXPRESSO
.
- 对于 GNU C++
VGLITE_POINT_FILTERING_FOR_SIMPLE_SCALE
QUL_STD_STRING_SUPPORT
- 适用于所有配置和语言
- 选择 C/C++ Build > Settings > Tool Settings > MCU C++ Linker > Miscellaneous > Other objects,将库列表中的库顺序更改为以下顺序:
- libQulCore_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulControlsTemplates_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulControls_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulShapes_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulTimeline_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulMonotypeUnicodeEngineShaperDisabled_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulMonotypeUnicode_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulPNGDecoderNull_cortex-m7-hf-fpv5-d16_Linux_armgcc_MinSizeRel.a
- libQulDeviceLink_mimxrt1170-evkb-freertos_Linux_armgcc_MinSizeRel.a
- libQulCore_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulControlsTemplates_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulControls_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulShapes_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulTimeline_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulMonotypeUnicodeEngineShaperDisabled_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulMonotypeUnicode_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulPNGDecoderNull_cortex-m7-hf-fpv5-d16_Windows_armgcc_MinSizeRel.a
- libQulDeviceLink_mimxrt1170-evkb-freertos_Windows_armgcc_MinSizeRel.a
注意:库的顺序必须与列表中的顺序相同。否则,链接器可能会因为错误的链接顺序而导致缺少符号。
- 选择 C/C++ Build > Settings > Tool Settings > MCU C++ Linker > Miscellaneous > Linker flags 并添加
-specs=nosys.specs
。注意:请务必不要将它添加到 Other options(-Xlinker [option]) 字段。这将导致链接器无法正确识别该标志。
- 选择 Resource > Linked Resources。在 Linked Resources 标签中,选中 Variable Relative Location > MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.ld 并单击 Edit... 按钮。在 Edit Link Location 中,复制 Location 字段的全部内容。
- 选择 C/C++ Build > Settings > Tool Settings > MCU C++ Linker > Managed Linker Script 并清除 Manage linker script,然后将上一步复制的内丌粘贴到 Linker script 字段。
- 选择 C/C++ Build > Settings > Tool Settings > MCU C++ Linker > General 并清除 No startup or default libs 选项。
- 更改设置后,选择 Apply and Close 按钮。
- 选择 C/C++ General > Paths and Symbols > Source Location 并将以下内容添加到列表中
- 从项目中删除 source/FreeRTOSConfig.h。生成的 CMSIS 包已包含适用于项目的有效 FreeRTOSConfig.h。
- 打开 source/cpp_config.cpp 并进行以下更改
- 添加
#include <FreeRTOS.h> #include <portable.h> #include <task.h>
- 将所有
malloc()
和free()
调用分别替换为pvPortMalloc()
和vPortFree()
调用。注意:不要更改
#ifdef CPP_NO_HEAP
内部的函数定义。 - 如果您愿意,您还可以用 FreeRTOS 内存分配函数调用替换空的
malloc()
和free()
实现。
- 添加
完成应用程序后端
- 打开
source/<项目名称>.cpp
并将其内容替换为以下代码注意:用导出的 UI 应用程序名称替换
YOUR_UI_APP
。#include <app_thread.h> #include <YOUR_UI_APP.h> #include <qul/application.h> #include <qul/qul.h> #include <platforminterface/log.h> #include <FreeRTOS.h> #include <task.h> #include <board.h> static void Qul_Thread(void *argument); static void App_Thread(void *argument); int main() { Qul::initHardware(); Qul::initPlatform(); if (xTaskCreate(Qul_Thread, "Qul_Thread", 32768, 0, 4, 0) != pdPASS) { Qul::PlatformInterface::log("Task creation failed!.\r\n"); configASSERT(false); } if (xTaskCreate(App_Thread, "App_Thread", 200, 0, 4, 0) != pdPASS) { Qul::PlatformInterface::log("Task creation failed!.\r\n"); configASSERT(false); } vTaskStartScheduler(); // Should not reach this point return 1; } static void Qul_Thread(void *argument) { (void) argument; Qul::Application _qul_app; static struct ::YOUR_UI_APP _qul_item; _qul_app.setRootItem(&_qul_item); #ifdef APP_DEFAULT_UILANGUAGE _qul_app.settings().uiLanguage.setValue(APP_DEFAULT_UILANGUAGE); #endif _qul_app.exec(); } static void App_Thread(void *argument) { App::run(); } extern "C" { void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { (void) xTask; (void) pcTaskName; Qul::PlatformInterface::log("vApplicationStackOverflowHook"); configASSERT(false); } void vApplicationMallocFailedHook(void) { Qul::PlatformInterface::log("vApplicationMallocFailedHook"); configASSERT(false); } }
main()
初始化板子并创建以下两个任务Qul_Thread
用于运行 UIApp_Thread
用于处理 LED 命令,并通知 UI 根据 LED 状态更新按钮颜色。
- 右键单击 source 文件夹,然后选择 新建 >头文件。将其命名为
app_thread.h
并添加以下内容:#ifndef APP_THREAD_H_ #define APP_THREAD_H_ namespace App { void run(); void sendToThread(bool ledStatus); } // namespace App #endif /* APP_THREAD_H_ */
- 右键单击 source 文件夹,然后选择 新建 >源文件。将其命名为
app_thread.cpp
并添加以下代码:#include "app_thread.h" #include "uicommunicator.h" #include "board.h" #include <fsl_gpio.h> #include <FreeRTOS.h> #include <queue.h> namespace App { static QueueHandle_t appQueue = NULL; void run() { // enable SW7/WAKE UP button interrupt NVIC_SetPriority(BOARD_USER_BUTTON_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); EnableIRQ(BOARD_USER_BUTTON_IRQ); USER_LED_INIT(0U); // initialize LED to be off appQueue = xQueueCreate(20, 1); bool ledState; while (true) { if (pdTRUE == xQueueReceive(appQueue, &ledState, portMAX_DELAY)) { if (ledState) USER_LED_ON(); else USER_LED_OFF(); UI::sendToThread(ledState); } } } void sendToThread(bool ledStatus) { if (appQueue) { xQueueSend(appQueue, &ledStatus, 0); } } } // namespace App extern "C" void BOARD_USER_BUTTON_IRQ_HANDLER(void) { GPIO_PortClearInterruptFlags(BOARD_USER_BUTTON_GPIO, 1U << BOARD_USER_BUTTON_GPIO_PIN); bool ledStatus = 0x1 ^ GPIO_PinRead(BOARD_USER_LED_GPIO, BOARD_USER_LED_GPIO_PIN); if (App::appQueue) xQueueSendFromISR(App::appQueue, &ledStatus, NULL); }
此文件定义了一个简单的应用程序线程及其所有相关函数。首先,定义了
appQueue
以存储切换板子 LED 状态(开启或关闭)的命令。App::run
函数是app_thread
的主循环。它启用了板上用户按钮的中断,初始化一个 LED 为关闭状态,并为线程创建一个队列。在此之后,线程进入一个无限循环,等待命令以切换 LED 状态。然后将此状态发送到 UI(Qt Quick Ultralite)线程。接下来,我们有一个
App::sendToThread
函数,它将指定的 LED 状态发布到appQueue
。最后,有一个用户按钮的中断处理程序。当按钮被按下时,它检查 LED 的当前状态并将该状态的相反状态发布到appQueue
。
您的应用程序现在已就绪。将其构建并烧录到 NXP i.MX RT1170 板上以测试一切是否按预期工作。
注意:如果应用程序似乎没有响应触摸,请尝试按下板上的 SW7/WAKEUP 按钮。
在特定 Qt 许可证下提供。
了解更多。