C

Develop the Application Backend (Traveo II)

This topic guides you through the steps to create and build the application's backend using GHS MULTI IDE. The backend enables the application's UI to communicate with the platform and get the required information from the hardware. In this case, the device interface gets the status of the on-board user button. The following diagram describes the interaction between the two components:

Export application and platform sources

This section provides you step-by-step instructions to create a GHS MULTI IDE project, and integrate application and platform sources exported by the Qt for MCUs tools.

Note: If you are using Traveo II 6M, replace tviic2d4m-baremetal with tviic2d6m-baremetal in the following steps.

  1. Export the UI sources using the qmlprojectexporter tool. Create a batch script with the following commands:
    set QUL_ROOT=C:\path\to\QtMCUs\2.4.0
    set QMLPROJECT_FILE=C:\path\to\YourProject.qmlproject
    set BOARDDEFAULTS=%QUL_ROOT%\platform\boards\cypress\tviic2d4m-baremetal\cmake\BoardDefaults_32bpp.qmlprojectconfig
    set APPLICATION_EXPORT_DIR=application-sources
    
    %QUL_ROOT%\bin\qmlprojectexporter.exe %QMLPROJECT_FILE% --platform=tviic2d4m-baremetal --toolchain=ghs-arm --boarddefaults=%BOARDDEFAULTS% --outdir=%APPLICATION_EXPORT_DIR%

    Make sure to set all the relevant paths (QUL_ROOT and QMLPROJECT_FILE) and run the script from the Command Prompt. The C++ sources generated from QML will now be in %APPLICATION_EXPORT_DIR%. For more information, refer to qmlprojectexporter documentation.

  2. Export the platform sources and generate a top-level GHS project file using the platformexporter tool. Create a batch script with the following commands:
    set QUL_ROOT=C:\path\to\QtforMCUs\2.4.0
    set PLATFORM_EXPORT_DIR=platform-sources
    set GRAPHICS_DRIVER_DIR=C:\path\to\TVII-GraphicsDriver-V1.2.0
    
    %QUL_ROOT%\bin\platformexporter.exe --infile=%QUL_ROOT%\lib\QulPlatformTargets_tviic2d4m-baremetal_32bpp_Windows_ghs-arm-export.json --outdir=%PLATFORM_EXPORT_DIR% --sdkdir=%GRAPHICS_DRIVER_DIR% --outputformat=ghs --includeIDEgeneratedHWCode

    Note: Use the v2e1.0 graphics driver for tviic2d6m-baremetal.

    Make sure to set GRAPHICS_DRIVER_DIR to the Traveo II Graphics Driver install path, and run the script. The script exports the platform sources in %PLATFORM_EXPORT_DIR%\platform and creates a top-level project file and sub-project files for GHS MULTI IDE in %PLATFORM_EXPORT_DIR%. The generated GHS project includes the following:

    • %PLATFORM_EXPORT_DIR%\project.gpj: the top-level project file
    • %PLATFORM_EXPORT_DIR%\prj\program.gpj: program compile definitions, include directories, compiler and linker options
    • %PLATFORM_EXPORT_DIR%\prj\drivers.gpj: list of Graphics Driver sources
    • %PLATFORM_EXPORT_DIR%\prj\platform.gpj: list of tviic2d4m-baremetal platform sources
    • %PLATFORM_EXPORT_DIR%\prj\application.gpj: a convenience empty sub-project for the application which you will edit in the next section

For more information, refer to platformexporter documentation.

Build application in GHS MULTI IDE

The following instructions guide you through the GHS project adaptation steps needed to build the application:

  1. Launch GHS MULTI IDE
  2. Select File > Open Project and select the top-level project.gpj file exported in the earlier section.
  3. Create a new file named main.cpp in any directory, which you will refer to as BACKEND_DIR:
    #include "YourProject.h"
    
    #include <qul/application.h>
    #include <qul/qul.h>
    
    int main()
    {
        Qul::initHardware();
        Qul::initPlatform();
        Qul::Application app;
        static YourProject item;
        app.setRootItem(&item);
        app.exec();
        return 0;
    }

    This file has the default entrypoint for the application. You will extend this entrypoint later with extra configuration steps to use the LED and user button. Refer to the entry point to Qt Quick Ultralite applications documentation for more information. Make sure to use the same project name (YourProject) that you chose in the earlier chapter.

  4. Right-click application.gpj and select Edit to add the application sources that you exported in the earlier section, and the source file you created in the earlier step. Replace its contents with the following:
    #!gbuild
    macro APPLICATION_EXPORT_DIR=C:/path/to/application-sources/
    macro BACKEND_DIR=C:/path/to/backend
    
    [Subproject]
        -DQUL_STD_STRING_SUPPORT
        -I${APPLICATION_EXPORT_DIR}
    
    # ----- UI -----
    ${APPLICATION_EXPORT_DIR}/resources/qulrcc_assets.cpp
    ${APPLICATION_EXPORT_DIR}/resources/qulrcc_lookup_data.cpp
    ${APPLICATION_EXPORT_DIR}/resources/qulrcc_runtime_allocation_info.cpp
    ${APPLICATION_EXPORT_DIR}/YourProject.cpp
    ${APPLICATION_EXPORT_DIR}/Screen01.cpp
    ${APPLICATION_EXPORT_DIR}/loader_item_allocator.cpp
    ${APPLICATION_EXPORT_DIR}/qul_font_engines.cpp
    ${APPLICATION_EXPORT_DIR}/qul_font_data.cpp
    
    # ----- backend -----
    ${BACKEND_DIR}/main.cpp

    Make sure to set the APPLICATION_EXPORT_DIR macro to the directory containing the exported application sources from the earlier section. You should add all the source files exported by qmlprojectexporter as part of this step. The %APPLICATION_EXPORT_DIR%\config\YourProject.1.compiler_outputs.txt file has the full list of sources.

    Similarly, set the BACKEND_DIR macro to the directory containing the main.cpp.

  5. Set the application binary name using -o YourProject.elf in the program.gpj project file.
  6. Finally, the %APPLICATION_EXPORT_DIR%\config\YourProject.1.libraries.txt file lists the Qt Quick Ultralite libraries that an application should link against. For example, it might list these libraries:
    • Qul::MonotypeUnicode
    • Qul::MonotypeUnicodeEngineShaperDisabled
    • Qul::PNGDecoderNull

    Identify the corresponding libraries for your build type and platform in the ${QUL_DIR}/lib folder and add them to program.gpj with the -l directive. For the example libraries listed above, these are the corresponding library files to link against in program.gpj:

    • -l${QUL_DIR}/lib/libQulMonotypeUnicode_tviic2d4m-baremetal_Windows_ghs-arm_MinSizeRel.a
    • -l${QUL_DIR}/lib/libQulMonotypeUnicodeEngineShaperDisabled_tviic2d4m-baremetal_Windows_ghs-arm_MinSizeRel.a
    • -l${QUL_DIR}/lib/libQulPNGDecoderNull_tviic2d4m-baremetal_Windows_ghs-arm_MinSizeRel.a
  7. At this point, in order to verify that the steps so far have been followed correctly, you can build your partially implemented application and flash it to the Traveo II board using the Infineon Auto Flash Utility to run it on the target hardware.

    The following command shows how to flash the application to the board. Replace the Infineon Auto Flash Utility path if necessary. If you are using the J-Link probe instead of a MiniProg4, replace kitprog3.cfg with jlink.cfg. If your target board is a Traveo II 6M instead of a Traveo II 4M, replace traveo2_c2d_4m.cfg with traveo2_6m.cfg:

    "C:\Program Files (x86)\Infineon\Auto Flash Utility 1.2\bin\openocd.exe" -s "C:\Program Files (x86)\Infineon\Auto Flash Utility 1.2\scripts" -f interface/kitprog3.cfg -c "set ENABLE_HYPERFLASH_0 1" -c "transport select swd" -f target/traveo2_c2d_4m.cfg -c "init; reset init; program C:/path/to/YourProject.elf verify; shutdown"

    You will also need to flash a bootloader to the CM0+ core of the Traveo II board. First, set QUL_ROOT to the same value as in the earlier batch scripts. Next, use the earlier Infineon Auto Flash Utility command and replace the path to YourProject.elf with the following:

    • Traveo II 4M
      • %QUL_ROOT%/bin/bootloaders/cypress/tviic2d4m-baremetal_bootloader.elf
    • Traveo II 6M
      • %QUL_ROOT%/bin/bootloaders/cypress/tviic2d4m-baremetal_bootloader.elf

