STMicrosoft?
Microsoft’s purchase of Azure RTOS, formerly known as ThreadX, raised many questions. This article looks at the Microsoft-STMicroelectronics-relationship, at the products offered, and also gives some background information.
First things first: Azure RTOS is, by no means, a new product. It, instead, is but a rebrand of Express Logic‘s ThreadX product, along with a slightly modified direction of marketing. The most important change is that use of the product is now free on all microcontrollers (MCUs) where Microsoft has achieved a deal with the silicon vendor.
While the supported device list, shared on the Azure RTOS GitHub and reprinted below, it lists a significant amount of devices; STMicroelectronics (ST) stands out in terms of particularly aggressive public support for the new product:
STMicroelectronics:
STM32 MCUs
STM32 MPUs
MediaTek:
MT3620 MCU (Azure Sphere)
Microchip Technology:
PIC 32-bit MCUs
SAM 32-bit MCUs
SAM 32-bit MPUs
NXP Semiconductor:
NXP i.MX RT10xx series crossover MCUs
— ADVERTISMENT—
—Advertise Here—
Renesas Electronics:
Synergy Platform
RX Family of MCUs
RZ Family of MPUs
In the following steps, we will use an STMicro STM32H723 Nucleo144 evaluation board to do first tests with the real-time operating system. As of now, ST‘s STM32H7 is the only officially supported STM32 architecture. This, however, does not mean that ST will not add support for future MCU architectures. A recently held webinar (access it here) presented the slides shown in Figure 1 and Figure 2 providing further information. STMicroelectronics representatives keep repeating that the license achieved with Microsoft explicitly permits the porting of ThreadX to any STM32 core including low-end units such as the F0 and the F1.
While STMicroelectronics says it does not plan to remove FreeRTOS from already released MCU support packages, new MCUs were said to be Azure RTOS only in the webinar. This means that the graphical configuration in CUBE will be limited to Azure RTOS. If you still want to use FreeRTOS, GitHub bundles will, however, be made available for manual integration.
Finally, keep in mind that both safety and security pre-certification is handled via Microsoft. This means that STMicroelectronics customers need to get the certification documents from Microsoft, which comes at a price. This price was said to be volume dependent, and has not been disclosed publicly during webinars and presentations. All we currently know is that this price determination is to be started by getting in touch with a local ST field engineer.
Why ThreadX?
Real time operating systems (RTOSes) are dime a dozen: simple task scheduling is a common „first reason“ for their deployment. In practice, managing threads usually is the least of the problems adressed by an RTOS. More important problems involve network communications, file system management and graphical user interfaces. Azure RTOS covers these “must haves“ via a group of dedicated libraries shown in Figure 3.
One important aspect is that ThreadX is required for USBX, FileX and NetXDuo—bare metal mode for the advanced modules is not supported as of this writing. In addition to that, some aspects of the USBX library—think, in particularily, about working with USB Sticks—also require the FileX library. USBX stands out from other RTOS‘s USB stack in that it provides an advanced set of peripheral capabilities. One nice demonstration involves the simulation of an USB mouse on the H7, which is done with but a few lines of code.
This can best be illustrated by visiting https://github.com/STMicroelectronics/x-cube-azrtos-h7 and downloading the entire repository. It is a “normal“ STM32 feature pack and can be extracted anywhere. Yours truly placed it in C:\Users\tamha\Downloads\x-cube-azrtos-h7-main. x-cube-azrtos-h7-main\Projects\NUCLEO-H723ZG\Applications. It contains all examples relevant for our evaluation board. While a more detailed discussion of the startup and the handling processes inside an Azure RTOS program will follow later in this article, feel free to load the example Applications\USBX\Ux_Device_HID at this point.
Given that most Azure RTOS based projects contain the operating systems source code in them, the example projects downloaded from STMicroelectronics GitHub site can be loaded as if they were a normal STM example. Do, however, keep in mind that using the Azure RTOS integration requires at least version 1.5 of the IDE. In practice, downloading 1.6 is the smarter approach. It provides a variety of GUI based helpers to Azure RTOS projects which we will discuss during the steps that follow.
CUBE is able to update itself via the self-service facilities of the Eclipse IDE. Do keep in mind that these do not change the version string shown in the Windows 10 start menu. Yours truly has version 1.6.0 installed, but the start menu of the workstation still displays the originally installed version 1.5.1.
— ADVERTISMENT—
—Advertise Here—
The meat of the USB mouse simulator is found in the folder USBX/App/. start out by looking at the file app usbx_device.c. It creates a normal Azure RTOS based application. Interestingly, the realization of the UsbX stack starts out by the creation of a set of sub-frameworks shown in Listing 1.
Listing 1
UINT App_USBX_Device_Init(VOID *memory_ptr) {
. . .
ux_system_initialize(pointer, USBX_MEMORY_SIZE, UX_NULL, 0);
/* Get_Device_Framework_High_Speed and get the length */
device_framework_high_speed = USBD_Get_Device_Framework_Speed(HIGH_SPEED,
&device_framework_hs_length);
/* Get_Device_Framework_High_Speed and get the length */
device_framework_full_speed = USBD_Get_Device_Framework_Speed(FULL_SPEED,
&device_framework_fs_length);
/* Get_String_Framework and get the length */
string_framework = USBD_Get_String_Framework(&string_framework_length);
/* Get_Language_Id_Framework and get the length */
language_id_framework = USBD_Get_Language_Id_Framework(&languge_id_framework_length);
When all these classes are provided, the actual USB stack can then be brought up via a dedicated method, as shown in Listing 2.
Listing 2
ret = _ux_device_stack_initialize(device_framework_high_speed,
device_framework_hs_length,
device_framework_full_speed,
device_framework_fs_length,
string_framework,
string_framework_length,
language_id_framework,
languge_id_framework_length, UX_NULL);
Embedded developers will now ask themselves where we configure the USB periphery of the MCU. The answer for this is the method usbx_app_thread_entry
, which, interestingly, invokes a CUBE generated hardware configuration method as follows:
void usbx_app_thread_entry(ULONG arg)
{
tx_thread_sleep(0.1 * TX_TIMER_TICKS_PER_SECOND);
MX_USB_Device_Init();
}
The actual logic sits in file ux_device_mouse.c. There, we (mainly) find another thread method, which uses the UsbX driver component in order to transmit mouse coordinates to the USB host, as show in Listing 3.
Listing 3
void usbx_hid_thread_entry(ULONG arg)
{
UX_SLAVE_DEVICE *device;
UX_SLAVE_INTERFACE *interface;
UX_SLAVE_CLASS_HID *hid;
UX_SLAVE_CLASS_HID_EVENT hid_event;
device = &_ux_system_slave->ux_system_slave_device;
ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
while (1)
{
if (device->ux_slave_device_state == UX_DEVICE_CONFIGURED)
{
interface = device->ux_slave_device_first_interface;
hid = interface->ux_slave_interface_class_instance;
/* sleep for 10ms */
tx_thread_sleep(0.01 * TX_TIMER_TICKS_PER_SECOND);
GetPointerData(&hid_event);
ux_device_class_hid_event_set(hid, &hid_event);
}
Finally, a quick look at the generation of the actual pointer information, as shown in Listing 4.
Listing 4
static void GetPointerData(UX_SLAVE_CLASS_HID_EVENT *hid_event)
{
static int8_t cnt = 0;
int8_t x = 0, y = 0;
if (cnt++ > 0)
{
x = CURSOR_STEP;
}
else
{
x = -CURSOR_STEP;
}
/* Mouse event. Length is fixed to . */
hid_event->ux_device_class_hid_event_length = 3;
hid_event->ux_device_class_hid_event_buffer[0] = x;
hid_event->ux_device_class_hid_event_buffer[1] = y;
hid_event->ux_device_class_hid_event_buffer[2] = 0;
}
Anyone who ever tried to bit bang USB HID by hand can testify that the code provided here is a great simplification. Incidentally, creating Virtual USB input periphery is a common task—not only for companies working on mice, but also for the ever more important market of cyber warfare trinkets. Emulating a keyboard can also be a very cheap way to input data into a system.
Finally, an interesting question remains: What about the ThreadX GUI stack, or, more commonly known as GuiX? The answer to this is simple: Some years before Microsoft purchased ThreadX, STMicroelectronics went on a shopping spree and acquired Draupner Graphics.
This company provides its own GUI stack which is known as touchGFX. ST explicitly stated that it rather its developers use this product for creating applications with a user interface even when ThreadX is used.
This does not mean that the use of GuiX is prohibited. If a developer wants to use it and is willing to handle porting and integration on his own, the licensing agreement between Microsoft and STMicroelectronics is permissive of this admittedly somewhat unusual application scenario. This is further confirmed by the list of licensed hardware for GuiX, found at https://github.com/azure-rtos/guix/blob/master/LICENSED-HARDWARE.txt.
CUBE 1.6 to the Rescue
Traditionally, playing around with a RTOS and/or a MCU was a job based on digging through examples. If you feel like this, visit https://github.com/azure-rtos/samples to find offerings for various MCU types. Recent developments—say during about the last five years or so—have shown a shift in focus. Instead of providing the developer with the software development kit and then leaving him to fend for himself, more and more sophisticated code generators—think Microchip MCC, but also the original ST‘s (non-IDE) CUBE—provided developers with a GUI generating a custom project skeleton containing all the hardware drivers required for the peripheral task at hand.
An interesting aspect of ST‘s CUBE is the ability of the product to integrate expansions called packs. Once a pack is loaded, it (normally) can be used and configured from the graphical code generator. The author insists on the statement (normally) here because of his personal experience – some packs, such as the flash memory library for the L4, are not yet graphical.
Be that as it may, the Azure RTOS package currently is not part of the default installation. This can be fixed by opening Help → Manage Embedded Software packages. Firstly, update the package description via the Refresh button, and then switch into the STMicroelectronics tab. There, select X-CUBE-AZRTOS-H7, expand it and mark it as shown in Figure 4. Finally, click the Install Now button and agree to the licensing terms to finalize the deployment.
When the installation has run its course, start a new project using the eclipse project generator. Select the template ST → STM Project to start the STMicroelectronics Target Selector. There, enable the tab Board Selector and search for the code NUCLEO-H723ZG in order to create a project skeleton for our evaluation board.
Once the graphical configuration is done, you find yourself in Eclipse project generation mode. In the following steps, Yours truly will select a project name of PrescottDemo. Make sure to let the “Targeted project type“ be Cube to ensure the generation of the files needed for the graphical editor. Furthermore, ensure that the “Targeted language“ setting is set to C. If you select C++ here, all kinds of weirdness can ensure as Azure RTOS is a C based operating system. Other than that, most of the settings can be left as they are—generate an STM32CubeIDE project, and do agree to initialize all peripherals with their default modes. Don’t be surprised if project generation takes a few minutes. CubeIDE is partially parallelized, and the H7 is a notoriously “hairy“ architecture with a lot of complicated settings.
— ADVERTISMENT—
—Advertise Here—
When project generation is done, switch into the Pinout & Configuration tab. There, click the menu option Software Packs, and select the option Select Components. CubeIDE will react by displaying a list of packages. There, expand the Azure RTOS package, open the device subsection and set the HW_Profile selection to the STM32H7 option offered. Next, go one step down to the application option, and select the option Azure RTOS app as shown in Figure 5. If the width of the individual tabs in the selector is too small, modify it by dragging and dropping the boundaries.
Interestingly, selecting the string provokes CubeIDE to show a serieus of warnings in the Component Dependencies window. The pack contains sufficient logic in order to automatically determine if the selected configuration will lead to a viable project skeleton.
The easiest way to get the application to compile is to select the package ThreadX/Core. This can also be done by clicking on the results button for this entry in the Component Dependencies window. Once the IDE displays the bold text All conditions are solved, the integration of the pack is complete. You can, of course, also use this window to select other packages such as the file system, the USB or the network components. As we discussed before, the GuiX stack is not made available here because ST you to use its custom TouchGFX component. When done, close the package management window by selecting the OK button.
When done, the .IOC file editor will have a new option called Software packs → STMicroelectronics. Open it as if you were configuring a hardware device, and check both checkboxes in the mode selector. Selecting one of them will automatically lead to the display of new options in the configuration window below. When all checkboxes are enabled, you have a total of three tabs as shown in Figure 6.
Interestingly, the configuration tool lets you set up a variety of parameters in order to customize the behavior of the ThreadX stack to your needs. You can, for example, adjust the behavior of the scheduling or of the timers. Be that as it may, save the .IOC file and permit Cube to regenerate your application code at this point. The IDE offers you to perform a perspective switch, this is also recommended.
CUBE, Reloaded
Getting the clock configuration of an STM32 board right is a science of its own. Yours truly learned this the hard way when his L4 design started having all kinds of problems after it woke up from sleep mode.The default settings used in the CubeIDE set a subideal configuration, which is called out by the project generator with the window shown in Figure 7.
For our current experiment, however, click the Yes option in order to force code generation. For this little analysis of the project structure, having maximum timing accuracy is not required.
When done, you will find more or less stock STM32 project which, however, has an additional folder with a familiar name (see Figure 8).
It‘s obvious that our generated project skeleton contains the bare-bones implementation of an Azure RTOS application. First, let trace down the control flow. Program life begins in the main method, where we find a total of two methods in addition to the code which you should already know from your work with CUBE.
int main(void) {
. . .
MX_USB_OTG_HS_USB_Init();
MX_AZURE_RTOS_Init();
. . .
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_AZURE_RTOS_Process();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
Tracing the method MX_AZURE_RTOS_Init()
leads us into the application-specific code, shown below. There, we find the following declaration:
void MX_AZURE_RTOS_Init(void)
{
/* USER CODE BEGIN Before_Kernel_Start */
/* USER CODE END Before_Kernel_Start */
tx_kernel_enter();
/* USER CODE BEGIN Kernel_Start_Error */
/* USER CODE END Kernel_Start_Error */
}
CUBEs generated code is suboptimal at this point, as it pretends that the is a life after the method tx_kernel_enter()
. If we, however, look at the actual declaration of the method, we find that it does not return. It instead starts off the ThreadX kernel, which then takes care of dispatching work towards its individual worker threads. Once program flow control has been transferred to the operating system, the next step in is the invocation of the application declaration. It looks as shown in Listing 5.
Listing 5
VOID tx_application_define(VOID *first_unused_memory)
{
#if (USE_MEMORY_POOL_ALLOCATION == 1)
VOID *memory_ptr;
if (tx_byte_pool_create(&tx_app_byte_pool, "Tx App memory pool", tx_byte_pool_buffer, TX_APP_MEM_POOL_SIZE) != TX_SUCCESS)
{
}
else
{
memory_ptr = (VOID *)&tx_app_byte_pool;
if (App_ThreadX_Init(memory_ptr) != TX_SUCCESS)
{
At this point, you are, in principle, free to proceed however you see fit. However, please keep in mind that the method MX_AZURE_RTOS_Process();
usually is not invoked automatically. You must, instead, declare your own thread if you want to something meaningful re payload. This, however, would be beyond of the scope of this short introduction to ThreadX.
Avoid Knee-Jerk Reactions
Express Logic‘s ThreadX product always was the “Convair 990“ of RTOSes—a high performance system with great functionality, albeit at a substantial price. Microsoft‘s rechristening to Azure RTOS eliminates the price pain point. From a technical point of view, the wide amount of supported libraries and functions makes clear why ST‘s changes its embedded software provider. In addition to that, Azure‘s ever-more-sophisticated ML (machine learning) and management capabilities make for a potent first step in the ever-annoying task of coding the web interface for a solution.
On the other hand, the licensing of Azure RTOS is more restrictive than the one in FreeRTOS. This, however, is a mitigatable risk. The presence of Amazon FreeRTOS ensures that fear scenarios of a “surprise price hike“ commonly peddled here by the West German press are unlikely. If Microsoft raises prices by a lot, mass migration will take place. The same applies for cloud services. MQTT after all, remains MQTT and can (or should) be bought from other vendors if the Azure solution becomes expensive.
Disclaimer: the author of this story acts as engineering teacher for LinkedIn Learning of West Germany. This company is a subsidiary of Microsoft. However, the earnings from this relationship are insignificant (less than 5% of annual active income).
WEB EXCLUSIVE ARTICLE
Sponsor this ArticleBefore entering the mobile market in 2004, Tam Hanna earned himself some money in the embedded design space...only to return to embedded design again with a lot of mobile phone programming experience. Find out more about my work and my cigar smoking habit at my Instagram account at https://www.instagram.com/tam.hanna/ - given that 20 000 people follow the Crazy Electronics Lab, you will be in good company - and do not forget that we smoke the bad cigars so that you don't have to!