Just like memorizing text when we were young, there are some codes that need to be memorized (a little exaggeration, but at least familiar). The demo of threadX for STM32 is posted here today to familiarize me a little bit.

Description of this code (translated from official documentation)

This application provides an example of using the Azure RTOS ThreadX stack, which shows how to develop an application using the ThreadX thread management API. It demonstrates how to create and destroy multiple threads using the Azure RTOS ThreadX APIs. In addition, it demonstrates how to use preemption thresholds between threads and dynamically change priorities. During ThreadX kernel startup, ThreadX calls the main entry function tx_application_define(). At this stage, the application creates three threads with different priorities:

  • MainThread (Priority: 5; Preemption threshold: 5)
  • ThreadOne (Priority: 10; Preemption threshold: 9)
  • ThreadTwo (Priority: 10; Preemption threshold: 10)

At present, I have not made clear the meaning of preemption threshold, temporarily think it is preemption priority. When I do, I’ll talk specifically about priorities and preemption thresholds.

Once started, MainThread is suspended and then waits for the event flag. ThreadOne starts turning the green light LED_GREEN on and off repeatedly at 500ms intervals, ThreadTwo does not execute because its preemption priority (preemption threshold) is smaller than ThreadOne’s, and after 5 seconds it sends an event flag for THREAD_ONE_EVT to MainThread.

After receiving THREAD_ONE_EVT, MainThread changes ThreadTwo’s preemption priority to 8, where it has a higher preemption priority than ThreadOne’s, and waits for the event.

ThreadTwo can now crowd out ThreadOne to start turning the green LED_GREEN5 seconds on and off repeatedly at 200ms intervals. When it finishes, it sends the THREAD_TWO_EVT event to the MainThread. Once MainThread receives the ThreadTwo_Evt event flag, it restores ThreadTwo’s priority and preempts it to its original value (10, 10), and ThreadOne is called again to perform the above set of actions. After the above actions have been performed three times, MainThread destroys ThreadOne and ThreadTwo, and keeps turning the LED_GREEN green on and off at one-second intervals.

