2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
29 /* FreeRTOS includes. */
33 /*-----------------------------------------------------------*/
35 /* Count of the critical section nesting depth. */
36 uint32_t ulCriticalNesting = 9999;
38 /*-----------------------------------------------------------*/
40 /* Registers required to configure the RTI. */
41 #define portRTI_GCTRL_REG ( *( ( volatile uint32_t * ) 0xFFFFFC00 ) )
42 #define portRTI_TBCTRL_REG ( *( ( volatile uint32_t * ) 0xFFFFFC04 ) )
43 #define portRTI_COMPCTRL_REG ( *( ( volatile uint32_t * ) 0xFFFFFC0C ) )
44 #define portRTI_CNT0_FRC0_REG ( *( ( volatile uint32_t * ) 0xFFFFFC10 ) )
45 #define portRTI_CNT0_UC0_REG ( *( ( volatile uint32_t * ) 0xFFFFFC14 ) )
46 #define portRTI_CNT0_CPUC0_REG ( *( ( volatile uint32_t * ) 0xFFFFFC18 ) )
47 #define portRTI_CNT0_COMP0_REG ( *( ( volatile uint32_t * ) 0xFFFFFC50 ) )
48 #define portRTI_CNT0_UDCP0_REG ( *( ( volatile uint32_t * ) 0xFFFFFC54 ) )
49 #define portRTI_SETINTENA_REG ( *( ( volatile uint32_t * ) 0xFFFFFC80 ) )
50 #define portRTI_CLEARINTENA_REG ( *( ( volatile uint32_t * ) 0xFFFFFC84 ) )
51 #define portRTI_INTFLAG_REG ( *( ( volatile uint32_t * ) 0xFFFFFC88 ) )
54 /* Constants required to set up the initial stack of each task. */
55 #define portINITIAL_SPSR ( ( StackType_t ) 0x1F )
56 #define portINITIAL_FPSCR ( ( StackType_t ) 0x00 )
57 #define portINSTRUCTION_SIZE ( ( StackType_t ) 0x04 )
58 #define portTHUMB_MODE_BIT ( ( StackType_t ) 0x20 )
60 /* The number of words on the stack frame between the saved Top Of Stack and
61 * R0 (in which the parameters are passed. */
62 #define portSPACE_BETWEEN_TOS_AND_PARAMETERS ( 12 )
64 /*-----------------------------------------------------------*/
66 /* vPortStartFirstSTask() is defined in portASM.asm */
67 extern void vPortStartFirstTask( void );
69 /*-----------------------------------------------------------*/
71 /* Saved as part of the task context. Set to pdFALSE if the task does not
72 * require an FPU context. */
73 uint32_t ulTaskHasFPUContext = 0;
75 /*-----------------------------------------------------------*/
79 * See header file for description.
81 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
82 TaskFunction_t pxCode,
85 StackType_t * pxOriginalTOS;
87 pxOriginalTOS = pxTopOfStack;
89 #if __TI_VFP_SUPPORT__
91 /* Ensure the stack is correctly aligned on exit. */
96 /* Setup the initial stack of the task. The stack is set exactly as
97 * expected by the portRESTORE_CONTEXT() macro. */
99 /* First on the stack is the return address - which is the start of the as
100 * the task has not executed yet. The offset is added to make the return
101 * address appear as it would within an IRQ ISR. */
102 *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
105 *pxTopOfStack = ( StackType_t ) 0x00000000; /* R14 */
107 *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
110 #ifdef portPRELOAD_TASK_REGISTERS
112 *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
114 *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
116 *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
118 *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
120 *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
122 *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
124 *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
126 *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
128 *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
130 *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
132 *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
134 *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
137 #else /* ifdef portPRELOAD_TASK_REGISTERS */
139 pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS;
141 #endif /* ifdef portPRELOAD_TASK_REGISTERS */
143 /* Function parameters are passed in R0. */
144 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
147 /* Set the status register for system mode, with interrupts enabled. */
148 *pxTopOfStack = ( StackType_t ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR );
150 if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00 )
152 /* The task will start in thumb mode. */
153 *pxTopOfStack |= portTHUMB_MODE_BIT;
156 #ifdef __TI_VFP_SUPPORT__
160 /* The last thing on the stack is the tasks ulUsingFPU value, which by
161 * default is set to indicate that the stack frame does not include FPU
163 *pxTopOfStack = pdFALSE;
169 /*-----------------------------------------------------------*/
171 static void prvSetupTimerInterrupt( void )
173 /* Disable timer 0. */
174 portRTI_GCTRL_REG &= 0xFFFFFFFEUL;
176 /* Use the internal counter. */
177 portRTI_TBCTRL_REG = 0x00000000U;
179 /* COMPSEL0 will use the RTIFRC0 counter. */
180 portRTI_COMPCTRL_REG = 0x00000000U;
182 /* Initialise the counter and the prescale counter registers. */
183 portRTI_CNT0_UC0_REG = 0x00000000U;
184 portRTI_CNT0_FRC0_REG = 0x00000000U;
186 /* Set Prescalar for RTI clock. */
187 portRTI_CNT0_CPUC0_REG = 0x00000001U;
188 portRTI_CNT0_COMP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
189 portRTI_CNT0_UDCP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
191 /* Clear interrupts. */
192 portRTI_INTFLAG_REG = 0x0007000FU;
193 portRTI_CLEARINTENA_REG = 0x00070F0FU;
195 /* Enable the compare 0 interrupt. */
196 portRTI_SETINTENA_REG = 0x00000001U;
197 portRTI_GCTRL_REG |= 0x00000001U;
199 /*-----------------------------------------------------------*/
202 * See header file for description.
204 BaseType_t xPortStartScheduler( void )
206 /* Start the timer that generates the tick ISR. */
207 prvSetupTimerInterrupt();
209 /* Reset the critical section nesting count read to execute the first task. */
210 ulCriticalNesting = 0;
212 /* Start the first task. This is done from portASM.asm as ARM mode must be
214 vPortStartFirstTask();
216 /* Should not get here! */
219 /*-----------------------------------------------------------*/
222 * See header file for description.
224 void vPortEndScheduler( void )
226 /* Not implemented in ports where there is nothing to return to.
227 * Artificially force an assert. */
228 configASSERT( ulCriticalNesting == 1000UL );
230 /*-----------------------------------------------------------*/
232 #if configUSE_PREEMPTION == 0
234 /* The cooperative scheduler requires a normal IRQ service routine to
235 * simply increment the system tick. */
236 __interrupt void vPortNonPreemptiveTick( void )
238 /* clear clock interrupt flag */
239 portRTI_INTFLAG_REG = 0x00000001;
241 /* Increment the tick count - this may make a delaying task ready
242 * to run - but a context switch is not performed. */
243 xTaskIncrementTick();
246 #else /* if configUSE_PREEMPTION == 0 */
249 **************************************************************************
250 * The preemptive scheduler ISR is written in assembler and can be found
251 * in the portASM.asm file. This will only get used if portUSE_PREEMPTION
252 * is set to 1 in portmacro.h
253 **************************************************************************
255 void vPortPreemptiveTick( void );
257 #endif /* if configUSE_PREEMPTION == 0 */
258 /*-----------------------------------------------------------*/
262 * Disable interrupts, and keep a count of the nesting depth.
264 void vPortEnterCritical( void )
266 /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
267 portDISABLE_INTERRUPTS();
269 /* Now that interrupts are disabled, ulCriticalNesting can be accessed
270 * directly. Increment ulCriticalNesting to keep a count of how many times
271 * portENTER_CRITICAL() has been called. */
274 /*-----------------------------------------------------------*/
277 * Decrement the critical nesting count, and if it has reached zero, re-enable
280 void vPortExitCritical( void )
282 if( ulCriticalNesting > 0 )
284 /* Decrement the nesting count as we are leaving a critical section. */
287 /* If the nesting level has reached zero then interrupts should be
289 if( ulCriticalNesting == 0 )
291 /* Enable interrupts as per portENABLE_INTERRUPTS(). */
292 portENABLE_INTERRUPTS();
296 /*-----------------------------------------------------------*/
298 #if __TI_VFP_SUPPORT__
300 void vPortTaskUsesFPU( void )
302 extern void vPortInitialiseFPSCR( void );
304 /* A task is registering the fact that it needs an FPU context. Set the
305 * FPU flag (saved as part of the task context. */
306 ulTaskHasFPUContext = pdTRUE;
308 /* Initialise the floating point status register. */
309 vPortInitialiseFPSCR();
312 #endif /* __TI_VFP_SUPPORT__ */
314 /*-----------------------------------------------------------*/