C

Qt Quick Ultralite freertos_app_switch 示例

展示如何通过软复位在 Qt Quick Ultralite 应用和其他应用之间切换。

概述

freertos_app_switch 示例演示了如何通过软复位和存储其状态的内存位置在 Qt Quick Ultralite 应用和其他应用之间切换。本例还演示了如何重新启动 Qt Quick Ultralite 应用,重新触发应用程序的初始化步骤。

启动时使用特定的内存地址选择两个应用之一

  • Application #1 是本身是 Qt Quick Ultralite 应用,为引导选择机制提供用户界面。

  • Application #2 是另一个应用,它直接写入帧缓冲区,闪烁 LED 几秒钟,然后重新启动设备到第一个应用。

注意: 使用软复位时请小心。确保硬件外设可以正确重新初始化。某些外设可能需要复位信号或在编程前处于特定状态。

注意: 本处所示的相同复位机制可以修改为使用硬复位(触发断电)和不可挥发的内存来存储状态。

目标平台

代码概述

应用程序入口点

main() 函数负责硬件和平台初始化,并另外使用板级特定的 InitLED() 函数初始化 LED。

...
int main()
{
    Qul::initHardware();
    Qul::initPlatform();
    initLED();
    ...

接下来,从内存中读取 boot 值。

    int boot = readBootValue();

readBootValue() 方法简单地从特定的内存位置读取,并在 boardutils.c 中定义。

int readBootValue()
{
    int *ptr = &__BOOT_VAL_ADDR;
    return *ptr;
}

可以通过 board.cmake 文件中的链接器定义的符号设置 boot 变量的地址。

set(BOOT_VAL_ADDR 0x81400000)
if (IAR)
    target_link_options(freertos_app_switch PRIVATE --define_symbol __BOOT_VAL_ADDR=${BOOT_VAL_ADDR})
else()
    target_link_options(freertos_app_switch PRIVATE -Xlinker --defsym=__BOOT_VAL_ADDR=${BOOT_VAL_ADDR})
endif()

根据 boot 值创建不同的 FreeRTOS 任务。或者是一个运行 Application #1 的 Qt Quick Ultralite 任务,或者是一个实现 Application #2 的任务。

    if (boot != APP2) {
        Qul::PlatformInterface::log("Application #1...QUL Application Switch\r\n");
        if (xTaskCreate(App1_thread, "QulExec", QUL_STACK_SIZE, 0, 4, &QulTask) != pdPASS) {
            Qul::PlatformInterface::log("Task creation failed!\r\n");
            configASSERT(false);
        }
    } else {
        Qul::PlatformInterface::log("Application #2...blinking LED\r\n");
        if (xTaskCreate(App2_thread, "LedToggle", configMINIMAL_STACK_SIZE, 0, 4, &LedTask) != pdPASS) {
            Qul::PlatformInterface::log("LED task creation failed!\r\n");
            configASSERT(false);
        }
    }

    vTaskStartScheduler();
    ...

运行 Qt Quick Ultralite 的 Application #1 任务简单地设置应用程序的根项并调用 exec() 函数。

static void App1_thread(void *argument)
{
    (void) argument;

    Qul::Application app;
    static appswitch item;
    app.setRootItem(&item);
    app.exec();
}

任务 #2 的应用程序通过 displayApp2Background() 将原始图像直接写入帧缓冲区,然后闪烁 LED 几次。

static void App2_thread(void *argument)
{
    (void) argument;
    displayApp2Background();

    //Blink for N_BLINKS times then reboot into App1
    for (int i = 0; i < N_BLINKS; ++i) {
        xTaskNotifyWait(0, ULONG_MAX, NULL, pdMS_TO_TICKS(500));
        toggleLED();
        taskYIELD();
    }
    reset(APP1);
}
QML

Qt Quick Ultralite 用户界面在 freertos_app_switch.qml 中实现。通过两个单选按钮和一个复位按钮选择下一次启动时要执行的应用程序,并触发软复位。

                ...
                Button {
                    id: resetButton
                    text: "Reset!"
                    anchors.centerIn: parent
                    onClicked: {
                        console.log("Chosen application #", DevControl.application, "...Resetting system!")
                        DevControl.resetDevice();
                    }
                }
                ...

DevControl 对象用作 UI 和抽象硬件之间的接口。

void DevControl::HWResetDevice()
{
    reset(application.value());
}

公共方法 resetDevice() 允许将 Qul::Property<int> application 的值写入启动内存位置,然后通过 NVIC_SystemReset() 触发软复位。

void writeBootValue(int app)
{
    int *ptr = &__BOOT_VAL_ADDR;
    *ptr = app;
    QUL_CleanInvalidateDCache_by_Addr((void *) ptr, 4);
}

void reset(int app)
{
    writeBootValue(app);
    NVIC_SystemReset();
}

注意: 在 NXP i.MX RT1170 上,在烧录二进制文件后,设备应该重置一次。否则,通过 NVIC_SystemReset() 进行的软复位可能无法正常工作。

文件

另请参阅 FreeRTOS 应用程序构建过程.

适用于特定 Qt 许可证。
了解更多信息。