preface
uC/OS is a scalable, preemptive, real-time multitasking kernel that can run based on ROM. it is highly portable. It is especially suitable for microprocessors and controllers. It is suitable for many real-time operating systems (RTOS) with comparable performance of commercial operating systems.
The programs we wrote in the early stage are executed repeatedly in a while(1) loop. In this example, we use uC/OS operating system to realize specific functions and experience transplanting an operating system. It sounds very interesting. Let's start!
1, Get uC/OS-III source code
Download from the official website
Micrium download official website
The download steps on the official website are cumbersome. If you want to download on the official website, you can refer to
STM32F103C8T6 porting uC/OS-III based on HAL Library
Network disk download
Of course, I also uploaded the downloaded files to the online disk
After downloading, open the file with four folders, namely EvalBoards, UC CPU, UC lib and UCOS III, as shown in the figure below
(1) EvalBoards folder
The EvalBoards folder is based on the application layer implementation of the evaluation version. In our migration, some files can be moved to use.
(2) UC CPU folder
UC CPU folder this is a file closely related to CPU. Some files in it are very important and we need to use them.
(3) UC lib folder
UC lib folder, the official library provided by Micrium company, such as string operation, memory operation and other interfaces, can be used or not. Generally, it can be used to replace some functions in the standard library, which makes the application in embedded more convenient and safe.
(4) UCOS III folder
uCOS-III folder is the operating system kernel folder, which is the system core file. These files are all we need. We can copy them during migration.
2, Establish engineering documents
In this example, we transplant uC/OS-III operating system based on HAL library. The function is relatively simple, and a total of 3 task s are constructed.
task1: LED1 flashes at 1s frequency
task2: LED2 flashes at 3s frequency
task3: send the prompt message "hello uc/OS! Welcome to RTOS multitasking environment!" through the serial port every 2s.
The LED flashing and serial port sending / receiving procedures have been described in detail before. For details, please refer to
Lighting: Construction and use of STM32CubeMX environment
Serial port:
Serial communication of stm32
After configuration, the generated project files are as follows
3, Porting uC/OS-III files
(1) Create a new ucOSIII in the project folder and copy the UC CPU, UC lib and UCOS-III folders in the source code to the file
(2) Create a new ucos_config folder and ucos_bsp folder, copy the official file selected in the routine file to ucos_config
Then UCOS_ Create a new app.h in config, as shown in the following figure
(3) Copy the selected project file under Micrium\Software\EvalBoards\Micrium\uC-Eval-STM32F107\BSP to ucos_bsp clip
4, Add project components and paths
(1) Add project group
Open UC_ For osiii project, add six new groups as shown in the figure: bsp and uCOSIII_CPU, uCOSIII_LIB, uCOSIII_Ports, uCOSIII_Source, OS_cfg
(2) Add file to group
1. Put ucos_bsp.c and bsp.h in the bsp folder are added to the grouped bsp
2. In ucosiii_ Add the following files to the CPU group
Click add fillers... And select the selected file in the UC CPU folder under the newly created ucOSIII folder to add it
Then add the following files to the UC CPU – > arm-cortex-m3 – > RealView file directory
3. Add uCOSIII_LIB assembly
Click add fillers... And still select the selected file in the UC lib folder under the newly created ucOSIII folder to add it
Then add Lib in the UC lib \ ports \ arm-cortex-m3 \ RealView path_ mem_ a. ASM file
4. Add uCOSIII_Ports component
Find the selected file in uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView and add it
5. Add file to uCOSIII_Source group
Under UCOS III \ source file, add the selected 20 files to uCOSIII_Source grouping
5. Add files to OS_cfg group
In the newly created UCOS_ Locate the following file in the config folder and add it to the OS_cfg grouping
View the completed project file structure
(3) Include header file path
Select magic wand – > C / C + + option – > > include paths to add the path of the file used
The newly added file path is as follows
5, Modify engineering documents
(1) Startup file
First, modify the project startup file "startup_stm32f103xb.s"
Where PendSV_Handler and systick_ The handler is changed to
OS_CPU_PendSVHandler and OS_CPU_SysTickHandler, there are two places in total. Because uCOS officials have handled the corresponding interrupt function for us, we don't need to handle the system related interrupts ourselves. At the same time, we'd better use stm32f10x_ Pendsv in it. C file_ Handler and systick_ The handler function is commented out.
Revised as follows:
Modify startup_stm32f103xb.s file (lines 76 and 77)
Modify startup_stm32f103xb.s file (lines 174 to 179)
(2) app_cfg.h file
Before modification:
#define APP_CFG_SERIAL_EN DEF_ENABLED
After modification:
#define APP_CFG_SERIAL_EN DEF_DISABLED
(3) Modify bsp.c and bsp.h files
- bsp.c file
// bsp.c #include "includes.h" #define DWT_CR *(CPU_REG32 *)0xE0001000 #define DWT_CYCCNT *(CPU_REG32 *)0xE0001004 #define DEM_CR *(CPU_REG32 *)0xE000EDFC #define DBGMCU_CR *(CPU_REG32 *)0xE0042004 #define DEM_CR_TRCENA (1 << 24) #define DWT_CR_CYCCNTENA (1 << 0) CPU_INT32U BSP_CPU_ClkFreq (void) { return HAL_RCC_GetHCLKFreq(); } void BSP_Tick_Init(void) { CPU_INT32U cpu_clk_freq; CPU_INT32U cnts; cpu_clk_freq = BSP_CPU_ClkFreq(); #if(OS_VERSION>=3000u) cnts = cpu_clk_freq/(CPU_INT32U)OSCfg_TickRate_Hz; #else cnts = cpu_clk_freq/(CPU_INT32U)OS_TICKS_PER_SEC; #endif OS_CPU_SysTickInit(cnts); } void BSP_Init(void) { BSP_Tick_Init(); MX_GPIO_Init(); } #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) void CPU_TS_TmrInit (void) { CPU_INT32U cpu_clk_freq_hz; DEM_CR |= (CPU_INT32U)DEM_CR_TRCENA; /* Enable Cortex-M3's DWT CYCCNT reg. */ DWT_CYCCNT = (CPU_INT32U)0u; DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA; cpu_clk_freq_hz = BSP_CPU_ClkFreq(); CPU_TS_TmrFreqSet(cpu_clk_freq_hz); } #endif #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) CPU_TS_TMR CPU_TS_TmrRd (void) { return ((CPU_TS_TMR)DWT_CYCCNT); } #endif #if (CPU_CFG_TS_32_EN == DEF_ENABLED) CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts) { CPU_INT64U ts_us; CPU_INT64U fclk_freq; fclk_freq = BSP_CPU_ClkFreq(); ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC); return (ts_us); } #endif #if (CPU_CFG_TS_64_EN == DEF_ENABLED) CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts) { CPU_INT64U ts_us; CPU_INT64U fclk_freq; fclk_freq = BSP_CPU_ClkFreq(); ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC); return (ts_us); } #endif
- bsp.h
// bsp.h #ifndef __BSP_H__ #define __BSP_H__ #include "stm32f1xx_hal.h" void BSP_Init(void); #endif
(4) Modify the includes.h header file
First Amendment:
#include "bsp.h" #include "gpio.h" #include "usart.h" #include "app_cfg.h"
Second amendment:
#include "stm32f1xx_hal.h"
(5) main.c
/* Includes ------------------------------------------------------------------*/ #include "main.h" #include "gpio.h" #include "usart.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <includes.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* Task priority */ #define START_TASK_PRIO 3 #define LED1_TASK_PRIO 4 #define MSG_TASK_PRIO 5 #define LED2_TASK_PRIO 6 /* Task stack size */ #define START_STK_SIZE 96 #define LED1_STK_SIZE 64 #define MSG_STK_SIZE 64 #define LED2_STK_SIZE 64 /* Task stack */ CPU_STK START_TASK_STK[START_STK_SIZE]; CPU_STK LED1_TASK_STK[LED1_STK_SIZE]; CPU_STK MSG_TASK_STK[MSG_STK_SIZE]; CPU_STK LED2_TASK_STK[LED2_STK_SIZE]; /* Task control block */ OS_TCB StartTaskTCB; OS_TCB Led1TaskTCB; OS_TCB MsgTaskTCB; OS_TCB Led2TaskTCB; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* Task function definition */ void start_task(void *p_arg); static void AppTaskCreate(void); static void AppObjCreate(void); static void led1_pb0(void *p_arg); static void send_msg(void *p_arg); static void led2_pb1(void *p_arg); /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { OS_ERR err; OSInit(&err); HAL_Init(); SystemClock_Config(); //MX_GPIO_Init(); This will also be initialized in BSP initialization MX_USART1_UART_Init(); /* Create task */ OSTaskCreate((OS_TCB *)&StartTaskTCB, /* Create the start task */ (CPU_CHAR *)"start task", (OS_TASK_PTR ) start_task, (void *) 0, (OS_PRIO ) START_TASK_PRIO, (CPU_STK *)&START_TASK_STK[0], (CPU_STK_SIZE) START_STK_SIZE/10, (CPU_STK_SIZE) START_STK_SIZE, (OS_MSG_QTY ) 0, (OS_TICK ) 0, (void *) 0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); /* Start the multitasking system and give control to uC/OS-III */ OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */ } void start_task(void *p_arg) { OS_ERR err; CPU_SR_ALLOC(); p_arg = p_arg; /* YangJie add 2021.05.20*/ BSP_Init(); /* Initialize BSP functions */ //CPU_Init(); //Mem_Init(); /* Initialize Memory Management Module */ #if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); //Statistical tasks #endif #ifdef CPU_CFG_INT_DIS_MEAS_EN // If enabled, measure the interrupt off time CPU_IntDisMeasMaxCurReset(); #endif #if OS_CFG_SCHED_ROUND_ROBIN_EN // When using time slice rotation //Enable the time slice rotation scheduling function. The time slice length is 1 system clock beat, i.e. 1*5=5ms OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); #endif OS_CRITICAL_ENTER(); //Enter critical zone /* Create LED1 task */ OSTaskCreate((OS_TCB * )&Led1TaskTCB, (CPU_CHAR * )"led1_pb0", (OS_TASK_PTR )led1_pb0, (void * )0, (OS_PRIO )LED1_TASK_PRIO, (CPU_STK * )&LED1_TASK_STK[0], (CPU_STK_SIZE)LED1_STK_SIZE/10, (CPU_STK_SIZE)LED1_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); /* Create LED2 task */ OSTaskCreate((OS_TCB * )&Led2TaskTCB, (CPU_CHAR * )"led2_pb1", (OS_TASK_PTR )led2_pb1, (void * )0, (OS_PRIO )LED2_TASK_PRIO, (CPU_STK * )&LED2_TASK_STK[0], (CPU_STK_SIZE)LED2_STK_SIZE/10, (CPU_STK_SIZE)LED2_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); /* Create MSG task */ OSTaskCreate((OS_TCB * )&MsgTaskTCB, (CPU_CHAR * )"send_msg", (OS_TASK_PTR )send_msg, (void * )0, (OS_PRIO )MSG_TASK_PRIO, (CPU_STK * )&MSG_TASK_STK[0], (CPU_STK_SIZE)MSG_STK_SIZE/10, (CPU_STK_SIZE)MSG_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err); //Suspend start task OS_CRITICAL_EXIT(); //Enter critical zone } /** * Function function: start the task function body. * Input parameter: p_arg is the formal parameter passed when the task was created * Return value: None * Description: None */ static void led1_pb0 (void *p_arg) { OS_ERR err; (void)p_arg; BSP_Init(); /* Initialize BSP functions */ CPU_Init(); Mem_Init(); /* Initialize Memory Management Module */ #if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */ #endif CPU_IntDisMeasMaxCurReset(); AppTaskCreate(); /* Create Application Tasks */ AppObjCreate(); /* Create Application Objects */ while (DEF_TRUE) { HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); OSTimeDlyHMSM(0, 0, 1, 500,OS_OPT_TIME_HMSM_STRICT,&err); HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); OSTimeDlyHMSM(0, 0, 1, 500,OS_OPT_TIME_HMSM_STRICT,&err); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } static void led2_pb1 (void *p_arg) { OS_ERR err; (void)p_arg; BSP_Init(); /* Initialize BSP functions */ CPU_Init(); Mem_Init(); /* Initialize Memory Management Module */ #if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */ #endif CPU_IntDisMeasMaxCurReset(); AppTaskCreate(); /* Create Application Tasks */ AppObjCreate(); /* Create Application Objects */ while (DEF_TRUE) { HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); OSTimeDlyHMSM(0, 0, 0, 500,OS_OPT_TIME_HMSM_STRICT,&err); HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET); OSTimeDlyHMSM(0, 0, 0, 500,OS_OPT_TIME_HMSM_STRICT,&err); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } static void send_msg (void *p_arg) { OS_ERR err; (void)p_arg; BSP_Init(); /* Initialize BSP functions */ CPU_Init(); Mem_Init(); /* Initialize Memory Management Module */ #if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */ #endif CPU_IntDisMeasMaxCurReset(); AppTaskCreate(); /* Create Application Tasks */ AppObjCreate(); /* Create Application Objects */ while (DEF_TRUE) { printf("hello uc/OS! Welcome to RTOS Multitasking environment!\r\n"); OSTimeDlyHMSM(0, 0, 2, 0,OS_OPT_TIME_HMSM_STRICT,&err); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /* USER CODE BEGIN 4 */ /** * Function function: create application task * Input parameter: p_arg is the formal parameter passed when the task was created * Return value: None * Description: None */ static void AppTaskCreate (void) { } /** * Function function: uCOSIII kernel object creation * Input parameters: None * Return value: None * Description: None */ static void AppObjCreate (void) { } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
This is because of memory overflow. The memory of STM32C8T6 is only 20KB, while in lib_ The macro in CFG. H defines that the heap size is 27KB, resulting in insufficient memory space
In Lib_ Find the macro definition in the CFG. H file and modify it as follows
Before modification:
#define LIB_MEM_CFG_HEAP_SIZE 27u * 1024u
After modification:
#define LIB_MEM_CFG_HEAP_SIZE 5u * 1024u
6, Example demonstration
- LED1 and 2 Flash
- Serial port sending data
summary
This is a transplant based on the ucOS operating system. Xiaobian doesn't know the ucOS system, but just tries to transplant it correctly. The code analysis and the whole code running process are skipped.
If there is anything wrong with the above, please advise!!!
STM32F103C8T6 porting uC/OS-III based on HAL Library
Transplantation of uCOS-III in STM32
stm32f103c8t6 porting ucos - Ⅲ memory overflow bug
[wildfire] UCOS III Kernel Implementation and application development practice guide