]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/CCS/ARM_Cortex-R4/port.c
fca306b54a6e63c0c28e28e3e76d0474346a4673
[freertos] / FreeRTOS / Source / portable / CCS / ARM_Cortex-R4 / port.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* FreeRTOS includes. */\r
30 #include "FreeRTOS.h"\r
31 #include "task.h"\r
32 \r
33 /*-----------------------------------------------------------*/\r
34 \r
35 /* Count of the critical section nesting depth. */\r
36 uint32_t ulCriticalNesting = 9999;\r
37 \r
38 /*-----------------------------------------------------------*/\r
39 \r
40 /* Registers required to configure the RTI. */\r
41 #define portRTI_GCTRL_REG               ( * ( ( volatile uint32_t * ) 0xFFFFFC00 ) )\r
42 #define portRTI_TBCTRL_REG      ( * ( ( volatile uint32_t * ) 0xFFFFFC04 ) )\r
43 #define portRTI_COMPCTRL_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC0C ) )\r
44 #define portRTI_CNT0_FRC0_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC10 ) )\r
45 #define portRTI_CNT0_UC0_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC14 ) )\r
46 #define portRTI_CNT0_CPUC0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC18 ) )\r
47 #define portRTI_CNT0_COMP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC50 ) )\r
48 #define portRTI_CNT0_UDCP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC54 ) )\r
49 #define portRTI_SETINTENA_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC80 ) )\r
50 #define portRTI_CLEARINTENA_REG ( * ( ( volatile uint32_t * ) 0xFFFFFC84 ) )\r
51 #define portRTI_INTFLAG_REG     ( * ( ( volatile uint32_t * ) 0xFFFFFC88 ) )\r
52 \r
53 \r
54 /* Constants required to set up the initial stack of each task. */\r
55 #define portINITIAL_SPSR                ( ( StackType_t ) 0x1F )\r
56 #define portINITIAL_FPSCR               ( ( StackType_t ) 0x00 )\r
57 #define portINSTRUCTION_SIZE    ( ( StackType_t ) 0x04 )\r
58 #define portTHUMB_MODE_BIT              ( ( StackType_t ) 0x20 )\r
59 \r
60 /* The number of words on the stack frame between the saved Top Of Stack and\r
61 R0 (in which the parameters are passed. */\r
62 #define portSPACE_BETWEEN_TOS_AND_PARAMETERS    ( 12 )\r
63 \r
64 /*-----------------------------------------------------------*/\r
65 \r
66 /* vPortStartFirstSTask() is defined in portASM.asm */\r
67 extern void vPortStartFirstTask( void );\r
68 \r
69 /*-----------------------------------------------------------*/\r
70 \r
71 /* Saved as part of the task context.  Set to pdFALSE if the task does not\r
72 require an FPU context. */\r
73 uint32_t ulTaskHasFPUContext = 0;\r
74 \r
75 /*-----------------------------------------------------------*/\r
76 \r
77 \r
78 /*\r
79  * See header file for description.\r
80  */\r
81 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )\r
82 {\r
83 StackType_t *pxOriginalTOS;\r
84 \r
85         pxOriginalTOS = pxTopOfStack;\r
86 \r
87         #if __TI_VFP_SUPPORT__\r
88         {\r
89                 /* Ensure the stack is correctly aligned on exit. */\r
90                 pxTopOfStack--;\r
91         }\r
92         #endif\r
93 \r
94         /* Setup the initial stack of the task.  The stack is set exactly as\r
95         expected by the portRESTORE_CONTEXT() macro. */\r
96 \r
97         /* First on the stack is the return address - which is the start of the as\r
98         the task has not executed yet.  The offset is added to make the return\r
99         address appear as it would within an IRQ ISR. */\r
100         *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;\r
101         pxTopOfStack--;\r
102 \r
103         *pxTopOfStack = ( StackType_t ) 0x00000000;     /* R14 */\r
104         pxTopOfStack--;\r
105         *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */\r
106         pxTopOfStack--;\r
107 \r
108         #ifdef portPRELOAD_TASK_REGISTERS\r
109         {\r
110                 *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */\r
111                 pxTopOfStack--;\r
112                 *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */\r
113                 pxTopOfStack--;\r
114                 *pxTopOfStack = ( StackType_t ) 0x10101010;     /* R10 */\r
115                 pxTopOfStack--;\r
116                 *pxTopOfStack = ( StackType_t ) 0x09090909;     /* R9 */\r
117                 pxTopOfStack--;\r
118                 *pxTopOfStack = ( StackType_t ) 0x08080808;     /* R8 */\r
119                 pxTopOfStack--;\r
120                 *pxTopOfStack = ( StackType_t ) 0x07070707;     /* R7 */\r
121                 pxTopOfStack--;\r
122                 *pxTopOfStack = ( StackType_t ) 0x06060606;     /* R6 */\r
123                 pxTopOfStack--;\r
124                 *pxTopOfStack = ( StackType_t ) 0x05050505;     /* R5 */\r
125                 pxTopOfStack--;\r
126                 *pxTopOfStack = ( StackType_t ) 0x04040404;     /* R4 */\r
127                 pxTopOfStack--;\r
128                 *pxTopOfStack = ( StackType_t ) 0x03030303;     /* R3 */\r
129                 pxTopOfStack--;\r
130                 *pxTopOfStack = ( StackType_t ) 0x02020202;     /* R2 */\r
131                 pxTopOfStack--;\r
132                 *pxTopOfStack = ( StackType_t ) 0x01010101;     /* R1 */\r
133                 pxTopOfStack--;\r
134         }\r
135         #else\r
136         {\r
137                 pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS;\r
138         }\r
139         #endif\r
140 \r
141         /* Function parameters are passed in R0. */\r
142         *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
143         pxTopOfStack--;\r
144 \r
145         /* Set the status register for system mode, with interrupts enabled. */\r
146         *pxTopOfStack = ( StackType_t ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR );\r
147 \r
148         if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00 )\r
149         {\r
150                 /* The task will start in thumb mode. */\r
151                 *pxTopOfStack |= portTHUMB_MODE_BIT;\r
152         }\r
153 \r
154         #ifdef __TI_VFP_SUPPORT__\r
155         {\r
156                 pxTopOfStack--;\r
157 \r
158                 /* The last thing on the stack is the tasks ulUsingFPU value, which by\r
159                 default is set to indicate that the stack frame does not include FPU\r
160                 registers. */\r
161                 *pxTopOfStack = pdFALSE;\r
162         }\r
163         #endif\r
164 \r
165         return pxTopOfStack;\r
166 }\r
167 /*-----------------------------------------------------------*/\r
168 \r
169 static void prvSetupTimerInterrupt(void)\r
170 {\r
171         /* Disable timer 0. */\r
172         portRTI_GCTRL_REG &= 0xFFFFFFFEUL;\r
173 \r
174         /* Use the internal counter. */\r
175         portRTI_TBCTRL_REG = 0x00000000U;\r
176 \r
177         /* COMPSEL0 will use the RTIFRC0 counter. */\r
178         portRTI_COMPCTRL_REG = 0x00000000U;\r
179 \r
180         /* Initialise the counter and the prescale counter registers. */\r
181         portRTI_CNT0_UC0_REG =  0x00000000U;\r
182         portRTI_CNT0_FRC0_REG =  0x00000000U;\r
183 \r
184         /* Set Prescalar for RTI clock. */\r
185         portRTI_CNT0_CPUC0_REG = 0x00000001U;\r
186         portRTI_CNT0_COMP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;\r
187         portRTI_CNT0_UDCP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;\r
188 \r
189         /* Clear interrupts. */\r
190         portRTI_INTFLAG_REG =  0x0007000FU;\r
191         portRTI_CLEARINTENA_REG = 0x00070F0FU;\r
192 \r
193         /* Enable the compare 0 interrupt. */\r
194         portRTI_SETINTENA_REG = 0x00000001U;\r
195         portRTI_GCTRL_REG |= 0x00000001U;\r
196 }\r
197 /*-----------------------------------------------------------*/\r
198 \r
199 /*\r
200  * See header file for description.\r
201  */\r
202 BaseType_t xPortStartScheduler(void)\r
203 {\r
204         /* Start the timer that generates the tick ISR. */\r
205         prvSetupTimerInterrupt();\r
206 \r
207         /* Reset the critical section nesting count read to execute the first task. */\r
208         ulCriticalNesting = 0;\r
209 \r
210         /* Start the first task.  This is done from portASM.asm as ARM mode must be\r
211         used. */\r
212         vPortStartFirstTask();\r
213 \r
214         /* Should not get here! */\r
215         return pdFAIL;\r
216 }\r
217 /*-----------------------------------------------------------*/\r
218 \r
219 /*\r
220  * See header file for description.\r
221  */\r
222 void vPortEndScheduler(void)\r
223 {\r
224         /* Not implemented in ports where there is nothing to return to.\r
225         Artificially force an assert. */\r
226         configASSERT( ulCriticalNesting == 1000UL );\r
227 }\r
228 /*-----------------------------------------------------------*/\r
229 \r
230 #if configUSE_PREEMPTION == 0\r
231 \r
232         /* The cooperative scheduler requires a normal IRQ service routine to\r
233          * simply increment the system tick. */\r
234         __interrupt void vPortNonPreemptiveTick( void )\r
235         {\r
236                 /* clear clock interrupt flag */\r
237                 portRTI_INTFLAG_REG = 0x00000001;\r
238 \r
239                 /* Increment the tick count - this may make a delaying task ready\r
240                 to run - but a context switch is not performed. */\r
241                 xTaskIncrementTick();\r
242         }\r
243 \r
244  #else\r
245 \r
246         /*\r
247          **************************************************************************\r
248          * The preemptive scheduler ISR is written in assembler and can be found\r
249          * in the portASM.asm file. This will only get used if portUSE_PREEMPTION\r
250          * is set to 1 in portmacro.h\r
251          **************************************************************************\r
252          */\r
253         void vPortPreemptiveTick( void );\r
254 \r
255 #endif\r
256 /*-----------------------------------------------------------*/\r
257 \r
258 \r
259 /*\r
260  * Disable interrupts, and keep a count of the nesting depth.\r
261  */\r
262 void vPortEnterCritical( void )\r
263 {\r
264         /* Disable interrupts as per portDISABLE_INTERRUPTS(); */\r
265         portDISABLE_INTERRUPTS();\r
266 \r
267         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
268         directly.  Increment ulCriticalNesting to keep a count of how many times\r
269         portENTER_CRITICAL() has been called. */\r
270         ulCriticalNesting++;\r
271 }\r
272 /*-----------------------------------------------------------*/\r
273 \r
274 /*\r
275  * Decrement the critical nesting count, and if it has reached zero, re-enable\r
276  * interrupts.\r
277  */\r
278 void vPortExitCritical( void )\r
279 {\r
280         if( ulCriticalNesting > 0 )\r
281         {\r
282                 /* Decrement the nesting count as we are leaving a critical section. */\r
283                 ulCriticalNesting--;\r
284 \r
285                 /* If the nesting level has reached zero then interrupts should be\r
286                 re-enabled. */\r
287                 if( ulCriticalNesting == 0 )\r
288                 {\r
289                         /* Enable interrupts as per portENABLE_INTERRUPTS(). */\r
290                         portENABLE_INTERRUPTS();\r
291                 }\r
292         }\r
293 }\r
294 /*-----------------------------------------------------------*/\r
295 \r
296 #if __TI_VFP_SUPPORT__\r
297 \r
298         void vPortTaskUsesFPU( void )\r
299         {\r
300         extern void vPortInitialiseFPSCR( void );\r
301 \r
302                 /* A task is registering the fact that it needs an FPU context.  Set the\r
303                 FPU flag (saved as part of the task context. */\r
304                 ulTaskHasFPUContext = pdTRUE;\r
305 \r
306                 /* Initialise the floating point status register. */\r
307                 vPortInitialiseFPSCR();\r
308         }\r
309 \r
310 #endif /* __TI_VFP_SUPPORT__ */\r
311 \r
312 /*-----------------------------------------------------------*/\r
313 \r