cancel
Showing results for 
Search instead for 
Did you mean: 

How do ThreadX Message Queues work on STM32 part 2

B.Montanari
ST Employee

How do ThreadX Message Queues work on STM32?

This is the part 2 of the article to explain how the ThreadX Message Queue work on STM32 with working examples. Welcome back!

1. STM32CubeIDE – step by step demo:


Launch STM32CubeIDE (version used 1.7.0), select your preferred workspace, click on Launch. Once open, locate the Information Center, select to Start New STM32 Project – alternatively, click on File->New->STM32 Project. For this demo, we’ll use the NUCLEO-H723ZG as the starting point
186.png
Give your project a name, just remember to avoid space and special characters – the name given by this article is “Queue”
A pop up asking if we should initialize the peripherals in the default mode, click yes. Then second popup to ask to open device configuration perspective, click yes again
Time to add the software pack:
187.png
Browse and locate the AzureRTOS pack in the component selection window:
188.png
Open the RTOS ThreadX and check the Core box and click OK
189.pngThis will add the Software Pack in the lower part of the Categories:
190.png
Now, by clicking on it, you can add the RTOS ThreadX box, this will show the configuration options for the AzureRTOS application
191.png
As this demo is just meant to create small printfs to indicate which thread it is and use the message queue, the default settings are alright, 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 time base for the HAL by clicking in the System Core/SYS and selecting the time base Source as TIM6:
192.png
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:
193.png
All set, we can press Alt+K to generate the code and Ctrl+S to save it:
194.png
The project now has a new set of folders, this is the detail of its structure:
195.png
The last part is to create our demo code. Just to recap, this first portion of the demo will use a single sender and receiver, using a queue to send a message:
196.gif
Open Core\Src \app_threadx.c – Here we’ll create the 2 threads using the command tx_thread_create and the message queue, by using tx_queue_create.
The Sender1 thread will send the queue message, increment the content and then sleep for 2 seconds, to avoid spamming the terminal. The Receiver thread is always in suspended mode waiting for the queue to be received. You can copy and paste the code below, please use the USER CODE to locate the proper region to paste it:
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "main.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PD */
#define THREAD_STACK_SIZE 	512
#define QUEUE_STACK_SIZE		128
/* USER CODE END PD */
/* USER CODE BEGIN PV */
uint8_t thread_sender1[THREAD_STACK_SIZE];
uint8_t thread_receiver[THREAD_STACK_SIZE];
uint8_t   queue_stack[QUEUE_STACK_SIZE];
TX_THREAD sender1_ptr;
TX_THREAD receiver_ptr;
TX_QUEUE  queue_ptr;
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
VOID Sender1 (ULONG initial_input);
VOID Receiver (ULONG initial_input);
/* USER CODE END PFP */
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 */
	tx_queue_create(&queue_ptr, "Queue0", 1 ,queue_stack,128);
	tx_thread_create(&sender1_ptr,"Sender1",Sender1, 0, thread_sender1,THREAD_STACK_SIZE,15,15,1,TX_AUTO_START);
	tx_thread_create(&receiver_ptr,"Receiver",Receiver, 0, thread_receiver,THREAD_STACK_SIZE,15,15,1,TX_AUTO_START);
	/* USER CODE END App_ThreadX_Init */
	return ret;
}
/* USER CODE BEGIN 1 */
VOID Sender1 (ULONG initial_input){
	/* Infinite loop */
	uint32_t message1=0;
	for(;;)	{
	    printf("Sender1\r\n");
	    tx_queue_send(&queue_ptr,&message1,TX_NO_WAIT);
	    printf("Sender1 delay\r\n");
	    message1++;
		/* Sleep for 2seconds */
		tx_thread_sleep(200);
	}
}
VOID Receiver (ULONG initial_input){
	uint32_t message_received;
	for(;;)	{
		tx_queue_receive(&queue_ptr,&message_received,TX_WAIT_FOREVER);
		printf("message received:%lu \r\n",message_received);
	}
}
/* USER CODE END 1 */
Open Core\Src \main.c – you can copy and paste the code below:
/* USER CODE BEGIN 0 */
void __io_putchar(char ch) {
    // Code to write character 'ch' on the UART
    HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 10);
}
/* USER CODE END 0 */
From this point, press Ctrl+B to build and you should see 0 errors and 0 warnings.
Connect the board to the computer and enter in debug mode by first clicking in the project name, then menu Run/Debug As/STM32. In Edit Configuration window, click Debug:
197.png
Once in the Debug perspective, click in the resume button to enjoy your ThreadX application with mutex working. You can also use the Window/Show View/ThreadX/ThreadX Thread List and do it again for the ThreadX Queue to enhance the overall debugging options (the thread list will be automatically loaded once the application runs for a bit and is paused):
198.png
Now, the last step is to enable the console inside the STM32CubeIDE to see the print messages. Locate the Console tab and click Command Shell Console:
199.png
In the pop-up window, change the Connection Type to Serial Port and click on New… to add the VCOM related to your STLINK:
200.png
You can give the port a name, so it is easier for later usage as well, in this case, it will be labelled as NUCLEO_H723ZI:
201.png
By clicking finish, the message on the console will indicate it is now connected.
Here is the debug view when adding a breakpoint in the Receiver Thread with the views for threads and queues enabled. It is possible to see the size of the queue as 32, and this is because upon the queue creation it was set to have a single word (32bit long or 4 byte long) with a stack size of 128 bytes, so 128/4 = 32. You can also check that the Message Queue tab is showing that currently, the queue has 1 message there, thus the Free size is 31:
202.png
By removing the breakpoint, adding the console view and hitting F8, we can see the code running with the messages being displayed:
203.png
On the third and last part , we'll add the second sender thread and explore the priority change effects.
See you soon!
https://community.st.com/s/article/how-do-threadx-message-queues-work-on-stm32-part-3
Version history
Last update:
‎2021-12-14 07:29 AM
Updated by: