QT for MCU Application Development on Bare metal and RTOS

Gopalakrishnan M
28 November 2023
Categories:Technology,  Embedded Software,  UI/UX Design,  Consumer Electronics

Microcontroller Units (MCUs) are the heart of countless embedded systems, powering devices from consumer electronics to industrial machinery. With modern applications demanding rich user interfaces, many electronic devices now require graphical UI. QT for MCU application development, using the “QT for MCUs” variant, offers a robust solution for building graphical user interfaces on resource-constrained MCUs. QT for MCU strips away the heavyweight desktop runtime to deliver only what is needed for embedded UI rendering. While QT for MCU firmware development involves navigating hardware constraints and real-time requirements, it provides a powerful framework for creating attractive, responsive UIs. Today, we'll delve into the process of QT for MCU application development, comparing approaches for both bare-metal and Real-Time Operating Systems (RTOS). Embien's expertise in digital transformation services includes QT for MCU application delivery for automotive, industrial, and consumer products.

Understanding QT for MCU Application Architecture

Before diving into QT for MCU application development, it is essential to understand the architecture of QT for MCU. With a development history of over 23 years, QT is a C++ based library for backend integration with QML frontend development. It comes with a rich set of widgets, efficient memory management, modular architecture, and portability — all of which make QT for MCU one of the preferred choices for any GUI product.

While the full QT runtime is suitable for processor-based systems, MCUs are far more limited in terms of memory and features. A heavy runtime cannot be supported, and hence QT launched the QT for MCU variant targeted for smaller MCUs. This variant is optimized for QT for MCU firmware development on microcontrollers with as little as 256 KB of RAM.

The tech stack of QT is captured along with that of QT for MCU below.

QT for MCU Architecture

QT for MCU does not support multimedia, filesystem, Networking etc. It supports only graphical interface design.

In QT for MCU, all the design and assets are converted to cpp and compiled together to get a single elf file.

QT Files Organization

Run Time environment: Bare-Metal vs RTOS

QT for MCU can be run on embedded firmware both on bare-metal and RTOS modes. Let us understand the differences the same.

Bare-Metal: In a bare-metal environment, applications run directly on the MCU hardware without an operating system layer. Developers have direct control over hardware peripherals and system resources, allowing for maximum efficiency and minimal overhead. It will be a single threaded application with only one job running at any point in time. Bare-metal development requires careful management of application architecture to maintain the application responses to external world.

RTOS: In contrast, Real-Time Operating Systems (RTOS) provide a layer of abstraction on top of the hardware, enabling multitasking and deterministic behaviour. While there is a direct control over peripherals, RTOSes offer task scheduling, synchronization primitives, and communication mechanisms, making it easier to develop complex applications with strict timing requirements. However, RTOSes introduce overhead, and complexity compared to bare-metal development.

QT for MCU Application Development: Bare-Metal Approach

Bare metal QT for MCU firmware development involves running QT for MCU application logic directly on the MCU hardware without an OS. Understanding how QT for MCU renders content and handles UI updates at runtime is the core of bare metal QT for MCU firmware design.

Bare metal QT for MCU Firmware

In QT all the UI layouts are defined in QML language, for a project with multiple layouts and screens there will be multiple QML files. So, in QT project, we need to define one of the QML as an entrypoint for QT application by setting it as root item for QT Application. All the QML files will be converted to cpp and header files during compilation. Include necessary assets and resources in the qmlproject or cmake.

Example (Test.qml)

import QtQuick 2.15 
import QtQuick.Controls 2.15 
import DataModels 
Rectangle{ 
    width: 800 
    height: 480 
    visible: true 
    Image { 
        id: testImage 
        visible: true 
        source: TestModel.image1 			=>	QT Object variables 
    } 
} 

QML widget properties(source) are updated using QT Object variables.

Example(TestModel.qml)

pragma Singleton 
import QtQuick 2.15 
QtObject { 
    id: TestModel 
    property string image1: ''			   => QT Object Variable 
} 

Main.cpp shall be created and define the entrypoint of qml file and timer to update the QT object variable dynamically.

Example(main.cpp)
 
#include 'test.h'				         => 	default entry QML file header file 
#include  
#include  
#include  
int main() 
{ 
    Qul::initHardware();			     =>	Initialize hardware 
    Qul::initPlatform();				 =>	Initialize QT  
    Qul::Platform::getPlatformInstance(); 
    Qul::Application app; 
    static test item;			         =>	Create an instance of default QML file(test.qml) 
    Qul::Timer timer;				     =>	Timer instance to handle application requirement 
    timer.onTimeout([]() { timer_call(); });		=>	Register application handler for the timer 
    timer.start(1000);				     =>	Configure timer for 1ms 
    app.setRootItem(&item);			     =>	Configure QT application with root element as our default QML file. 
    app.exec();				             =>	QT application idle loop to redraw UI on need basis. 
    return 0; 
} 

As an example in the below timer routine, we are updating the display image path dynamically.

Example(timer.cpp)
void timer_handler () 
{ 
    ::TestModel &model = < Model URI >:: TestModel::instance();	=>	Fetch instance of a singleton qtobject class 
    /*Process business logic and update data*/ 
    /*Update QT Object interface variables to QML accordingly*/ 
    if (condition)
        Model.image1.setValue(“background.png”); 
    else
        Model.image1.setValue(“”); 
} 

This is a trivial approach which might be suitable for very small applications. But when we are working for a complex use case like an industrial HMI or automotive instrument cluster, there is a lot of business logic involved more than that can be handled over a simple timer handler. In this case the following approach can be used, where we keep the execution in application control and update the QT screens as and when necessary.

