]> begriffs open source - cmsis-freertos/blob - Source/portable/CCS/ARM_Cortex-R4/port.c
Updated pack to FreeRTOS 10.4.3
[cmsis-freertos] / Source / portable / CCS / ARM_Cortex-R4 / port.c
1 /*
2  * FreeRTOS Kernel V10.4.3
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 /* FreeRTOS includes. */
29 #include "FreeRTOS.h"
30 #include "task.h"
31
32 /*-----------------------------------------------------------*/
33
34 /* Count of the critical section nesting depth. */
35 uint32_t ulCriticalNesting = 9999;
36
37 /*-----------------------------------------------------------*/
38
39 /* Registers required to configure the RTI. */
40 #define portRTI_GCTRL_REG               ( * ( ( volatile uint32_t * ) 0xFFFFFC00 ) )
41 #define portRTI_TBCTRL_REG      ( * ( ( volatile uint32_t * ) 0xFFFFFC04 ) )
42 #define portRTI_COMPCTRL_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC0C ) )
43 #define portRTI_CNT0_FRC0_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC10 ) )
44 #define portRTI_CNT0_UC0_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC14 ) )
45 #define portRTI_CNT0_CPUC0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC18 ) )
46 #define portRTI_CNT0_COMP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC50 ) )
47 #define portRTI_CNT0_UDCP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC54 ) )
48 #define portRTI_SETINTENA_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC80 ) )
49 #define portRTI_CLEARINTENA_REG ( * ( ( volatile uint32_t * ) 0xFFFFFC84 ) )
50 #define portRTI_INTFLAG_REG     ( * ( ( volatile uint32_t * ) 0xFFFFFC88 ) )
51
52
53 /* Constants required to set up the initial stack of each task. */
54 #define portINITIAL_SPSR                ( ( StackType_t ) 0x1F )
55 #define portINITIAL_FPSCR               ( ( StackType_t ) 0x00 )
56 #define portINSTRUCTION_SIZE    ( ( StackType_t ) 0x04 )
57 #define portTHUMB_MODE_BIT              ( ( StackType_t ) 0x20 )
58
59 /* The number of words on the stack frame between the saved Top Of Stack and
60 R0 (in which the parameters are passed. */
61 #define portSPACE_BETWEEN_TOS_AND_PARAMETERS    ( 12 )
62
63 /*-----------------------------------------------------------*/
64
65 /* vPortStartFirstSTask() is defined in portASM.asm */
66 extern void vPortStartFirstTask( void );
67
68 /*-----------------------------------------------------------*/
69
70 /* Saved as part of the task context.  Set to pdFALSE if the task does not
71 require an FPU context. */
72 uint32_t ulTaskHasFPUContext = 0;
73
74 /*-----------------------------------------------------------*/
75
76
77 /*
78  * See header file for description.
79  */
80 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
81 {
82 StackType_t *pxOriginalTOS;
83
84         pxOriginalTOS = pxTopOfStack;
85
86         #if __TI_VFP_SUPPORT__
87         {
88                 /* Ensure the stack is correctly aligned on exit. */
89                 pxTopOfStack--;
90         }
91         #endif
92
93         /* Setup the initial stack of the task.  The stack is set exactly as
94         expected by the portRESTORE_CONTEXT() macro. */
95
96         /* First on the stack is the return address - which is the start of the as
97         the task has not executed yet.  The offset is added to make the return
98         address appear as it would within an IRQ ISR. */
99         *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
100         pxTopOfStack--;
101
102         *pxTopOfStack = ( StackType_t ) 0x00000000;     /* R14 */
103         pxTopOfStack--;
104         *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
105         pxTopOfStack--;
106
107         #ifdef portPRELOAD_TASK_REGISTERS
108         {
109                 *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */
110                 pxTopOfStack--;
111                 *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */
112                 pxTopOfStack--;
113                 *pxTopOfStack = ( StackType_t ) 0x10101010;     /* R10 */
114                 pxTopOfStack--;
115                 *pxTopOfStack = ( StackType_t ) 0x09090909;     /* R9 */
116                 pxTopOfStack--;
117                 *pxTopOfStack = ( StackType_t ) 0x08080808;     /* R8 */
118                 pxTopOfStack--;
119                 *pxTopOfStack = ( StackType_t ) 0x07070707;     /* R7 */
120                 pxTopOfStack--;
121                 *pxTopOfStack = ( StackType_t ) 0x06060606;     /* R6 */
122                 pxTopOfStack--;
123                 *pxTopOfStack = ( StackType_t ) 0x05050505;     /* R5 */
124                 pxTopOfStack--;
125                 *pxTopOfStack = ( StackType_t ) 0x04040404;     /* R4 */
126                 pxTopOfStack--;
127                 *pxTopOfStack = ( StackType_t ) 0x03030303;     /* R3 */
128                 pxTopOfStack--;
129                 *pxTopOfStack = ( StackType_t ) 0x02020202;     /* R2 */
130                 pxTopOfStack--;
131                 *pxTopOfStack = ( StackType_t ) 0x01010101;     /* R1 */
132                 pxTopOfStack--;
133         }
134         #else
135         {
136                 pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS;
137         }
138         #endif
139
140         /* Function parameters are passed in R0. */
141         *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
142         pxTopOfStack--;
143
144         /* Set the status register for system mode, with interrupts enabled. */
145         *pxTopOfStack = ( StackType_t ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR );
146
147         if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00 )
148         {
149                 /* The task will start in thumb mode. */
150                 *pxTopOfStack |= portTHUMB_MODE_BIT;
151         }
152
153         #ifdef __TI_VFP_SUPPORT__
154         {
155                 pxTopOfStack--;
156
157                 /* The last thing on the stack is the tasks ulUsingFPU value, which by
158                 default is set to indicate that the stack frame does not include FPU
159                 registers. */
160                 *pxTopOfStack = pdFALSE;
161         }
162         #endif
163
164         return pxTopOfStack;
165 }
166 /*-----------------------------------------------------------*/
167
168 static void prvSetupTimerInterrupt(void)
169 {
170         /* Disable timer 0. */
171         portRTI_GCTRL_REG &= 0xFFFFFFFEUL;
172
173         /* Use the internal counter. */
174         portRTI_TBCTRL_REG = 0x00000000U;
175
176         /* COMPSEL0 will use the RTIFRC0 counter. */
177         portRTI_COMPCTRL_REG = 0x00000000U;
178
179         /* Initialise the counter and the prescale counter registers. */
180         portRTI_CNT0_UC0_REG =  0x00000000U;
181         portRTI_CNT0_FRC0_REG =  0x00000000U;
182
183         /* Set Prescalar for RTI clock. */
184         portRTI_CNT0_CPUC0_REG = 0x00000001U;
185         portRTI_CNT0_COMP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
186         portRTI_CNT0_UDCP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
187
188         /* Clear interrupts. */
189         portRTI_INTFLAG_REG =  0x0007000FU;
190         portRTI_CLEARINTENA_REG = 0x00070F0FU;
191
192         /* Enable the compare 0 interrupt. */
193         portRTI_SETINTENA_REG = 0x00000001U;
194         portRTI_GCTRL_REG |= 0x00000001U;
195 }
196 /*-----------------------------------------------------------*/
197
198 /*
199  * See header file for description.
200  */
201 BaseType_t xPortStartScheduler(void)
202 {
203         /* Start the timer that generates the tick ISR. */
204         prvSetupTimerInterrupt();
205
206         /* Reset the critical section nesting count read to execute the first task. */
207         ulCriticalNesting = 0;
208
209         /* Start the first task.  This is done from portASM.asm as ARM mode must be
210         used. */
211         vPortStartFirstTask();
212
213         /* Should not get here! */
214         return pdFAIL;
215 }
216 /*-----------------------------------------------------------*/
217
218 /*
219  * See header file for description.
220  */
221 void vPortEndScheduler(void)
222 {
223         /* Not implemented in ports where there is nothing to return to.
224         Artificially force an assert. */
225         configASSERT( ulCriticalNesting == 1000UL );
226 }
227 /*-----------------------------------------------------------*/
228
229 #if configUSE_PREEMPTION == 0
230
231         /* The cooperative scheduler requires a normal IRQ service routine to
232          * simply increment the system tick. */
233         __interrupt void vPortNonPreemptiveTick( void )
234         {
235                 /* clear clock interrupt flag */
236                 portRTI_INTFLAG_REG = 0x00000001;
237
238                 /* Increment the tick count - this may make a delaying task ready
239                 to run - but a context switch is not performed. */
240                 xTaskIncrementTick();
241         }
242
243  #else
244
245         /*
246          **************************************************************************
247          * The preemptive scheduler ISR is written in assembler and can be found
248          * in the portASM.asm file. This will only get used if portUSE_PREEMPTION
249          * is set to 1 in portmacro.h
250          **************************************************************************
251          */
252         void vPortPreemptiveTick( void );
253
254 #endif
255 /*-----------------------------------------------------------*/
256
257
258 /*
259  * Disable interrupts, and keep a count of the nesting depth.
260  */
261 void vPortEnterCritical( void )
262 {
263         /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
264         portDISABLE_INTERRUPTS();
265
266         /* Now interrupts are disabled ulCriticalNesting can be accessed
267         directly.  Increment ulCriticalNesting to keep a count of how many times
268         portENTER_CRITICAL() has been called. */
269         ulCriticalNesting++;
270 }
271 /*-----------------------------------------------------------*/
272
273 /*
274  * Decrement the critical nesting count, and if it has reached zero, re-enable
275  * interrupts.
276  */
277 void vPortExitCritical( void )
278 {
279         if( ulCriticalNesting > 0 )
280         {
281                 /* Decrement the nesting count as we are leaving a critical section. */
282                 ulCriticalNesting--;
283
284                 /* If the nesting level has reached zero then interrupts should be
285                 re-enabled. */
286                 if( ulCriticalNesting == 0 )
287                 {
288                         /* Enable interrupts as per portENABLE_INTERRUPTS(). */
289                         portENABLE_INTERRUPTS();
290                 }
291         }
292 }
293 /*-----------------------------------------------------------*/
294
295 #if __TI_VFP_SUPPORT__
296
297         void vPortTaskUsesFPU( void )
298         {
299         extern void vPortInitialiseFPSCR( void );
300
301                 /* A task is registering the fact that it needs an FPU context.  Set the
302                 FPU flag (saved as part of the task context. */
303                 ulTaskHasFPUContext = pdTRUE;
304
305                 /* Initialise the floating point status register. */
306                 vPortInitialiseFPSCR();
307         }
308
309 #endif /* __TI_VFP_SUPPORT__ */
310
311 /*-----------------------------------------------------------*/
312