cancel
Showing results for 
Search instead for 
Did you mean: 

How to create a Thread using AzureRTOS and STM32CubeIDE

B.Montanari
ST Employee

How to create a Thread using AzureRTOS and STM32CubeIDE?

Using the software package available in the STM32Cube ecosystem is straight forward, all steps and a demo code are provided in this article.

 

  • Goal: The purpose of this article is to give you a first overview of how the AZURE-RTOS ThreadX is supported in the STM32Cube ecosystem
Although the example is using the NUCLEO-H723ZG, you can use the same steps for other STM32H7 based boards. The main differences are usually pinout and clock configuration.
This article will show you how to start a project from scratch, with the goal of getting an LED to blink in a few clicks, while using a simple thread to do it.
Demo block diagram:
422.png
  • STM32CubeIDE – step by step demo:

 

  1. Launch STM32CubeIDE (version used 1.7.0)
  2. Select your preferred workspace, click on Launch
  3. In the information Center, select to Start New STM32 Project
423.png

 

  1.  For this demo in particular, we’ll use the NUCLEO-H723ZG as the starting point:
424.png

 

  1. Give your project a name, just remember to avoid space and special characters – if you are missing any libraries, the STM32CubeIDE will automatically start the download now
425.png
A pop up asking if we should initialize the peripherals in the default mode, click yes:
426.png
Then second popup to ask to open device configuration perspective, click yes again:
427.png

 

  1. Now you should have a view of the MCU with some of its peripherals configured, and on the left side you’ll have the initial code, yet without the ThreadX added
428.png
Time to add the software pack:
429.png

 

  1. Browse and locate the AzureRTOS pack in the component selection window:
430.png

 

  1. Open the RTOS ThreadX and check the Core box and click OK
431.png

 

  1. This will add the Software Pack in the lower part of the Categories:
435.png

 

  1. Now, by clicking on it, you can add the RTOS ThreadX box, this will show the configuration options for the AzureRTOS application
438.png


 

  1. As this demo is just meant to blink an LED, the default settings are all set, but we do need to do one other modification. By default, the HAL driver will use the Systick as its primary time base, but this timer should be left to the AzureRTOS only.
If the HAL library doesn’t have a separate time source, the compilation will fail because both libraries want to use the SysTick_Handler interrupt. To prevent this, we can simply select a different timebase for the HAL by clicking in the System Core/SYS and selecting the time base Source as TIM6:
441.png

 

  1. One final modification, to prevent generating too much unused code, we can decide to not create the functions for USB and Ethernet, as they were natively added when we created the design based on the board, this can be done by removing the Generate Code for them:
445.png

 

  1. All set, we can press Alt+K to generate the code and Ctrl+S to save it:
449.png
The project now has a new set of folders:
450.png
This is a detail on the code structure:
451.png

 

  1.  The last part is to create the first thread:

 

  • Open Core\Src \app_threadx.c and start adding the code at around line 37, use the comments to find the proper place for the following code:

 

452.png
  • After the stack is allocated, we can create the thread inside the function App_ThreadX_Init:
453.png
Some notes on what we just added:
454.png
  • Create the thread’s main function
First, as we want access to LED definitions, we need to include main.h, still in the same app_threadx.c file:
456.png
And finally our thread:
458.png
It might not have been clear up until this point, but the default time base is 10ms, so by having the tx_thread_sleep(20) will actually wait for 200ms
459.png

 

  1. From this point, press Ctrl+B to build and you should see 0 errors and 0 warnings.

 

  1. Connect the board to the computer and enter in debug mode by first clicking in the project name, then menu Run/Debug As/STM32:
461.png
In Edit Configuration window, click Debug:
463.png

 

  1. Once in the Debug perspective, hit play to enjoy your blinking LED with ThreadX. You can also use the Window/Show View/ThreadX/ThreadX Thread List
465.png
To enhance the overall debugging options (the thread list will be automatically loaded once the application runs for a bit and is paused):
466.png
 
  • Useful links:

 

  • Conclusion:
Adding ThreadX application to a bare metal project consists in:
    • Adding the ThreadX component in STM32CubeMX/STM32CubeIDE
    • Adapt ThreadX configuration in STM32CubeMX/ STM32CubeIDE
    • Generate the code from STM32CubeMX/ STM32CubeIDE
      1. This will update the project structure with all needed files
    • Use ThreadX API to create ThreadX components thread, mutex, etc
Comments
OHaza.1
Associate III

Is it safe to allocate the stack like this? I see in the examples it's usually allocated with tx_byte_allocate

LauraCx
ST Employee

Hi @OHaza.1​ 

Thank you for your question, @B.Montanari​ I am sure you can provide some insights.

B.Montanari
ST Employee

Hi @OHaza.1​ ,

Yes, it is safe to allocate the stack as shown in this example. When calling the tx_thread_create(), among its passing arguments, it expects to receive the starting address of the stack's memory area and the number bytes in the stack memory area. The thread's stack area must be large enough to handle its worst-case function call nesting and local variable usage. The way it is displayed in this article, those arguments are used thru a global vector, so both conditions are properly met and I think it is easier overall to use and edit as needed (but this is just my personal preference). Of course, it is also fine to do it by calling the tx_byte_allocate and then tx_thread_create using the pointer for the stack. The code generated by the STM32CubeIDE will create a pool using the settings showed at step10 - this is done inside the app_azure_rtos.c file in the tx_application_define() . Inside it or in the App_ThreadX_Init() you can add your tx_byte_allocate() call to make use of it.

In a nutshell, these would be the code pieces:

#define DEMO_STACK_SIZE 512
 
 
UINT App_ThreadX_Init(VOID *memory_ptr){
	UINT ret = TX_SUCCESS;
	TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr;
	/* USER CODE BEGIN App_ThreadX_MEM_POOL */
	(void)byte_pool;
	/* USER CODE END App_ThreadX_MEM_POOL */
	/* USER CODE BEGIN App_ThreadX_Init */
	CHAR *pointer;
	/* Allocate the stack for thread 0. */
	tx_byte_allocate(byte_pool, &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
	/* Create the main thread. */
	tx_thread_create(&thread_ptr, "my_thread", my_thread, 0,pointer, DEMO_STACK_SIZE,15, 15, 1, TX_AUTO_START);
}

let me know if you have any further questions

OHaza.1
Associate III

Ok, thanks for the detailed explanation. Yes it does seem a little cleaner if more involved memory management is not required/desired.

jerry_sandc
Associate III

I like this post, thanks.

I'm trying to figure out the purpose of these lines in the _Init functions.  What does (void)byte_pool; do ?

/* USER CODE BEGIN MX_FileX_MEM_POOL */
(void)byte_pool;
/* USER CODE END MX_FileX_MEM_POOL */

 

Version history
Last update:
‎2024-01-03 09:04 AM
Updated by:
Contributors