Handcrafted OS Transformation Benchmark Code – Simple Scheduling Algorithm (Part 2)

This article will rewrite the handcrafted OS – a function running the minimum core code of FREERTOS, as shown in the figure below.
Handcrafted OS Transformation Benchmark Code - Simple Scheduling Algorithm (Part 2)
Mainly: rewriting vTaskSwitchContext + background tick interrupt automatically switches tasks.
In fact, the functionality has been completed in two articles, but it seems clumsy to represent using UART.
This article aims to use the built-in logic analyzer of KEIL for representation, which is very refreshing!
In task1, write PB12 high.
In task2, write PB12 low.
The effect presented is shown in the figure below.
Handcrafted OS Transformation Benchmark Code - Simple Scheduling Algorithm (Part 2)
Handcrafted OS Transformation Benchmark Code - Simple Scheduling Algorithm (Part 2)

Operation Video

1>Configure the Emulator
2>Open the Logic Analyzer: In the debug interface, click the “View” menu, select “Analysis Windows”, and then select “Logic Analyzer” to open the logic analyzer window.

3>Set up the Logic Analyzer: In the logic analyzer window, click the “Setup” button. In the pop-up dialog, enter the port you want to observe, for example, PORTA.0 (indicating the 0th pin of GPIOA) and ensure “Display Type” is set to “Bit”. If needed, set the “Shift right” value to specify the specific pin number.

Benchmark Code