In the next section, you will add the logic to enable interaction between the application UI and hardware with the user button.

Develop the low-level backend in GHS MULTI IDE

The following instructions guide you through the process of developing the low-level backend functionality needed by your application:

  1. Create new C++ source and header files and name them deviceinterface.cpp and deviceinterface.h respectively. Save these files in the BACKEND_DIR directory that you used in the earlier section.
  2. Right-click application.gpj and select Add File into application.gpj to add the newly created files into the application sub-project file.
  3. Right-click deviceinterface.h in the project manager and select Edit. Replace its contents with the following:
    #ifndef DEVICEINTERFACE_H
    #define DEVICEINTERFACE_H
    
    #include <qul/signal.h>
    #include <qul/singleton.h>
    #include <qul/eventqueue.h>
    
    typedef int HWButtonEvent;
    
    class DeviceInterface : public Qul::Singleton<DeviceInterface>, public Qul::EventQueue<HWButtonEvent>
    {
    public:
        Qul::Signal<void(int button)> buttonEvent;
        void onEvent(const HWButtonEvent &inputEvent);
    
        void toggleLED();
    };
    
    #endif //DEVICEINTERFACE_H

    The header declares the DeviceInterface class, which inherits from Qul::Singleton and Qul::EventQueue. It also declares the buttonEvent Signal and the HWButtonEvent event type. This allows the Singleton instance to be globally available. It provides an interface between C++ and QML, to emit the changed signal on receiving the HWButtonEvent input event. For more information, refer to Defining Singletons in QML and Transferring data from Interrupt Handlers to QML.

  4. Similarly, replace the contents of deviceinterface.cpp with the following:
    #include "deviceinterface.h"
    #include "boardutils.h"
    
    #include <platforminterface/log.h>
    
    extern "C" void DeviceInterface_handleButtonEvent()
    {
        DeviceInterface::instance().postEventFromInterrupt(0);
    }
    
    void DeviceInterface::onEvent(const HWButtonEvent &inputEvent)
    {
        buttonEvent(inputEvent);
    }
    
    void DeviceInterface::toggleLED()
    {
        Qul::PlatformInterface::log("Toggling LED\n");
        BoardUtils_toggleLED();
    }
  5. Create new C source and header files and name them boardutils.c and boardutils.h respectively. Save these files in the BACKEND_DIR directory and add them to application.gpj.
  6. Replace the code in boardutils.h with the following:
    #ifndef BOARDUTILS_H
    #define BOARDUTILS_H
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void BoardUtils_configure();
    void BoardUtils_toggleLED();
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif //BOARDUTILS_H
  7. Add the Traveo II specific implementation of BoardUtils_configure() and BoardUtils_toggleLED() to boardutils.c:
    #include "boardutils.h"
    
    #include <stdint.h>
    
    #include <cy_project.h>
    
    #define USER_LED1_PORT CY_USER_LED1_PORT
    #define USER_LED1_PIN CY_USER_LED1_PIN
    #define USER_LED1_PIN_MUX CY_USER_LED1_PIN_MUX
    
    #define USER_BUTTON1_PORT CY_USER_BUTTON_WAKE_PORT
    #define USER_BUTTON1_PIN CY_USER_BUTTON_WAKE_PIN
    #define USER_BUTTON1_PIN_MUX CY_USER_BUTTON_WAKE_PIN_MUX
    #define USER_BUTTON1_IRQN CY_USER_BUTTON_WAKE_IRQN
    
    extern void DeviceInterface_handleButtonEvent();
    
    void ButtonInterruptHandler(void)
    {
        uint32_t interruptStatus = Cy_GPIO_GetInterruptStatusMasked(USER_BUTTON1_PORT, USER_BUTTON1_PIN);
        if (interruptStatus) {
            DeviceInterface_handleButtonEvent();
            Cy_GPIO_ClearInterrupt(USER_BUTTON1_PORT, USER_BUTTON1_PIN);
        }
    }
    
    void BoardUtils_configure()
    {
        // GPIO configuration for LED
        cy_stc_gpio_pin_config_t user_led_port_pin_cfg = {
            .outVal = 0x00,
            .driveMode = CY_GPIO_DM_STRONG_IN_OFF,
            .hsiom = USER_LED1_PIN_MUX,
            .intEdge = 0,
            .intMask = 0,
            .vtrip = 0,
            .slewRate = 0,
            .driveSel = 0,
            .vregEn = 0,
            .ibufMode = 0,
            .vtripSel = 0,
            .vrefSel = 0,
            .vohSel = 0,
        };
    
        Cy_GPIO_Pin_Init(USER_LED1_PORT, USER_LED1_PIN, &user_led_port_pin_cfg);
    
        // GPIO configuration for button
        static cy_stc_gpio_pin_config_t user_button1_port_pin_cfg = {
            .outVal = 0x00,
            .driveMode = CY_GPIO_DM_HIGHZ,
            .hsiom = USER_BUTTON1_PIN_MUX,
            .intEdge = CY_GPIO_INTR_FALLING,
            .intMask = 1,
            .vtrip = 0,
            .slewRate = 0,
            .driveSel = 0,
            .vregEn = 0,
            .ibufMode = 0,
            .vtripSel = 0,
            .vrefSel = 0,
            .vohSel = 0,
        };
    
        Cy_GPIO_Pin_Init(USER_BUTTON1_PORT, USER_BUTTON1_PIN, &user_button1_port_pin_cfg);
    
        // IRQ configuration for button
        cy_stc_sysint_irq_t irq_cfg = {
            .sysIntSrc = USER_BUTTON1_IRQN,
            .intIdx = CPUIntIdx2_IRQn,
            .isEnabled = true,
        };
    
        Cy_SysInt_InitIRQ(&irq_cfg);
        Cy_SysInt_SetSystemIrqVector(irq_cfg.sysIntSrc, ButtonInterruptHandler);
    
        NVIC_SetPriority(CPUIntIdx2_IRQn, 3);
        NVIC_ClearPendingIRQ(CPUIntIdx2_IRQn);
        NVIC_EnableIRQ(CPUIntIdx2_IRQn);
    }
    
    void BoardUtils_toggleLED()
    {
        Cy_GPIO_Inv(USER_LED1_PORT, USER_LED1_PIN);
    }

    The configure function initializes the LED and button pins. It then registers ButtonInterruptHandler() as the interrupt request handler for the user button events using the GPIO and IRQ APIs from the Traveo II Graphics Driver.

  8. To properly configure the Traveo II LED and button, change main.cpp to include the boardutils.h header and to call BoardUtils_configure() after the normal platform initialization:
    #include "boardutils.h"
    ...
    
    int main()
    {
        Qul::initHardware();
        Qul::initPlatform();
        BoardUtils_configure();
        ...
    }

