ucOS file migration based on C8T6 core board

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

Interrupt mode 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

uCOSIII transplantation

Transplantation of uCOS-III in STM32

stm32f103c8t6 porting ucos - Ⅲ memory overflow bug

[wildfire] UCOS III Kernel Implementation and application development practice guide

Tags: C Single-Chip Microcomputer stm32

Posted on Sat, 04 Dec 2021 17:46:57 -0500 by guybrush