Example(main.cpp)

#include 'test.h'
#include  
#include  
int main() 
{ 
    Qul::initHardware(); 
    Qul::initPlatform(); 
    Qul::Application app; 
    static test item;				     =>	Create an instance of default QML file(test.qml)     
    app.setRootItem(&item); 
    while (true) { 
        uint64_t now = Qul::Platform::getPlatformInstance()->currentTimestamp(); 
        //  
        uint64_t nextUpdate = app.update(); 
        //Do business logic here 
	    if (event1) 
	    { 
            Model.image1.setValue(“background.png”); 
        } 
        else 
        { 
            Model.image1.setValue(“”); 
        } 
    } 
    return 1; 
} 

QT for MCU Application Development: RTOS Approach

RTOS based QT for MCU firmware separates the QT for MCU application rendering task from the business logic task, enabling true multitasking. RTOS based QT for MCU firmware is the preferred approach for complex applications such as automotive instrument clusters and industrial HMIs. The process is similar to the bare-metal approach but with added RTOS task management considerations.

RTOS based QT for MCU Firmware

RTOS Integration: Choose an RTOS that is suitable for the target and configure task scheduling, memory management, and communication mechanisms provided by the RTOS. Integrate application business case excluding UI as one or more task and configure priority of the tasks as required for the use case.

QT Integration: Create a dedicated task for LCD initialization and asset initialization. Post initialization QT EXEC will be called. QT exec is a QT idle loop routine, which repaints the UI based on dirty flag status. Dirty flag get set based on any widget property changes.

Synchronization and Communication: Utilize RTOS primitives for synchronization and communication between tasks, ensuring thread safety and deterministic behavior. QT widget properties update and repaint need to happen in the same thread.

Use case:Let's take a typical example of a firmware where the business logic runs one task and QT on another. Here the scheduler contact-switches both periodically and the business logic determines the value to be shown.

Via RTOS mechanisms these changes are to be indicated to the QT task from where the QT related API's can be called.

Example(main.cpp)

#include “qul_run.h” 
Void main(){ 
Platform_init();			                     =>	Initialize hardware 
RTOS_init();			                         =>	Initialize stack and heap for RTOS 
/*Create task for QT*/		                     =>	Create QT task and call qul_run() 
RTOS_Task_Start (qt_task); 
/*Create task for business logic and data processing */	 
RTOS_Task_Start (app_task); 
} 
Example(QTTask.cpp)

#include  
#include  
#include  
extern RTOSEvent Event1; 
int qt_task() 
{ 
    Qul::initHardware(); 
    Qul::initPlatform(); 
    Qul::Application app; 
    static test item;				               =>	Create an instance of default QML file(test.qml)    app.setRootItem(&item); 
    while (true) { 
        uint64_t now = Qul::Platform::getPlatformInstance()->currentTimestamp(); 
        //  
        uint64_t nextUpdate = app.update(); 
        if (nextUpdate > now) { 
            ::TestModel &model = < Model URI >:: TestModel::instance();	=>	Fetch instance of a singleton qtobject class  
            /*Process LIN/CAN data and do business logic*/ 
            /*Update QT Object interface variables to QML accordingly*/ 
            if (Rtos_IsEventSet (&Event1)) 
                Model.image1.setValue(“background.png”);	=>	Draw background image 
            else  
                Model.image1.setValue(“”);	=>	Turn off background image 
            
        } 
    } 
    return 0; 
} 
Example(AppTask.cpp)

#include 'app_task.h'				 
RTOSEvent Event1; 
int app_task() 
{ 
    /*Process business logic and derive information*/ 
    if (/*condition*/){ 
        Rtos_SetEvent (&Event1); 
    } 
    else { 
        Rtos_ClearEvent (&Event1); 
    } 
} 

An essential aspect to consider in the design is ensuring that any modifications to UI elements via models are executed in a sequential order to prevent potential race conditions in the QT processing pipeline. This sequential execution is critical for maintaining the integrity and consistency of the user interface.

This can be achieved by ensuring the UI elements are updated only in the QT task. By adhering to this, we can mitigate the risk of concurrent access to UI elements, thereby avoiding conflicts that could arise if multiple threads attempt to modify the interface simultaneously. Qt Application Development Services delivering efficient GUI solutions for MCU applications on bare metal and RTOS.

Conclusion

QT for MCU application development provides a powerful framework for GUI applications on MCUs, offering high abstraction and cross-platform compatibility. Whether opting for bare metal QT for MCU firmware or RTOS based QT for MCU firmware, QT for MCU enables developers to create rich and responsive user interfaces for embedded systems. By understanding the differences between the two approaches, teams can choose the best fit for their QT for MCU firmware development project, balancing efficiency, real-time performance, and development complexity. Whether the QT for MCU application is a simple consumer gadget or a complex automotive cluster, QT for MCU empowers developers to unlock the full potential of MCUs across a wide range of applications.

Related Pages

PRODUCT ENGINEERING SERVICES

Embien's product engineering services include end-to-end QT for MCU application delivery — from QT for MCU firmware development architecture through production deployment.

Read More

QT APPLICATION DEVELOPMENT SERVICES

Embien's QT application development services cover QT for MCU, bare metal QT for MCU firmware, and RTOS based QT for MCU firmware for automotive, industrial, and consumer platforms.

Read More

TFT BASED INSTRUMENT CLUSTER WITH SPARKLET ON RENESAS RH850

Case study: TFT-based instrument cluster showcasing QT for MCU application development with RTOS based QT for MCU firmware on Renesas RH850 hardware.

Read More

Subscribe to our Blog