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解压缩到您选择的一个目录,并遵循以下说明

  1. 启动MCUXpresso IDE并安装下载的SDK
    • 通过选择窗口 > 显示视图 > 安装SDK来确保您可以看到SDK视图。
    • 转到安装的SDK
    • 在视图中右键单击并选择导入文件夹...。如果您有SDK存档,也可以选择导入存档...
    • 选择文件夹/存档,然后选择打开将SDK导入到IDE中。
  2. 使用文件 > 新建 > 创建新的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
      • 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驱动程序
          • display-mipi-dsi-cmd
          • 列表
          • 视频通用
      • 项目模板
        • 板级支持 > SDK 项目模板 > evkbmimxrt1170
      • 其他
        • 设备 > 启动 > MIMXRT1176_startup

      选择 下一步 以转到下一屏幕。

    • 高级项目设置 中更改以下设置
      • 设置浮点类型FPv5-D16 (Hard ABI)
      • 语言标准GNU C++14 (-std=gnu++14)

      选择 完成 以完成项目设置。

配置引脚并导入额外的 SDK 组件

  1. 使用 ConfigTools > 引脚 选项配置 NXP i.MX RT1170 引脚。有关更多信息,请参阅配置 NXP i.MX RT1170 引脚
  2. 导入额外的 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/gccstartup_MIMXRT1176_cm7.S 导入到 <PROJECT_NAME>/startup。从项目中删除 <PROJECT_NAME>/startup/startup_mimxrt1176_cm7.c/.cpp
    • <SDK_PATH>/rtos/freertos/freertos-kernel/portable/MemMangheap_4.c 导入到 <PROJECT_NAME>/freertos/freertos-kernel/portable/MemMang

开发应用程序后端

  1. 创建 UI 通信器结构体

    后端允许应用程序的 UI 与平台通信并从硬件获取所需信息。在这种情况下,通信器获取板上 LED 的状态。以下图表描述了两个组件之间的工作流程

    1. 项目资源管理器 中右键单击 文件夹并选择 新建 > 类
    2. UICommunicator 添加到 类名 字段。将 头文件源文件 分别重命名为 uicommunicator.huicommunicator.cpp,然后选择 完成
    3. 打开 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::SingletonUICommunicator 结构体,使它与 UI 代码的集成变得简单易行。有关更多信息,请参阅Singleton 类参考。

      头文件还声明了定义一系列命令的 Command 枚举和用于管理队列的 CommandEventQueue。枚举使 UI 和应用程序之间的通信成为可能。

      UICommunicator 声明了 led1Status 属性,用于指示板上 LED 的状态。此属性在 QML 上下文中可用,以确定按钮的颜色。

      《UICommunicator》类有 sendFromUIreceiveToUI 方法用于发送和接收命令。它还有用于以线程安全方式与UI线程通信的 CommandEventQueue。不是从应用程序线程调用 receiveToUI,而是将命令添加到 CommandEventQueue。Qt Quick Ultralite 线程通过调用 receiveToUI 来处理队列。

    4. 打开 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() 并传递参数 commandcommandData。此外,还创建了一个静态实例的 CommandEventQueue,该实例用于由 UI::sendToThread() 函数来发布事件。UI::sendToThread() 从给定的布尔值构造了一个 CommandEvent 并将其添加到 commandEventQueue 以进行处理。这通常在LED的状态改变时从应用程序线程中调用。

创建一个适用于MCU的Qt CMSIS-Pack

CMSIS-Pack是一个不依赖于IDE的包,它包含在MCUXpresso IDE项目内设置Qt for MCUs应用程序所需的信息和文件。

  1. 使用 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
  2. 将创建的CMSIS包导入到MCUXpresso IDE项目中
    1. 转到 CMSIS-Pack Manager 视图。
    2. Packs 选项卡中,选择 Import Existing Packs... 按钮。
    3. 导航到由qmlprojectexporter指定的输出文件夹。包文件应在 CMSIS 文件夹中,命名为 <YourProject>-mimxrt1170-evkb-freertos-<OS>-armgcc-cmsis.pack。选择 Open。Pack应该显示在CMSIS-Packs列表中。
    4. 回到 Develop 视图。
    5. Project Explorer 中右键点击项目名称。
    6. 转到 SDK Management > Add Open-CMSIS Components
    7. 选择以下组件
      • Graphics(变体:Qt for MCUs)
        • Platform DeviceLink library(变体:FreeRTOS)
        • Platform sources(变体:FreeRTOS)
        • Qt Quick Ultralite头文件
        • Qt Quick Ultralite库
      • 项目
        • Qt for MCU应用程序
    8. 选择 Qt for MCUs Application 复选框旁边的较小按钮。这将启动 qmlprojectexporter,将Qt Quick Ultralite应用程序导出到项目中。
    9. 选择 应用并保存更改

配置MCUXpresso IDE项目

  1. 选择项目并选择 文件 > 属性 以进行以下更改
    • 选择 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 中引入空实现来禁用默认的 mallocfree 实现。
        • 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 按钮。
  2. 从项目中删除 source/FreeRTOSConfig.h。生成的 CMSIS 包已包含适用于项目的有效 FreeRTOSConfig.h。
  3. 打开 source/cpp_config.cpp 并进行以下更改
    • 添加
      #include <FreeRTOS.h>
      #include <portable.h>
      #include <task.h>
    • 将所有 malloc()free() 调用分别替换为 pvPortMalloc()vPortFree() 调用。

      注意:不要更改 #ifdef CPP_NO_HEAP 内部的函数定义。

    • 如果您愿意,您还可以用 FreeRTOS 内存分配函数调用替换空的 malloc()free() 实现。

完成应用程序后端

  1. 打开 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 用于运行 UI
    • App_Thread 用于处理 LED 命令,并通知 UI 根据 LED 状态更新按钮颜色。
  2. 右键单击 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_ */
  3. 右键单击 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 许可证下提供。
了解更多。