Since PB12 is the LED of the Taobao STM32F103C8T6, it has been initialized in MX, so we write directly.
void SystemClock_Config(void);/* USER CODE BEGIN PFP */
/* USER CODE BEGIN PFP */#include <stdio.h>#include <string.h>
void SysTick_Disable() {    // Disable SysTick timer    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;}
void SysTick_Enable() {    // Enable SysTick timer    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;}

#if 0//IARint putchar(int ch){    HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1 , 0xffff);    while (huart2.gState != HAL_UART_STATE_READY);//end of transmission    return ch;}
#elseint fputc( int ch, FILE *f ) {    HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1 , 0xffff);    while (huart2.gState != HAL_UART_STATE_READY);//end of transmission    return ch;}
#endifint TASK1DATA = 9;int TASK2DATA = 6;void TaskSwitch(void);typedef void (*TaskFunction_t)( void * );static void taskfun1(void *A){     int* data=(int*)A;   while(1){      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);   };}static void taskfun2(void *A){     int* data=(int*)A;   while(1){    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);   };}//TCBtypedef struct tskTaskControlBlock{  uint32_t  *pxTopOfStack;  /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */  uint32_t  *pxStack;       /*< Points to the start of the stack. */} tskTCB;typedef tskTCB TCB_t;TCB_t TCB[2]={0};//Point to the current working TCBTCB_t * volatile pxCurrentTCB = NULL;//Array#define ARRLEN 512uint32_t arrForStack[ARRLEN]={0};uint32_t arrForStack2[ARRLEN]={0};//Initialize a stackstatic void prvTaskExitError( void ){  for( ;; );}/*******************************************************************************/uint32_t *pxPortInitialiseStack( uint32_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ){  /* Simulate the stack frame as it would be created by a context switch  interrupt. */  pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */  *pxTopOfStack = 0x01000000;  /* xPSR *///https://blog.csdn.net/k666499436/article/details/127072835 α??xPSP?????  pxTopOfStack--;  *pxTopOfStack = ( ( uint32_t ) pxCode ) & 0xfffffffeUL;  /* PC *///α??PC????? https://blog.csdn.net/k666499436/article/details/127072835  pxTopOfStack--;  *pxTopOfStack = ( uint32_t ) prvTaskExitError;  /* LR */  pxTopOfStack -= 5;  /* R12, R3, R2 and R1. */  *pxTopOfStack = ( uint32_t ) pvParameters;  /* R0 */  pxTopOfStack -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */  return pxTopOfStack;}void prvInitialiseNewTask(const uint32_t ulStackDepth,TCB_t *pxNewTCB){  uint32_t *pxTopOfStack;  //portSTACK_GROWTH < 0  pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );  printf("%p\r\n",pxTopOfStack);//[This is the end of the array, the address of the last member is 0X20000084, which is arrForStack[23]]  pxTopOfStack = ( uint32_t * ) ( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );   printf("%p\r\n",pxTopOfStack);//[After the above, ensure this address ends in 000 which is 8, so the address is 0X20000080, which is arrForStack[22]]  pxNewTCB->pxTopOfStack = pxTopOfStack;}void xTaskCreateStatic(void){    uint8_t index=0;  TCB[index].pxStack=arrForStack;  prvInitialiseNewTask(ARRLEN,&TCB[index]);  TCB[index].pxTopOfStack=pxPortInitialiseStack(TCB[index].pxTopOfStack,taskfun1,&TASK1DATA);  pxCurrentTCB = &TCB[index];  index=1;  TCB[index].pxStack=arrForStack2;  prvInitialiseNewTask(ARRLEN,&TCB[index]);  TCB[index].pxTopOfStack=pxPortInitialiseStack(TCB[index].pxTopOfStack,taskfun2,&TASK2DATA);}/*******************************************************************************/__asm void SVC_Handler( void ){//it.c Please remove the same name function, after execution jump to task 1  extern pxCurrentTCB;  PRESERVE8  ldr  r3, =pxCurrentTCB  /* Restore the context. */  ldr r1, [r3]      /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */  ldr r0, [r1]      /* The first item in pxCurrentTCB is the task top of stack. */  ldmia r0!, {r4-r11}    /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */  msr psp, r0        /* Restore the task stack pointer. */  isb  mov r0, #0  msr  basepri, r0  orr r14, #0xd  bx r14}
__asm void prvStartFirstTask( void ){//Manually trigger SVC interrupt to automatically jump to function SVC_Handler  PRESERVE8
  /* Use the NVIC offset register to locate the stack. */  ldr r0, =0xE000ED08  ldr r0, [r0]  ldr r0, [r0]
  /* Set the msp back to the start of the stack. */  msr msp, r0  /* Globally enable interrupts. */  cpsie i  cpsie f  dsb  isb  /* Call SVC to start the first task. */  svc 0  nop  nop}
void xPortStartScheduler(void){    HAL_NVIC_SetPriority(SysTick_IRQn, 0X0F, 0X00);    HAL_NVIC_SetPriority(PendSV_IRQn,  0X0F, 0X00);    SysTick_Enable();       prvStartFirstTask();}

void setupMyOs(void){  xTaskCreateStatic();//Create two task stacks  xPortStartScheduler();//On power-up, the original plan is to go to main and then to the while loop, now intercept before the while loop to go to the agreed task stack 1
}/*********************************************************************/

/*******************************Timing**********************************/
//Enable mask interrupts#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5#define configMAX_SYSCALL_INTERRUPT_PRIORITY   ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4 )

//Manually trigger PendSV interrupt to automatically jump to function PendSV_Handlervoid xPortSysTickHandler( void ){    __set_BASEPRI(0X50);//Enable mask interrupts    ( * ( ( volatile uint32_t * ) 0xE000ED04 ) ) =  ( 1UL << 28UL );    __set_BASEPRI(0X00);//Disable mask interrupts}


void vTaskSwitchContext( void );__asm void PendSV_Handler( void ){//it.c Please remove the same name function  extern pxCurrentTCB;  extern vTaskSwitchContext;
  PRESERVE8
  mrs r0, psp  isb
  ldr  r3, =pxCurrentTCB    /* Get the location of the current TCB. */  ldr  r2, [r3]
  stmdb r0!, {r4-r11}      /* Save the remaining registers. */  str r0, [r2]        /* Save the new top of stack into the first member of the TCB. */
  stmdb sp!, {r3, r14}  mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY  msr basepri, r0  dsb  isb  bl vTaskSwitchContext  mov r0, #0  msr basepri, r0  ldmia sp!, {r3, r14}
  ldr r1, [r3]  ldr r0, [r1]        /* The first item in pxCurrentTCB is the task top of stack. */  ldmia r0!, {r4-r11}      /* Pop the registers and the critical nesting count. */  msr psp, r0  isb  bx r14  nop}


void TaskSwitch(void){    xPortSysTickHandler();}
uint8_t volatile index = 0;void vTaskSwitchContext( void ){    //static uint8_t index=0;    pxCurrentTCB = &TCB[index];    index =     (index+1)%2;//There are a total of 2 tasks, so it's 0 1 0 1 loop}

Other Code

As in the previous article, call in it.c and main.
void SysTick_Handler(void){  /* USER CODE BEGIN SysTick_IRQn 0 */extern void TaskSwitch(void);  /* USER CODE END SysTick_IRQn 0 */  HAL_IncTick();  /* USER CODE BEGIN SysTick_IRQn 1 */TaskSwitch();  /* USER CODE END SysTick_IRQn 1 */}
Call in main.c
SysTick_Disable();setupMyOs();//SysTick_Enable();//Note: The statements after setupMyOs cannot be executed! So this statement needs to be placed in front.

Leave a Comment