Series articles
- UCOSii startup process and platform related document analysis
- Priority algorithm and kernel source code analysis
- task management
- time management
- Event control block
- memory management
- Inter task communication and synchronization
preface
In fact, more than a year ago, I had the idea to write the source code analysis of UCOSii, but the level was limited at that time. Even if I wrote it, I'm afraid it was only an application of API on the surface. This time, I want to write some deeper understanding of UCOS. In fact, in my opinion, all RTOS have a very similar framework structure, but the algorithms filled in are different. Among them, the most core is a priority algorithm and scheduling algorithm.
(1) Description of UCOSII variables
(2) UCOSII startup process analysis
OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//Create start task OSStart();
- 1
- 2
- 3
Let's first look at the startup process of UCOS. The above three functions are called. The middle function is to create the start task. We won't take a closer look. We focus on the first function and the last function.
We first locate the function content of OSInit
(1) OSInit() function analysis
************************************************************************************************ * Initial value(INITIALIZATION) * * describe: initialization uC/OS-II. A call to this function must be made before calling OSStart()Before the function. * OSStart()When the function actually starts running multitasking * opinion: nothing * return: nothing * ************************************************************************************************
71
72 void OSInit (void) / / initialize the UCOS-II function
73 {
74 INT16U i; // Define a 16 bit variable I
75 INT8U prdytbl; // Define a ready state top-level task list pointer
76 OS_TCB ptcb1; // Define task control block priority table pointer 1
77 OS_TCB ptcb2; // Define task control block priority table pointer 2
78 #if (os_event_en > 0) & & (os_max_events > 1) / / if there is a message event, and the maximum message event value is > 1
79 OS_EVENT pevent1; // Define event pointer 1
80 OS_EVENT pevent2; // Define event pointer 2
81 #endif
82
83
84 #if OS_ Version > = 204 / / if the version is greater than version 2.04
85 OSInitHookBegin(); // Call the initialization hook function to add user code
86 #endif
87
88 #if OS_ TIME_ GET_ SET_ En > 0 / / allow generating OSTimeGet() and OSTimeSet() function codes
89 OSTime = 0L; // Clear 32 system clock
90 #endif
91 OSIntNesting = 0; // Clear interrupt nested counter
92 OSLockNesting = 0; // Clear lock nested counters
93 OSTaskCtr = 0; // Clear task counters
94 OSRunning = FALSE; // The task is not running
95 OSIdleCtr = 0L; // Clear counters for 32-bit idle tasks
96 / / it is allowed to generate OSTaskCreate() function and OSTaskCreateExt() function
97 #if (OS_TASK_STAT_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
98 OSIdleCtrRun = 0L; // The count value of the idle task counter is 0 per second
99 OSIdleCtrMax = 0L; // The maximum idle task count per second is 0
100 OSStatRdy = FALSE; // The flag of whether the statistical task is ready is empty
101 #endif
102 OSCtxSwCtr = 0; // Number of context switches (statistical task counter) cleared 0
103 OSRdyGrp = 0x00; // Clear the task ready list corresponding to the OSRdyTbl[i] group
104 prdytbl = &OSRdyTbl[0];
105 for (i = 0; i < OS_RDY_TBL_SIZE; i++) {
106 prdytbl++ = 0x00; // All ready list pointer contents are cleared to 0
107 }
108
109 OSPrioCur = 0; // Priority of running tasks
110 OSPrioHighRdy = 0; // The priority of the ready task with the highest priority
111 OSTCBHighRdy = (OS_TCB )0; // The pointer to the highest priority ready task control block is 0
112 OSTCBCur = (OS_TCB )0; // Pointer to running task control block 0
113 OSTCBList = (OS_TCB )0; // Pointer list control block of link 0
114 / / clear all priority control block priority lists e
115 for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) {
116 OSTCBPrioTbl[i] = (OS_TCB )0;
117 }
118 ptcb1 = &OSTCBTbl[0]; // Find the corresponding address of the task control block list (0)
119 ptcb2 = &OSTCBTbl[1]; // Find the corresponding address of the task control block list (1)
120 / / release all task control block lists
121 for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {
122 ptcb1->OSTCBNext = ptcb2;
123 ptcb1++;
124 ptcb2++;
125 }
126 ptcb1->OSTCBNext = (OS_TCB )0; // The back link of the last task block bidirectional link table is 0
127 OSTCBFreeList = &OSTCBTbl[0]; // The empty task control block address is the first address of the current task control block list
128
129 #if (os_event_en > 0) & & (os_max_events > 0) / / if there are message events, and the maximum number of message events > 0
130 #if OS_MAX_EVENTS == 1 / / if the maximum number of message events > 1
131 / / you can only have a single message event
132 OSEventFreeList = &OSEventTbl[0]; // Spare event management list = first address of task waiting table
133 OSEventFreeList->OSEventType = OS_ EVENT_ TYPE_ UNUSED; // Event type = idle
134 OSEventFreeList->OSEventPtr = (OS_EVENT )0; // The pointer to the message or message queue is null
135 #else
136 pevent1 = &OSEventTbl[0]; // Find the first address corresponding to the task waiting table (0)
137 pevent2 = &OSEventTbl[1]; // Find the corresponding address of the task waiting table (1)
138 / / release all task waiting tables and set the event type = idle
139 for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {
140 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
141 pevent1->OSEventPtr = pevent2;
142 pevent1++;
143 pevent2++;
144 }
145 pevent1->OSEventType = OS_ EVENT_ TYPE_ UNUSED; // Event type of the first address = idle
146 pevent1->OSEventPtr = (OS_EVENT )0; // The pointer to the message or message queue of the first address is null
147 OSEventFreeList = &OSEventTbl[0]; // Spare event management list = first address of task waiting table
148 #endif
149 #endif
150 / / conditional compilation: UCOS version > = 251_ FLAG_ EN allows the generation of event flag program code and the maximum event flag > 0
151 #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
3 H:\SOURCE Chinese source code \ OS_CORE.C
152 OS_FlagInit(); // Initialize event flag structure
153 #endif
154 / / conditional compilation: OS_Q_EN allows (1) to generate message queue related codes, and the maximum number of column control blocks in the application is > 0
155 #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
156 OS_QInit(); // Initialize event queue structure
157 #endif
158 / / conditional compilation: if two conditions are met, the following code is generated
159 //OS_MEM_EN allows (1) or prohibits (0) the generation of memory related codes
160 //OS_MAX_MEM_PART maximum number of memory blocks
161 #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
162 OS_MemInit(); // Initialize memory block structure
163 #endif
164
165 / ------------------ generate an IDLE task (CREATION OF 'IDLE' TASK) ------------------/
166 #if OS_ TASK_ CREATE_ EXT_ En > 0 / / allow generation of OSTaskCreateExt() function
167 #if OS_STK_GROWTH == 1 / / stack growth direction down
168 / / create extension task [
169 (void)OSTaskCreateExt(OS_TaskIdle, / / idle task
170 (void) 0, / / no (pass parameter pointer)
171 & ostaskidlestk [os_task_idle_stk_size - 1], / / allocate the top pointer of the task stack
172 OS_IDLE_PRIO, / / assign task priority
173 OS_TASK_IDLE_ID, / / (future) priority ID (same as priority)
174 & ostask idlestk [0], / / allocate the pointer at the bottom of the task stack
175 OS_TASK_IDLE_STK_SIZE, / / specifies the capacity of the stack (for inspection)
176 (void) 0, / / no (pointer to the data field attached by the user)
177
178 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
179 #else / / create an extension task [... / / the stack grows upward
180 (void)OSTaskCreateExt(OS_TaskIdle, / / idle task
181 (void) 0, / / no (pass parameter pointer)
182 & ostask idlestk [0], / / allocate the pointer at the bottom of the task stack
183 OS_IDLE_PRIO, / / assign task priority
184 OS_TASK_IDLE_ID, / / (future) priority ID (same as priority)
185 / / allocate the top pointer of the task stack
186 &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
187 OS_TASK_IDLE_STK_SIZE, / / specifies the capacity of the stack (for inspection)
188 (void) 0, / / no (pointer to the data field attached by the user)
189 / / no (pointer to the data field attached by the user)
190 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
191 #endif
192 #else / / otherwise, only OSTaskCreate() function can be generated
193 #if OS_STK_GROWTH == 1 / / stack growth direction down
194 (void)OSTaskCreate(OS_TaskIdle, / / create task [idle task
195 (void) 0, / / no (pass parameter pointer)
196 / / allocate the top pointer of the task stack
197 &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
198 OS_IDLE_PRIO); // Assign task priority
199 #else / / otherwise, the stack growth direction is upward
200 (void)OSTaskCreate(OS_TaskIdle, / / create task [idle task
201 (void) 0, / / no (pass parameter pointer)
202 & ostask idlestk [0], / / allocate the pointer at the bottom of the task stack
203 OS_IDLE_PRIO); // Assign task priority
204 #endif
205 #endif
206
207 / ------------------ generate a statistics task (CREATION OF 'statistical' TASK) -------------------/
208 #if OS_TASK_STAT_EN > 0
209 #if OS_ TASK_ CREATE_ EXT_ En > 0 / / allow generation of OSTaskCreateExt() function
210 #if OS_STK_GROWTH == 1 / / stack growth direction down
211 / / create an extension task [
212 (void) ostask createext (os_taskstat, / / generate a statistics task
213 (void) 0, / / no (pass parameter pointer)
214 & ostaskstatstk [os_task_stat_stk_size - 1], / / allocate the top pointer of the task stack
215 OS_STAT_PRIO, / / assign task priority
216 OS_TASK_STAT_ID, / / (future) priority ID (same as priority)
217 & ostaskstatstk [0], / / allocate the pointer at the bottom of the task stack
218 OS_TASK_STAT_STK_SIZE, / / specifies the capacity of the stack (for inspection)
219 (void) 0, / / no (pointer to the data field attached by the user)
220 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
221 #else / / create an extension task [... / / the stack grows upward
222 (void) ostask createext (os_taskstat, / / generate a statistics task
223 (void) 0, / / no (pass parameter pointer)
224 & ostaskstatstk [0], / / allocate the pointer at the bottom of the task stack
225 OS_STAT_PRIO, / / assign task priority
226 OS_TASK_STAT_ID, / / (future) priority ID (same as priority)
227 & ostaskstatstk [os_task_stat_stk_size - 1], / / allocate the top pointer of the task stack
4 H:\SOURCE Chinese source code \ OS_CORE.C
228 OS_TASK_STAT_STK_SIZE, / / specifies the capacity of the stack (for inspection)
229 (void) 0, / / no (pointer to the data field attached by the user)
230 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
231 #endif
232 #else / / otherwise, only OSTaskCreate() function can be generated
233 #if OS_STK_GROWTH == 1 / / stack growth direction down
234 (void)OSTaskCreate(OS_TaskStat, / / generate a statistics task
235 (void) 0, / / no (pass parameter pointer)
236 & ostaskstatstk [os_task_stat_stk_size - 1], / / allocate the top pointer of the task stack
237 OS_STAT_PRIO); // Assign task priority
238 #else / / otherwise, the stack growth direction is upward
239 (void)OSTaskCreate(OS_TaskStat, / / generate a statistics task
240 (void *)0, / / no (pass parameter pointer)
241 & ostaskstatstk [0], / / allocate the pointer at the bottom of the task stack
242 OS_STAT_PRIO); // Assign task priority
243 #endif
244 #endif
245 #endif
246
247 #if OS_ Version > = 204 / / judge whether the version is greater than or equal to version 2.41
248 OSInitHookEnd(); // Call osinithookend() hook program
249 #endif
250 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
OSInitHookBegin(); /* Call port specific initialization code */ OSInitHookEnd(); /* Call port specific init. code */
- 1
- 2
Analysis of the source code shows that the main function of OSInit() is to initialize various variables. For the initial value of the initial value, the preprocessed modules are initialized respectively.
It should be noted that there are two hook functions: in my opinion, the so-called hook function is an interface provided by a library so that users can do something in it.
********************************************************************************************************* * OS INITIALIZATION HOOK * (BEGINNING) *Initialization starts with a hook function * Description: This function is called by OSInit() at the beginning of OSInit(). * * Arguments : none * * Note(s) : 1) Interrupts should be disabled during this call. ********************************************************************************************************* */ #if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203 void OSInitHookBegin (void) { #if OS_TMR_EN > 0 OSTmrCtr = 0; #endif } #endif
/*
-
OS INITIALIZATION HOOK
-
(END)
*Hook function at the end of INIT
- Description: This function is called by OSInit() at the end of OSInit().
- Arguments : none
- Note(s) : 1) Interrupts should be disabled during this call.
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookEnd (void)
{
}
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
Usually in OS_ cpu. The C file completes this function.
(2)OS_Start() function analysis
423 /*$PAGE*/? 424 /* 425 ********************************************************************************************** 426 * Start multiple tasksstart multitasking 427 * 428 * Description: when OSStart() is called, OSStart() finds out the task control of the task with the highest priority established by the user from the task readiness table 429 * Block. Then, OSStart() calls the high priority ready task startup function OSStartHighRdy(), (see assembly language file) 430 * OS_CPU_A.ASM),This file is related to the selected microprocessor. In essence, the function OSStartHighRdy() is to add tasks to the stack 431 * The saved value bounces back to the CPU register, and then an interrupt return instruction is executed, which enforces the task code. 432 * High priority ready task startup function OSStartHighRdy(). 433 * 434 * Parameter: None 435 * 436 * Return: None 437 * 438 * Note: OSStartHighRdy() must: 439 * a) OSRunning If true, indicate that multitasking has started 440 * b) Before starting uC/OS-II, at least one application task must be established 441 * c) OSStartHighRdy()Will never return to OSStart() 442 ********************************************************************************************** 443 */ 444 445 void OSStart (void) //Start multiple tasks 446 { 447 INT8U y; 448 INT8U x; 449 450 451 if (OSRunning == FALSE) { //OSRunning is set to true, indicating that multitasking has started 452 y = OSUnMapTbl[OSRdyGrp]; //Find the highest priority task number 453 x = OSUnMapTbl[OSRdyTbl[y]]; 454 OSPrioHighRdy = (INT8U)((y << 3) + x); //Find the highest level task control block in ready state 455 OSPrioCur = OSPrioHighRdy; 456 //OSPrioCur and OSPrioHighRdy store the priority of user application tasks 457 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; 458 OSTCBCur = OSTCBHighRdy; 459 OSStartHighRdy(); //Call the high priority ready task startup function 460 } 461 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
The OSStart() function is for task scheduling, because we will jump out of main soon The function of C will not jump in again, so we need to jump out the internal pointer.
This function is almost the beginning of task scheduling. From here, UCOS is really started.
The highest priority of the current task will be detected first. This process is a little troublesome. I'll talk about it separately in the next article.
After obtaining the highest priority TCB block, start the OSStartHighRdy() function. This function needs to be implemented separately according to the platform. Here, take the cotex-m3 platform as an example.
OSStartHighRdy LDR R4, =NVIC_SYSPRI2 ; set up PendSV Priority of LDR R5, =NVIC_PENDSV_PRI STR R5, [R4]MOV R4<span class="token punctuation">,</span> #<span class="token number">0</span> <span class="token punctuation">;</span> set the PSP to <span class="token number">0</span> <span class="token keyword">for</span> initial context <span class="token keyword">switch</span> call MSR PSP<span class="token punctuation">,</span> R4 <span class="token punctuation">;</span> take PSP Move the pointer to the start of the idle task <span class="token punctuation">;</span> PENDSV Go back to execution PendSV_Handler_Nosave LDR R4<span class="token punctuation">,</span> <span class="token operator">=</span>OSRunning <span class="token punctuation">;</span> OSRunning <span class="token operator">=</span> TRUE MOV R5<span class="token punctuation">,</span> #<span class="token number">1</span> <span class="token punctuation">;</ Span > tell the system to start running STRB R5<span class="token punctuation">,</span> <span class="token punctuation">[</span>R4<span class="token punctuation">]</span> <span class="token punctuation">;</span> LDR R4<span class="token punctuation">,</span> <span class="token operator">=</span>NVIC_INT_CTRL <span class="token punctuation">;</span>trigger the PendSV exception <span class="token punctuation">(</span>causes context <span class="token keyword">switch</span><span class="token punctuation">)</span> LDR R5<span class="token punctuation">,</span> <span class="token operator">=</span>NVIC_PENDSVSET <span class="token punctuation">;</span>trigger PENDSV interrupt STR R5<span class="token punctuation">,</span> <span class="token punctuation">[</span>R4<span class="token punctuation">]</span> CPSIE I <span class="token punctuation">;</span>enable interrupts at processor level
OSStartHang
B OSStartHang ;should never get here
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
(3) Bottom migration file analysis
os_cpu_a.asm
;/*********************** (C) COPYRIGHT 2010 Libraworks ************************* ;* File Name : os_cpu_a.asm ;* Author : Librae ;* Version : V1.0 ;* Date : 06/10/2010 ;* Description : About the underlying code of STM32 ;*******************************************************************************/IMPORT OSRunning <span class="token punctuation">;</span> Introducing external variables IMPORT OSPrioCur IMPORT OSPrioHighRdy IMPORT OSTCBCur IMPORT OSTCBHighRdy IMPORT OSIntNesting IMPORT OSIntExit IMPORT OSTaskSwHook EXPORT OSStartHighRdy EXPORT OSCtxSw EXPORT OSIntCtxSw EXPORT OS_CPU_SR_Save <span class="token punctuation">;</span> Functions provided externally EXPORT OS_CPU_SR_Restore EXPORT PendSV_Handler
NVIC_INT_CTRL EQU 0xE000ED04 ; Address of interrupt control register
NVIC_SYSPRI2 EQU 0xE000ED20 ; System priority register
NVIC_ PENDSV_ PRI EQU 0xFFFF0000 ; Priority of pendsv (lowest)
;
NVIC_PENDSVSET EQU 0x10000000 ; The value that triggers the PendSV interrupt
PRESERVE8 AREA <span class="token operator">|</span><span class="token punctuation">.</span>text<span class="token operator">|</span><span class="token punctuation">,</span> CODE<span class="token punctuation">,</span> READONLY THUMB
;
; CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
; into the CPU's status register.
;
; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s) : 1) These functions are used in general like this:
;
; void Task (void p_arg)
; {
; #if OS_CRITICAL_METHOD == 3 / Allocate storage for CPU status register /
; OS_CPU_SR cpu_sr;
; #endif
;
; :
; :
; OS_ENTER_CRITICAL(); / cpu_sr = OS_CPU_SaveSR(); /
; :
; :
; OS_EXIT_CRITICAL(); / OS_CPU_RestoreSR(cpu_sr); /
; :
; :
; }
;*
OS_CPU_SR_Save
MRS R0, PRIMASK ; Load primask register address
CPSID I ;PRIMASK=1, close all interrupts (except nmi and hardfault)
BX LR ; return
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;
BX LR ;
;
; START MULTITASKING start task
; void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
; the first task to start. The function triggers a PendSV exception (essentially, a context switch) that causes the first task to start
;
; 2) OSStartHighRdy() MUST: key process
; a) Setup PendSV exception priority to lowest;
; Set the PendSV exception priority to the lowest
; b) Set initial PSP to 0, to tell context switcher this is first run;
; Set the initial process stack to position 0 to tell the context / task switcher that this function will execute first
; c) Set OSRunning to TRUE;
; Set the OSRunning flag to TRUE
; d) Trigger PendSV exception;
; Switching PendSV exception
; e) Enable interrupts (tasks will run with interrupts enabled).
; Enable interrupts (tasks will run by enabling interrupts)
; It completes the call through osspart()
;
OSStartHighRdy
LDR R4, =NVIC_SYSPRI2 ; set the PendSV exception priority
LDR R5, =NVIC_PENDSV_PRI
STR R5, [R4]
MOV R4<span class="token punctuation">,</span> #<span class="token number">0</span> <span class="token punctuation">;</span> set the PSP to <span class="token number">0</span> <span class="token keyword">for</span> initial context <span class="token keyword">switch</span> call MSR PSP<span class="token punctuation">,</span> R4 <span class="token punctuation">;</span> take PSP Move the pointer to the start of the idle task <span class="token punctuation">;</span> PENDSV Go back to execution PendSV_Handler_Nosave LDR R4<span class="token punctuation">,</span> <span class="token operator">=</span>OSRunning <span class="token punctuation">;</span> OSRunning <span class="token operator">=</span> TRUE MOV R5<span class="token punctuation">,</span> #<span class="token number">1</span> <span class="token punctuation">;</ Span > tell the system to start running STRB R5<span class="token punctuation">,</span> <span class="token punctuation">[</span>R4<span class="token punctuation">]</span> <span class="token punctuation">;</span> LDR R4<span class="token punctuation">,</span> <span class="token operator">=</span>NVIC_INT_CTRL <span class="token punctuation">;</span>trigger the PendSV exception <span class="token punctuation">(</span>causes context <span class="token keyword">switch</span><span class="token punctuation">)</span> LDR R5<span class="token punctuation">,</span> <span class="token operator">=</span>NVIC_PENDSVSET <span class="token punctuation">;</span>trigger PENDSV interrupt STR R5<span class="token punctuation">,</span> <span class="token punctuation">[</span>R4<span class="token punctuation">]</span> CPSIE I <span class="token punctuation">;</span>enable interrupts at processor level
OSStartHang
B OSStartHang ;should never get here
;
; PERFORM A CONTEXT SWITCH (From task level) performs a context switch from the task level
; void OSCtxSw(void)
;
; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function
; triggers the PendSV exception which is where the real work is done.
; OSCtxSw and OSIntCtxSw are used for task switching. They both look the same. In fact, they are different
; They just trigger a PendSV interrupt. The specific switching process is carried out in the PendSV interrupt service function. these two items.
; The functions look the same, but their meanings are different. OSCtxSw is task level switching, such as switching from task A
;
OSCtxSw
PUSH {
R4, R5}
LDR R4, =NVIC_INT_CTRL ; Address of interrupt control register (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {
R4, R5}
BX LR
; Interrupt switch to task
OSIntCtxSw
PUSH {
R4, R5}
LDR R4, =NVIC_INT_CTRL
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {
R4, R5}
BX LR
NOP ; Prompt MCU that I have finished stacking and do not need to do it again
PendSV_Handler
CPSID I ; Close interrupt interrupt during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, PendSV_ Handler_ Nosave ; Whether PSP is equal to 0 determines whether it is the first call
; If yes, the following paragraph does not need to execute Skip register save the first time
SUBS R0<span class="token punctuation">,</span> R0<span class="token punctuation">,</span> #<span class="token number">0x20</span> <span class="token punctuation">;</ Span > < span class = "token number" > 0x20 < / span > means that < span class = "token number" > 32 < / span > bytes need to be pushed into the stack. Save remaining regs R4 < span class = "token operator" > - < / span > < span class = "token number" > 11 < / span > on process stack STM R0<span class="token punctuation">,</span> <span class="token punctuation">{<!-- --></span>R4<span class="token operator">-</span>R11<span class="token punctuation">}</span> LDR R1<span class="token punctuation">,</span> <span class="token operator">=</span>OSTCBCur <span class="token punctuation">;</span> OSTCBCur<span class="token operator">-></span>OSTCBStkPtr <span class="token operator">=</span> SP<span class="token punctuation">;</span> LDR R1<span class="token punctuation">,</span> <span class="token punctuation">[</span>R1<span class="token punctuation">]</span> STR R0<span class="token punctuation">,</span> <span class="token punctuation">[</span>R1<span class="token punctuation">]</span> <span class="token punctuation">;</span> R0 is SP of process being switched out <span class="token punctuation">;</span> At this point<span class="token punctuation">,</span> entire context of process has been saved
PendSV_Handler_Nosave
PUSH {
R14} ; Call the dog subfunction Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {
R14}
LDR R0<span class="token punctuation">,</span> <span class="token operator">=</span>OSPrioCur <span class="token punctuation">;</span> OSPrioCur <span class="token operator">=</span> OSPrioHighRdy<span class="token punctuation">;</span> LDR R1<span class="token punctuation">,</span> <span class="token operator">=</span>OSPrioHighRdy LDRB R2<span class="token punctuation">,</span> <span class="token punctuation">[</span>R1<span class="token punctuation">]</span> STRB R2<span class="token punctuation">,</span> <span class="token punctuation">[</span>R0<span class="token punctuation">]</span> LDR R0<span class="token punctuation">,</span> <span class="token operator">=</span>OSTCBCur <span class="token punctuation">;</span> <span class="token operator">*</span>R0<span class="token operator">=</span>R2 as well as OSTCBCur <span class="token operator">=</span> OSTCBHighRdy<span class="token punctuation">;</span> LDR R1<span class="token punctuation">,</span> <span class="token operator">=</span>OSTCBHighRdy <span class="token punctuation">;</span> Is a pointer to the task control block structure that can point to the highest priority LDR R2<span class="token punctuation">,</span> <span class="token punctuation">[</span>R1<span class="token punctuation">]</span> STR R2<span class="token punctuation">,</span> <span class="token punctuation">[</span>R0<span class="token punctuation">]</span> LDR R0<span class="token punctuation">,</span> <span class="token punctuation">[</span>R2<span class="token punctuation">]</span> <span class="token punctuation">;</span> R0<span class="token operator">=</span>OSTCBHighRdy R0 is new process SP<span class="token punctuation">;</span> SP <span class="token operator">=</span> OSTCBHighRdy<span class="token operator">-></span>OSTCBStkPtr<span class="token punctuation">;</span> LDM R0<span class="token punctuation">,</span> <span class="token punctuation">{<!-- --></span>R4<span class="token operator">-</span>R11<span class="token punctuation">}</span> <span class="token punctuation">;</span> Recovery stack Restore r4<span class="token operator">-</span><span class="token number">11</span> from new process stack ADDS R0<span class="token punctuation">,</span> R0<span class="token punctuation">,</span> #<span class="token number">0x20</span> MSR PSP<span class="token punctuation">,</span> R0 <span class="token punctuation">;</span> R0<span class="token operator">+</span><span class="token operator">=</span><span class="token number">0X20</span> R0 Is the stack top pointer of the star task Load PSP with new process SP ORR LR<span class="token punctuation">,</span> LR<span class="token punctuation">,</span> #<span class="token number">0x04</span> <span class="token punctuation">;</ Span > change the value of PSP to R0 ensure exception < span class = "token keyword" > return < / span > uses process stack CPSIE I <span class="token punctuation">;</span> take LR position<span class="token number">2</span>Set<span class="token number">1</span> ,Means to return to the process after returning BX LR <span class="token punctuation">;</span> Exception <span class="token keyword">return</span> will restore remaining context
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
OSStartHighRdy OSCtxSw OSIntCtxSw OS_CPU_SR_Save OS_CPU_SR_Restore
- 1
- 2
- 3
- 4
- 5
This file mainly provides these five functions to the outside,
OSStartHighRdy is mainly called by OSStart
OSCtxSw
OSIntCtxSw
These two are the core functions of task switching, which will be used by the OS_ core. OSIntExit (void) and void OS in C_ The sched (void) function call can be traced back to systemtick_ OSIntExit() is called in the Handle function. So far, the basic framework of task scheduling has come out.
SystemTick_Handle ->OSIntExit()->OSCtxSw->PendSV_Handler triggers task scheduling
os_cpu.c
#define OS_CPU_GLOBALS
#include "includes.h"
OS_STK OSTaskStkInit (void (task)(void p_arg), void p_arg, OS_STK ptos, INT16U opt)
{
OS_STK stk;
<span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span>opt<span class="token punctuation">;</span> <span class="token comment">/* 'opt' is not used, prevent warning */</span> stk <span class="token operator">=</span> ptos<span class="token punctuation">;</span> <span class="token comment">/* Load stack pointer */</span>
//Except for the first few, these values are all written blindly
/* Registers stacked as if auto-saved on exception /
(stk) = (INT32U)0x01000000L; /* xPSR /
(–stk) = (INT32U)task; /* Entry Point /
(–stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)/
(–stk) = (INT32U)0x12121212L; /* R12 /
(–stk) = (INT32U)0x03030303L; /* R3 /
(–stk) = (INT32U)0x02020202L; /* R2 /
(–stk) = (INT32U)0x01010101L; /* R1 /
(–stk) = (INT32U)p_arg; /* R0 : argument */
<span class="token comment">/* Remaining registers saved on process stack */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x11111111L</span><span class="token punctuation">;</span> <span class="token comment">/* R11 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x10101010L</span><span class="token punctuation">;</span> <span class="token comment">/* R10 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x09090909L</span><span class="token punctuation">;</span> <span class="token comment">/* R9 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x08080808L</span><span class="token punctuation">;</span> <span class="token comment">/* R8 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x07070707L</span><span class="token punctuation">;</span> <span class="token comment">/* R7 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x06060606L</span><span class="token punctuation">;</span> <span class="token comment">/* R6 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x05050505L</span><span class="token punctuation">;</span> <span class="token comment">/* R5 */</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">--</span>stk<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span>INT32U<span class="token punctuation">)</span><span class="token number">0x04040404L</span><span class="token punctuation">;</span> <span class="token comment">/* R4 */</span> <span class="token keyword">return</span> <span class="token punctuation">(</span>stk<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
What this file really wants to see is this function. Other functions are all hook functions. There is no need to see them. In fact, it's nothing. It's just to initialize the task stack from the top of the stack down. You may ask, what are these numbers for? My personal feeling is that the author wrote them according to his mood. As long as there is a data on it.