]> begriffs open source - freertos/blob - portable/CCS/ARM_Cortex-R4/port.c
Add base priority get APIs (#818)
[freertos] / portable / CCS / ARM_Cortex-R4 / port.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
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.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* FreeRTOS includes. */
30 #include "FreeRTOS.h"
31 #include "task.h"
32
33 /*-----------------------------------------------------------*/
34
35 /* Count of the critical section nesting depth. */
36 uint32_t ulCriticalNesting = 9999;
37
38 /*-----------------------------------------------------------*/
39
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 ) )
52
53
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 )
59
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 )
63
64 /*-----------------------------------------------------------*/
65
66 /* vPortStartFirstSTask() is defined in portASM.asm */
67 extern void vPortStartFirstTask( void );
68
69 /*-----------------------------------------------------------*/
70
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;
74
75 /*-----------------------------------------------------------*/
76
77
78 /*
79  * See header file for description.
80  */
81 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
82                                      TaskFunction_t pxCode,
83                                      void * pvParameters )
84 {
85     StackType_t * pxOriginalTOS;
86
87     pxOriginalTOS = pxTopOfStack;
88
89     #if __TI_VFP_SUPPORT__
90     {
91         /* Ensure the stack is correctly aligned on exit. */
92         pxTopOfStack--;
93     }
94     #endif
95
96     /* Setup the initial stack of the task.  The stack is set exactly as
97      * expected by the portRESTORE_CONTEXT() macro. */
98
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;
103     pxTopOfStack--;
104
105     *pxTopOfStack = ( StackType_t ) 0x00000000;    /* R14 */
106     pxTopOfStack--;
107     *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
108     pxTopOfStack--;
109
110     #ifdef portPRELOAD_TASK_REGISTERS
111     {
112         *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
113         pxTopOfStack--;
114         *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
115         pxTopOfStack--;
116         *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
117         pxTopOfStack--;
118         *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
119         pxTopOfStack--;
120         *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
121         pxTopOfStack--;
122         *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
123         pxTopOfStack--;
124         *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
125         pxTopOfStack--;
126         *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
127         pxTopOfStack--;
128         *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
129         pxTopOfStack--;
130         *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
131         pxTopOfStack--;
132         *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
133         pxTopOfStack--;
134         *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
135         pxTopOfStack--;
136     }
137     #else /* ifdef portPRELOAD_TASK_REGISTERS */
138     {
139         pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS;
140     }
141     #endif /* ifdef portPRELOAD_TASK_REGISTERS */
142
143     /* Function parameters are passed in R0. */
144     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
145     pxTopOfStack--;
146
147     /* Set the status register for system mode, with interrupts enabled. */
148     *pxTopOfStack = ( StackType_t ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR );
149
150     if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00 )
151     {
152         /* The task will start in thumb mode. */
153         *pxTopOfStack |= portTHUMB_MODE_BIT;
154     }
155
156     #ifdef __TI_VFP_SUPPORT__
157     {
158         pxTopOfStack--;
159
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
162          * registers. */
163         *pxTopOfStack = pdFALSE;
164     }
165     #endif
166
167     return pxTopOfStack;
168 }
169 /*-----------------------------------------------------------*/
170
171 static void prvSetupTimerInterrupt( void )
172 {
173     /* Disable timer 0. */
174     portRTI_GCTRL_REG &= 0xFFFFFFFEUL;
175
176     /* Use the internal counter. */
177     portRTI_TBCTRL_REG = 0x00000000U;
178
179     /* COMPSEL0 will use the RTIFRC0 counter. */
180     portRTI_COMPCTRL_REG = 0x00000000U;
181
182     /* Initialise the counter and the prescale counter registers. */
183     portRTI_CNT0_UC0_REG = 0x00000000U;
184     portRTI_CNT0_FRC0_REG = 0x00000000U;
185
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;
190
191     /* Clear interrupts. */
192     portRTI_INTFLAG_REG = 0x0007000FU;
193     portRTI_CLEARINTENA_REG = 0x00070F0FU;
194
195     /* Enable the compare 0 interrupt. */
196     portRTI_SETINTENA_REG = 0x00000001U;
197     portRTI_GCTRL_REG |= 0x00000001U;
198 }
199 /*-----------------------------------------------------------*/
200
201 /*
202  * See header file for description.
203  */
204 BaseType_t xPortStartScheduler( void )
205 {
206     /* Start the timer that generates the tick ISR. */
207     prvSetupTimerInterrupt();
208
209     /* Reset the critical section nesting count read to execute the first task. */
210     ulCriticalNesting = 0;
211
212     /* Start the first task.  This is done from portASM.asm as ARM mode must be
213      * used. */
214     vPortStartFirstTask();
215
216     /* Should not get here! */
217     return pdFAIL;
218 }
219 /*-----------------------------------------------------------*/
220
221 /*
222  * See header file for description.
223  */
224 void vPortEndScheduler( void )
225 {
226     /* Not implemented in ports where there is nothing to return to.
227      * Artificially force an assert. */
228     configASSERT( ulCriticalNesting == 1000UL );
229 }
230 /*-----------------------------------------------------------*/
231
232 #if configUSE_PREEMPTION == 0
233
234 /* The cooperative scheduler requires a normal IRQ service routine to
235  * simply increment the system tick. */
236     __interrupt void vPortNonPreemptiveTick( void )
237     {
238         /* clear clock interrupt flag */
239         portRTI_INTFLAG_REG = 0x00000001;
240
241         /* Increment the tick count - this may make a delaying task ready
242          * to run - but a context switch is not performed. */
243         xTaskIncrementTick();
244     }
245
246 #else /* if configUSE_PREEMPTION == 0 */
247
248 /*
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  **************************************************************************
254  */
255     void vPortPreemptiveTick( void );
256
257 #endif /* if configUSE_PREEMPTION == 0 */
258 /*-----------------------------------------------------------*/
259
260
261 /*
262  * Disable interrupts, and keep a count of the nesting depth.
263  */
264 void vPortEnterCritical( void )
265 {
266     /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
267     portDISABLE_INTERRUPTS();
268
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. */
272     ulCriticalNesting++;
273 }
274 /*-----------------------------------------------------------*/
275
276 /*
277  * Decrement the critical nesting count, and if it has reached zero, re-enable
278  * interrupts.
279  */
280 void vPortExitCritical( void )
281 {
282     if( ulCriticalNesting > 0 )
283     {
284         /* Decrement the nesting count as we are leaving a critical section. */
285         ulCriticalNesting--;
286
287         /* If the nesting level has reached zero then interrupts should be
288          * re-enabled. */
289         if( ulCriticalNesting == 0 )
290         {
291             /* Enable interrupts as per portENABLE_INTERRUPTS(). */
292             portENABLE_INTERRUPTS();
293         }
294     }
295 }
296 /*-----------------------------------------------------------*/
297
298 #if __TI_VFP_SUPPORT__
299
300     void vPortTaskUsesFPU( void )
301     {
302         extern void vPortInitialiseFPSCR( void );
303
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;
307
308         /* Initialise the floating point status register. */
309         vPortInitialiseFPSCR();
310     }
311
312 #endif /* __TI_VFP_SUPPORT__ */
313
314 /*-----------------------------------------------------------*/