In January of 2020, we set out to create a multi-threaded application on Qt for MCUs. Here, the use case chosen was an Internet Radio Application.
We split the objective into Three Goals –
- First Goal – to get the HMI application running. A fairly easy objective, since we had already
developed the HomeChef for Qt, for MCUs.
- Second Goal – to enable networking on the Qt for MCUs with the ability to download images, station
names, and genres from the internet. It was a considerable milestone, as we had to create a multithreaded
application to run the GUI, and the backends to fetch internet data and serve them to the
- Third Goal – to stream MP3 content from the internet – decode and playback, and all while maintaining
a good and smooth GUI performance.
Equipment We Used
- Hardware – STM32F769i-Discovery
- OS – FreeRTOS v10.0.1
- lwIP network stack v2.0.3
- HMI framework – Qt for MCU Qul 1.2.0
How we went about developing the application:
Between Jan – Feb, we have created the UI using Qt Quick Ultralite, where all the data is pre-baked into QML. It consists of 2 screens:
The first screen will provide options to select categories: Stations, Genres, Cities, Artists, etc.
The second screen is for controlling the playback of the selected music, using controls like Play, Pause, and Volume Control.
After the creation of the GUI, we started the most interesting and challenging part of the project in March – adding networking support. For a few days, we explored and tried multithreaded examples by referring to the STM Cube SDK. Then, using Qt for MCU, we created multiple threads for GUI and networking, where we used the lwIP stack, made operational with some configuration settings.
The next challenge was to get the DHCP running. At the end of April, we got a Eureka moment when we acquired a Dynamic IP!!! This helped us connect the HTTP client-server and download the HTML content from the server successfully. Subsequently, we parsed the HTML content. We tried to download the station icons/images too but faced a memory shortage issue in the RAM. To solve the memory shortage issue as well as for data persistence, we stored the downloaded content into the Flash memory.
The subsequent step was about connecting the backend to the frontend. It commenced from mid of May, for a dynamic content update on the GUI. Qul components used to achieve this were:
Qul::ListModel: Qul::Object; Qul::Property; Qul::Signal; and Qul::Singleton
With these, we implemented a dynamic update of Station lists:1
- Station images/logos
It was quite easy to update the station names and genres from backend data with the help of the List Model class. But we faced a little bit of challenge while updating the station images. To update thems dynamically, we have used some of QUL’s private APIs that helped us render the images on to the GUI.
These API needs image data in the form of a raw image (i.e. BGRA format), but the downloaded images were in another form (e.g. PNG). Hence, we implemented the decoder which converts image data into BGRA format.
Finally, we achieved our milestone in the first week of June 2020.
This diagram explains how it all came together (note it does not yet contain the part for the music playback) while doing so, we came out with the below solution.
Memory and other key stats of the application :
four threads used:
1. App init Thread 2. DHCP
Heap allocated – 340 KB
Heap used for Thread stacks – 168 KB Heap used by
Images: 180 KB
Flash memory used for storing default image – 811 Bytes
Flash memory used for storing HTML file – for offline
mode – 3446 Bytes
Resources Semaphores – 3;