Integrate UI and backend in Design Studio

Use the DeviceInterface Singleton object from Design Studio, to access the low-level backend functions that you implemented in the earlier section.

  1. Open your project in Design Studio and select the Connections pane.
  2. Click twice on + in the Connections tab to add two new connections.
  3. In the first connection, set Target to statusRect, Signal Handler to onPressedChanged, and Action to DeviceInterface.toggleLED().
  4. In the second connection, set Target to DeviceInterface, Signal Handler to onButtonEvent, and Action to statusRect.pressed = !statusRect.pressed.

    Now on press of the button, the event propagates to the QML context, which changes the statusRect.pressed property. This results in changing the color of the UI item. In response to the statusRect.pressed property change, the DeviceInterface.toggleLED() method toggles the LED.

  5. Use a text editor to change yourproject.qmlproject to generate the necessary C++/QML interfaces needed for the singleton object:
    InterfaceFiles {
        files: ["C:/path/to/BACKEND_DIR/deviceinterface.h"]
    }

    Change the BACKEND_DIR path to the directory containing the deviceinterface.h file.

    For more information, refer to QmlProject InterfaceFiles.

  6. Re-run the qmlprojectexporter tool to regenerate C++ sources with the batch script created in Export application and platform sources.
  7. Re-build your GHS MULTI project to get the final application.
  8. Flash your application to the Traveo II board as you did earlier, and test that everything works as intended.

Your application is now ready. Next, you can try experimenting with the code by adding support for another LED.

Available under certain Qt licenses.
Find out more.