C
NXP MCUXpresso IDEプロジェクトの作成
このトピックでは、NXP MCUXpresso IDE プロジェクトを作成し、アプリケーションとプラットフォーム・ソースを統合する手順を説明します。
MCUXpresso IDEとARM GCCツールチェーンの両方を含むMCUXpresso SDKバージョン2.14.0が必要です。Qt Online Installer が提供するSDKを使用するか、自分でSDKをダウンロードすることができます。MCUXpresso IDEまたはボードSDKの新しいバージョンが動作する可能性がありますが、テストされていません。
SDKを自分でビルドする場合は、以下のコンポーネントをインストールしてください:
- すべてのツールチェーン(これにより、ARM GCCとMCUXpressoの両方のファイルが含まれるようになります)
- FreeRTOS
- VG-Lite GPUライブラリー
新しいプロジェクトを作成する
SDKを任意のディレクトリに解凍し、以下の手順に従ってください:
- MCUXpresso IDEを起動し、ダウンロードしたSDKをインストールします:
- Window > Show View > Installed SDKs を選択して SDK ビューが表示されることを確認します。
- Installed SDKs に移動します。
- ビューを選択したまま、または右クリックして、Import folder... を選択します。SDK をアーカイブとしてお持ちの場合は、Import archive... を選択することもできます。
- フォルダ/アーカイブを選択し、Open を選択して SDK を IDE にインポートします。
- File > New > Create a new C/C++ Project を使用して、i.MX RT1170 EVKB用の新規プロジェクトを作成します。
- evkbmimxrt1170 ボードを選択し、Next を選択します。
- 次の画面で、MIMXRT1176DVMAA デバイスパッケージを選択します。プロジェクトには以下の設定が必要です:
- Cores:cm7 core is set toStandalone Role.
- ボード:Default board files
- プロジェクト・タイプ:C++ Project
- Project Options:SDK Debug Console がUART に設定されています。Copy sources とImport other files の両方が選択されています。
以下のリストのコンポーネントも選択する:
- Operating Systems
- RTOS > Core > FreeRTOS kernel
- Drivers
- Device > SDK Drivers
- anatop_ai
- clock
- common
- dcdc_soc
- elcdif
- gpio
- i2c
- iomuxc
- lcdifv2
- lpuart
- memory
- mipi_dsi
- nic301
- pmu
- pxp
- soc_mipi_csi2rx
- xip_device
- Device > SDK Drivers
- CMSIS Include
- CMSIS > CORE > CMSIS_Include_CM
- Device > CMSIS > MIMXRT1176_CMSIS
- Device > CMSIS > MIMXRT1176_system
- Utilities
- Device > SDK Drivers > lpuart_adapter
- Device > SDK Utilities
- assert
- debug_console
- serial_manager
- serial_manager_uart
- Board Components
- Board Support > SDK Drivers > xip_board
- Device > SDK Drivers
- display-hx8394
- display-rm68191
- display-rm68200
- xmcd
- Abstraction Layer
- Device > SDK Drivers
- dc-fb-common
- dc-fb-elcdif
- dc-fb-lcdifv2
- display-common
- Device > SDK Drivers
- Software Components
- Device > SDK Drivers
- display-mipi-dsi-cmd
- lists
- video-common
- Device > SDK Drivers
- Project Template
- Board Support > SDK Project Template > evkbmimxrt1170
- Other
- Device > Startup > MIMXRT1176_startup
Next を選択して次の画面に進む。
- Advanced project settings で以下の設定を変更する:
- Set Floating Point type:FPv5-D16 (Hard ABI)
- Language standard:GNU C++14 (-std=gnu++14)
Finish を選択して、プロジェクトのセットアップを完了します。
ピンの設定とSDKコンポーネントのインポート
- ConfigTools > Pins オプションを使用して、NXP i.MX RT1170 ピンを構成します。詳細については、 NXP i.MX RT1170ピンの構成 を参照してください。
- 追加SDKコンポーネントをインポートします:
- プロジェクトを選択したまま、または右クリックして、Import を選択します。
- File System を選択します。
- From directory フィールドに
<SDK_PATH>/components/gt911を追加し、fsl_gt911.h/*.cファイルを選択します。 - Into folder フィールドに
<PROJECT_NAME>/gt911を追加し、Finish を選択します。 - 以下のディレクトリ(その中のファイルとサブディレクトリを含む)を
<SDK_PATH>/middleware/vgliteから<PROJECT_NAME>/vgliteにインポートします:incVGLiteVGLiteKernel
<SDK_PATH>/devices/MIMXRT1176/gccから<PROJECT_NAME>/startupにstartup_MIMXRT1176_cm7.Sをインポートする。<PROJECT_NAME>/startup/startup_mimxrt1176_cm7.c/.cppをプロジェクトから削除します。<SDK_PATH>/rtos/freertos/freertos-kernel/portable/MemMangから<PROJECT_NAME>/freertos/freertos-kernel/portable/MemMangにheap_4.cをインポートする。
アプリケーションのバックエンドを開発する
- UIコミュニケーター構造体の作成
バックエンドは、アプリケーションのUIがプラットフォームと通信し、ハードウェアから必要な情報を取得できるようにする。この場合、コミュニケーターはオンボードLEDのステータスを取得する。以下の図に、2つのコンポーネント間のワークフローを示します:

- Project Explorer のsource フォルダーを選択したまま、または右クリックして、New > Class を選択します。
- Class name フィールドにUICommunicator を追加。Header とSource の名前をそれぞれ
uicommunicator.hとuicommunicator.cppに変更し、Finish を選択します。 - 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は、搭載されている LED の状態を示すled1Statusプロパティを宣言している。このプロパティは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()メンバ関数は、command 引数を使用して、プロパティを更新する必要があるかどうかを判断します。次に、
CommandEventQueueクラスはonEvent()関数をオーバーライドし、commandとcommandDataパラメータを持つUICommunicatorインスタンスでreceiveToUI()を呼び出します。さらに、CommandEventQueueの静的インスタンスが作成され、UI::sendToThread()関数がイベントをポストするために使用します。UI::sendToThread()は、与えられたブール値からCommandEventを構築し、処理のためにcommandEventQueueに追加します。LEDの状態が変更されると、アプリケーション・スレッドから呼び出される。
Qt for MCUs CMSIS-Packの作成
CMSIS-Packは、MCUXpresso IDEプロジェクト内でQt for MCUs アプリケーションをセットアップするために必要な情報とファイルを含むIDEに依存しないパッケージです。
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.12.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.12.0 set QMLPROJECT_FILE=C:\path\to\YourProject.qmlproject set PLATFORM_METADATA=%QUL_ROOT%\lib\QulPlatformTargets_mimxrt1170-evkb-freertos_32bpp_Windows_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 を選択します。CMSIS-Packs のリストにパックが表示されるはずです。 - Develop パースペクティブに戻ります。
- Project Explorer のプロジェクト名を選択したまま、または右クリックします。
- SDK Management > Add Open-CMSIS Components に移動します。
- 以下のコンポーネントを選択します:
- Graphics (Variant:Qt for MCUs)
- Platform DeviceLink library (Variant:FreeRTOS)
- Platform sources (Variant:FreeRTOS)
- Qt Quick Ultralite headers
- Qt Quick Ultralite libraries
- Project
- Qt for MCUs Application
- Graphics (Variant:Qt for MCUs)
- チェックボックス Qt for MCUs Applicationチェックボックスの隣にある小さなボタンを選択します。これにより qmlprojectexporter が起動し、Qt Quick Ultralite アプリケーションがプロジェクトにエクスポートされます。
- エクスポートが終了するまで待ちます。以下の画像のように、プロジェクトエクスプローラーにapplication.gpdsc が表示されるはずです:

- Apply and save changes を選択してください。
MCUXpresso IDEプロジェクトの設定
- プロジェクトを選択し、File > Properties を選択して以下の変更を行います:
- C/C++ General > Paths and Symbols > Source Location を選択し、リストに以下を追加します:
gt911vglite
- C/C++ General > Paths and Symbols > Includes の下にある C++ インクルード・ ディレクトリ・リストに、以下のインクルード・パス を追加します。Add to all configurations とAdd to all languages を選択します。このアプリケーションでは、以下のインクルード・ ディレクトリを追加します:
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_IRQnBOARD_MIPI_PANEL_TOUCH_IRQ_HANDLER GPIO2_Combined_16_31_IRQHandlerCPP_NO_HEAPこれは、cpp_config.cppに空の実装を導入することで、デフォルトのmallocとfreeの実装を無効にします。FSL_RTOS_FREE_RTOSPRINTF_ADVANCED_ENABLE 0PRINTF_FLOAT_ENABLE 0SCANF_ADVANCED_ENABLE 0SCANF_FLOAT_ENABLE 0SKIP_SYSCLK_INITUSE_SDRAMSDK_I2C_BASED_COMPONENT_USED 1XIP_BOOT_HEADER_ENABLE 1XIP_EXTERNAL_FLASH 1XIP_BOOT_HEADER_DCD_ENABLE 1- を削除します。
__MCUXPRESSO
- GNU C++の場合
VGLITE_POINT_FILTERING_FOR_SIMPLE_SCALEQUL_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内の関数定義の名前は変更しないでください。 - 必要であれば、空の
malloc()とfree()の実装をFreeRTOS メモリ割り当て関数の呼び出しに置き換えることもできます。
- 以下を追加してください。
アプリケーションのバックエンドを確定する
-
source/<project-name>.cppを開き、内容を以下のコードに置き換える:注:
YOUR_UI_APPをエクスポートされたUIアプリケーション名に置き換えてください。#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()ボードを初期化し、以下の2つのタスクを作成する:Qul_ThreadUIを実行するApp_Threadを実行してLEDコマンドを処理し、LEDの状態に基づいてボタンの色を更新するためにUIに信号を送ります。
- source フォルダーを選択したまま、または右クリックして、New > Header File を選択します。名前を
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 フォルダーを選択したまま、または右クリックして、New > Source File を選択します。名前を
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の1つをオフに初期化し、スレッド用のキューを作成します。この後、スレッドはLEDの状態を切り替えるコマンドを待つ無限ループに入る。このステータスはUI (Qt Quick Ultralite)スレッドに送られる。次に、
App::sendToThread関数があり、与えられたLEDの状態をappQueueにポストする。 最後に、ユーザー・ボタン用のIRQハンドラーがある。ボタンが押されると、LEDの現在の状態をチェックし、その状態の逆数をappQueue。
これでアプリケーションの準備は完了です。ビルドしてNXP i.MX RT1170ボードにフラッシュし、すべてが意図したとおりに動作することをテストしてください。
注: アプリケーションがタッチに反応しないようであれば、ボードのSW7/WAKEUPボタンを押してみてください。