1 /*
2 * FreeRTOS Kernel V10.4.1
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
24 *
25 * 1 tab == 4 spaces!
26 */
27 /*
28 * Copyright (C) 2018-2021 Texas Instruments Incorporated
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 *
34 * Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 *
37 * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the
40 * distribution.
41 *
42 * Neither the name of Texas Instruments Incorporated nor the names of
43 * its contributors may be used to endorse or promote products derived
44 * from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
49 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
50 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58 #include <stdint.h>
59 #include <stdio.h>
60 #include <FreeRTOS.h>
61 #include <task.h>
62 #include <ti/osal/osal.h>
63 #include <ti/osal/HwiP.h>
64 #include <ti/osal/DebugP.h>
68 /* Let the user override the pre-loading of the initial LR with the address of
69 * prvTaskExitError() in case is messes up unwinding of the stack in the
70 * debugger. */
71 #ifdef configTASK_RETURN_ADDRESS
72 #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
73 #else
74 #define portTASK_RETURN_ADDRESS prvTaskExitError
75 #endif
78 /* A critical section is exited when the critical section nesting count reaches
79 * this value. */
80 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
82 /* Tasks are not created with a floating point context, but can be given a
83 * floating point context after they have been created. A variable is stored as
84 * part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
85 * does not have an FPU context, or any other value if the task does have an FPU
86 * context. */
87 #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
89 /* A variable is used to keep track of the critical section nesting. This
90 * variable has to be stored as part of the task context and must be initialised to
91 * a non zero value to ensure interrupts don't inadvertently become unmasked before
92 * the scheduler starts. As it is stored as part of the task context it will
93 * automatically be set to 0 when the first task is started. */
94 volatile uint32_t ulCriticalNesting = 9999UL;
96 /* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
97 * a floating point context must be saved and restored for the task. */
98 uint32_t ulPortTaskHasFPUContext = pdFALSE;
100 /* Set to 1 to pend a context switch from an ISR. */
101 uint32_t ulPortYieldRequired = pdFALSE;
103 /* Counts the interrupt nesting depth. A context switch is only performed if
104 * if the nesting depth is 0. */
105 uint32_t ulPortInterruptNesting = 0UL;
107 /* set to true when schedular gets enabled in xPortStartScheduler */
108 uint32_t ulPortSchedularRunning = pdFALSE;
110 /*
111 * Task control block. A task control block (TCB) is allocated for each task,
112 * and stores task state information, including a pointer to the task's context
113 * (the task's run time environment, including register values)
114 */
115 typedef struct tskTaskControlBlockBaseClass /* The old naming convention is used to prevent breaking kernel aware debuggers. */
116 {
117 volatile void * pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
118 } tskTaskControlBlockBaseClass_t;
120 extern tskTaskControlBlockBaseClass_t * pxCurrentTCB;
121 /*
122 * Starts the first task executing. This function is necessarily written in
123 * assembly code so is implemented in portASM.s.
124 */
125 extern void vPortRestoreTaskContext( void );
127 extern volatile cregister uint32_t TSCL, TSCH;
129 static void prvTaskExitError( void )
130 {
131 /* A function that implements a task must not exit or attempt to return to
132 * its caller as there is nothing to return to. If a task wants to exit it
133 * should instead call vTaskDelete( NULL ).
134 *
135 * Force an assert() to be triggered if configASSERT() is
136 * defined, then stop here so application writers can catch the error. */
137 DebugP_assert(0);
138 }
140 #define TaskSupport_buildTaskStack ti_sysbios_family_c62_TaskSupport_buildTaskStack
142 typedef void (*Task_FuncPtr)(uint32_t arg1, uint32_t arg2);
144 typedef void (*TaskSupport_FuncPtr)(void);
147 extern void * TaskSupport_buildTaskStack(void * stack, Task_FuncPtr fxn, TaskSupport_FuncPtr exit, TaskSupport_FuncPtr enter, uint32_t arg0, uint32_t arg1);
148 /*
149 * ======== Task_exit ========
150 */
151 void Task_exit(void)
152 {
153 prvTaskExitError();
154 }
156 void Task_enter(void)
157 {
159 }
161 void ti_sysbios_knl_Task_Func(uint32_t arg1, uint32_t arg2)
162 {
163 TaskFunction_t pxCode = (TaskFunction_t)arg2;
164 pxCode((void *)arg1);
165 }
167 #if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
168 StackType_t *pxPortInitialiseStack(StackType_t * pxTopOfStack, StackType_t * pxEndOfStack, TaskFunction_t pxCode, void * pvParameters )
169 #else
170 StackType_t *pxPortInitialiseStack(StackType_t * pxTopOfStack, TaskFunction_t pxCode, void * pvParameters )
171 #endif
172 {
173 #if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
174 {
175 (void) pxEndOfStack;
176 }
177 #endif
179 pxTopOfStack = (StackType_t *)TaskSupport_buildTaskStack(pxTopOfStack, ti_sysbios_knl_Task_Func, Task_exit, Task_enter, (uint32_t)pvParameters, (uint32_t)pxCode);
181 return pxTopOfStack;
182 }
184 extern void Hwi_switchFromBootStack(void);
185 extern void Hwi_Module_startup(void);
187 TimerP_Handle pTickTimerHandle = NULL;
189 static void prvPorttimerTickIsr(uintptr_t args)
190 {
191 void vPortTimerTickHandler();
193 vPortTimerTickHandler();
194 }
196 static void prvPortInitTickTimer(void)
197 {
199 TimerP_Params timerParams;
201 TimerP_Params_init(&timerParams);
202 timerParams.runMode = TimerP_RunMode_CONTINUOUS;
203 timerParams.startMode = TimerP_StartMode_USER;
204 timerParams.periodType = TimerP_PeriodType_MICROSECS;
205 timerParams.period = (portTICK_PERIOD_MS * 1000);
206 timerParams.intNum = configTIMER_INT_NUM;
208 pTickTimerHandle = TimerP_create(configTIMER_ID, &prvPorttimerTickIsr, &timerParams);
210 /* don't expect the handle to be null */
211 DebugP_assert (pTickTimerHandle != NULL);
213 }
215 static void prvPortStartTickTimer(void)
216 {
217 TimerP_Status status;
218 status = TimerP_start(pTickTimerHandle);
220 /* don't expect the handle to be null */
221 DebugP_assert (status == TimerP_OK);
223 }
225 BaseType_t xPortStartScheduler(void)
226 {
227 /* Interrupts are turned off in the CPU itself to ensure tick does
228 * not execute while the scheduler is being started. Interrupts are
229 * automatically turned back on in the CPU when the first task starts
230 * executing.
231 */
232 portDISABLE_INTERRUPTS();
234 Hwi_Module_startup();
235 prvPortInitTickTimer();
236 Hwi_switchFromBootStack();
238 /* Start the ISR handling of the timer that generates the tick ISR. */
239 prvPortStartTickTimer();
240 ulPortSchedularRunning = pdTRUE;
242 /* Start the first task executing. */
243 vPortRestoreTaskContext();
245 /* Will only get here if vTaskStartScheduler() was called with the CPU in
246 * a non-privileged mode or the binary point register was not set to its lowest
247 * possible value. prvTaskExitError() is referenced to prevent a compiler
248 * warning about it being defined but not referenced in the case that the user
249 * defines their own exit address. */
250 ( void ) prvTaskExitError;
252 return pdTRUE;
253 }
255 void vPortYeildFromISR( uint32_t xSwitchRequired )
256 {
257 if( xSwitchRequired != pdFALSE )
258 {
259 ulPortYieldRequired = pdTRUE;
260 }
261 }
263 void vPortTimerTickHandler()
264 {
265 if( ulPortSchedularRunning == pdTRUE )
266 {
267 /* Increment the RTOS tick. */
268 if( xTaskIncrementTick() != pdFALSE )
269 {
270 ulPortYieldRequired = pdTRUE;
271 }
272 }
273 }
275 void vPortTaskUsesFPU( void )
276 {
277 /* A task is registering the fact that it needs an FPU context. Set the
278 * FPU flag (which is saved as part of the task context). */
279 ulPortTaskHasFPUContext = pdTRUE;
281 }
284 /* initialize high resolution timer for CPU and task load calculation */
285 void vPortConfigTimerForRunTimeStats()
286 {
288 /* we assume clock is initialized before the schedular is started */
289 /* start TSC */
290 TSCL = 0;
291 }
293 /* return current counter value of high speed counter in units of 10's of usecs */
294 uint32_t uiPortGetRunTimeCounterValue()
295 {
296 uint64_t ts = ((uint64_t)TSCL | ((uint64_t) TSCH << 32U));
297 uint64_t timeInUsecs;
299 timeInUsecs = (ts * 1000000) / configCPU_CLOCK_HZ;
300 /* note, there is no overflow protection for this 32b value in FreeRTOS
301 *
302 * Dividing by 10 to reduce the resolution and avoid overflow for longer duration
303 * This will overflow after
304 * ((0x100000000/1000000)/(60*60))*10 hours ~ 12 hrs
305 */
306 return (uint32_t)(timeInUsecs/10);
307 }
309 /* This is used to make sure we are using the FreeRTOS API from within a valid interrupt priority level
310 * In our R%F port this means IRQ.
311 * i.e FreeRTOS API should not be called from FIQ, however right now we dont enforce it by checking
312 * if we are in FIQ when this API is called.
313 */
314 void vPortValidateInterruptPriority()
315 {
316 }
318 /* This is called as part of vTaskEndScheduler(), in our port, there is nothing to do here.
319 * interrupt are disabled by FreeRTOS before calling this.
320 */
321 void vPortEndScheduler()
322 {
323 /* nothing to do */
324 }
326 /* configCHECK_FOR_STACK_OVERFLOW is set to 1, so the application must provide an
327 * implementation of vApplicationStackOverflowHook()
328 */
329 void vApplicationStackOverflowHook( TaskHandle_t xTask,
330 char * pcTaskName )
331 {
332 DebugP_log1("[FreeRTOS] Stack overflow detected for task [%s]", (uintptr_t)pcTaskName);
333 DebugP_assert(0);
334 }
336 /* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an
337 * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
338 * used by the Idle task.
339 */
340 void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
341 StackType_t **ppxIdleTaskStackBuffer,
342 uint32_t *pulIdleTaskStackSize )
343 {
344 /* If the buffers to be provided to the Idle task are declared inside this
345 * function then they must be declared static – otherwise they will be allocated on
346 * the stack and so not exists after this function exits.
347 */
348 static StaticTask_t xIdleTaskTCB;
349 static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
351 /* Pass out a pointer to the StaticTask_t structure in which the Idle task’s
352 * state will be stored.
353 */
354 *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
356 /* Pass out the array that will be used as the Idle task’s stack. */
357 *ppxIdleTaskStackBuffer = uxIdleTaskStack;
359 /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
360 * Note that, as the array is necessarily of type StackType_t,
361 * configMINIMAL_STACK_SIZE is specified in words, not bytes.
362 */
363 *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
364 }
366 /* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
367 * application must provide an implementation of vApplicationGetTimerTaskMemory()
368 * to provide the memory that is used by the Timer service task.
369 */
370 void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
371 StackType_t **ppxTimerTaskStackBuffer,
372 uint32_t *pulTimerTaskStackSize )
373 {
374 /* If the buffers to be provided to the Timer task are declared inside this
375 * function then they must be declared static – otherwise they will be allocated on
376 * the stack and so not exists after this function exits.
377 */
378 static StaticTask_t xTimerTaskTCB;
379 static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
381 /* Pass out a pointer to the StaticTask_t structure in which the Timer
382 * task's state will be stored.
383 */
384 *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
386 /* Pass out the array that will be used as the Timer task’s stack. */
387 *ppxTimerTaskStackBuffer = uxTimerTaskStack;
389 /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
390 * Note that, as the array is necessarily of type StackType_t,
391 * configTIMER_TASK_STACK_DEPTH is specified in words, not bytes.
392 */
393 *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
394 }
396 extern void ti_sysbios_family_c62_TaskSupport_swap__E( void **oldtskContext, void **newtskContext);
399 void vPortRestoreTaskContext()
400 {
401 void * dummyTaskSp;
403 ti_sysbios_family_c62_TaskSupport_swap__E( &dummyTaskSp, (void **)(&pxCurrentTCB->pxTopOfStack));
404 }
406 void vPortYield()
407 {
408 void **oldSP;
409 void **newSP;
411 oldSP = (void **)(&pxCurrentTCB->pxTopOfStack);
412 vTaskSwitchContext();
413 newSP = (void **)(&pxCurrentTCB->pxTopOfStack);
414 _enable_interrupts();
415 ti_sysbios_family_c62_TaskSupport_swap__E(oldSP, newSP);
416 }
418 /*
419 * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
420 * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
421 */
422 BaseType_t xPortInIsrContext()
423 {
424 BaseType_t inISR = false;
425 if (ulPortInterruptNesting != 0)
426 {
427 inISR = true;
428 }
429 return inISR;
430 }
432 void vPortAssertIfInISR()
433 {
434 if( xPortInIsrContext() )
435 {
436 DebugP_log0( "port_interruptNesting\n\n");
437 }
439 configASSERT( !xPortInIsrContext() );
440 }