/* USER CODE BEGIN Header */
/** ****************************************************************************** * @file app_threadx.c * @author MCD Application Team * @brief ThreadX applicative file ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "app_threadx.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ TX_THREAD MainThread; TX_THREAD ThreadOne; TX_THREAD ThreadTwo; TX_EVENT_FLAGS_GROUP EventFlag; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ void ThreadOne_Entry(ULONG thread_input); void ThreadTwo_Entry(ULONG thread_input); void MainThread_Entry(ULONG thread_input); void App_Delay(uint32_t Delay); /* USER CODE END PFP */ /** * @brief Application ThreadX Initialization. * @param memory_ptr: memory pointer * @retval int */ 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_Init */ CHAR *pointer; /* Allocate the stack for MainThread. */ if(tx_byte_allocate(byte_pool, (VOID **) &pointer, APP_STACK_SIZE, TX_NO_WAIT) ! = TX_SUCCESS) { ret = TX_POOL_ERROR; }/* Create MainThread. */ if (tx_thread_create(&MainThread, "Main Thread", MainThread_Entry, 0, pointer, APP_STACK_SIZE, MAIN_THREAD_PRIO, MAIN_THREAD_PREEMPTION_THRESHOLD, TX_NO_TIME_SLICE, TX_AUTO_START) ! = TX_SUCCESS) { ret = TX_THREAD_ERROR; }/* Allocate the stack for ThreadOne. */ if(tx_byte_allocate(byte_pool, (VOID **) &pointer, APP_STACK_SIZE, TX_NO_WAIT) ! = TX_SUCCESS) { ret = TX_POOL_ERROR; }/* Create ThreadOne. */ if (tx_thread_create(&ThreadOne, "Thread One", ThreadOne_Entry, 0, pointer, APP_STACK_SIZE, THREAD_ONE_PRIO, THREAD_ONE_PREEMPTION_THRESHOLD, TX_NO_TIME_SLICE, TX_AUTO_START) ! = TX_SUCCESS) { ret = TX_THREAD_ERROR; }/* Allocate the stack for ThreadTwo. */ if(tx_byte_allocate(byte_pool, (VOID **) &pointer, APP_STACK_SIZE, TX_NO_WAIT) ! = TX_SUCCESS) { ret = TX_POOL_ERROR; }/* Create ThreadTwo. */ if (tx_thread_create(&ThreadTwo, "Thread Two", ThreadTwo_Entry, 0, pointer, APP_STACK_SIZE, THREAD_TWO_PRIO, THREAD_TWO_PREEMPTION_THRESHOLD, TX_NO_TIME_SLICE, TX_AUTO_START) ! = TX_SUCCESS) { ret = TX_THREAD_ERROR; }/* Create the event flags group. */ if (tx_event_flags_create(&EventFlag, "Event Flag") != TX_SUCCESS) { ret = TX_GROUP_ERROR; } /* USER CODE END App_ThreadX_Init */ return ret; } /* USER CODE BEGIN 1 */ /** * @brief Function implementing the MainThread thread. * @param thread_input: Not used * @retval None */ void MainThread_Entry(ULONG thread_input) { float t=0; UINT old_prio = 0; UINT old_pre_threshold = 0; ULONG actual_flags = 0; uint8_t count = 0; (void) thread_input; while (count < 3) { count++; if(tx_event_flags_get(&EventFlag, THREAD_ONE_EVT, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER) ! = TX_SUCCESS) { Error_Handler(); }else { /* Update the priority and preemption threshold of ThreadTwo to allow the preemption of ThreadOne */ tx_thread_priority_change(&ThreadTwo, NEW_THREAD_TWO_PRIO, &old_prio); tx_thread_preemption_change(&ThreadTwo, NEW_THREAD_TWO_PREEMPTION_THRESHOLD, &old_pre_threshold); if(tx_event_flags_get(&EventFlag, THREAD_TWO_EVT, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER) ! = TX_SUCCESS) { Error_Handler(); }else { /* Reset the priority and preemption threshold of ThreadTwo */tx_thread_priority_change(&ThreadTwo, THREAD_TWO_PRIO, &old_prio); tx_thread_preemption_change(&ThreadTwo, THREAD_TWO_PREEMPTION_THRESHOLD, &old_pre_threshold); }}}/* Destroy ThreadOne and ThreadTwo */ tx_thread_terminate(&ThreadOne); tx_thread_terminate(&ThreadTwo); /* Infinite loop */ while(1) { BSP_LED_Toggle(LED_GREEN); OLED_ShowNum(10.10,t,5,RED); t+=0.01; /* Thread sleep for 1s */ tx_thread_sleep(1000); }}/** * @brief Function implementing the ThreadOne thread. * @param thread_input: Not used * @retval None */ void ThreadOne_Entry(ULONG thread_input) {(void) thread_input; uint8_t count = 0; /* Infinite loop */ while(1) { BSP_LED_Toggle(LED_GREEN); /* Delay for 500ms (App_Delay is used to avoid context change). */ App_Delay(500); count ++; if (count == 10) { count = 0; if(tx_event_flags_set(&EventFlag, THREAD_ONE_EVT, TX_OR) ! = TX_SUCCESS) { Error_Handler(); }}}}/** * @brief Function implementing the ThreadTwo thread. * @param thread_input: Not used * @retval None */ void ThreadTwo_Entry(ULONG thread_input) {(void) thread_input; uint8_t count = 0; /* Infinite loop */ while (1) { BSP_LED_Toggle(LED_GREEN); /* Delay for 200ms (App_Delay is used to avoid context change). */ App_Delay(20); count ++; if (count == 25) { count = 0; if(tx_event_flags_set(&EventFlag, THREAD_TWO_EVT, TX_OR) ! = TX_SUCCESS) { Error_Handler(); }}}}/** * @brief Application Delay function. * @param Delay : number of ticks to wait * @retval None */ void App_Delay(uint32_t Delay) { UINT initial_time = tx_time_get(); while ((tx_time_get() - initial_time) < Delay); } /* USER CODE END 1 */ Copy the code