]> begriffs open source - freertos/blob - portable/IAR/AtmelSAM7S64/port.c
Remove "1 tab == 4 spaces!" line from files that still contain it.
[freertos] / portable / IAR / AtmelSAM7S64 / port.c
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\r
3  * Copyright (C) 2021 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.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * https://www.FreeRTOS.org\r
23  * https://github.com/FreeRTOS\r
24  *\r
25  */\r
26 \r
27 /*-----------------------------------------------------------\r
28  * Implementation of functions defined in portable.h for the Atmel ARM7 port.\r
29  *----------------------------------------------------------*/\r
30 \r
31 \r
32 /* Standard includes. */\r
33 #include <stdlib.h>\r
34 \r
35 /* Scheduler includes. */\r
36 #include "FreeRTOS.h"\r
37 #include "task.h"\r
38 \r
39 /* Constants required to setup the initial stack. */\r
40 #define portINITIAL_SPSR                                ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */\r
41 #define portTHUMB_MODE_BIT                              ( ( StackType_t ) 0x20 )\r
42 #define portINSTRUCTION_SIZE                    ( ( StackType_t ) 4 )\r
43 \r
44 /* Constants required to setup the PIT. */\r
45 #define portPIT_CLOCK_DIVISOR                   ( ( uint32_t ) 16 )\r
46 #define portPIT_COUNTER_VALUE                   ( ( ( configCPU_CLOCK_HZ / portPIT_CLOCK_DIVISOR ) / 1000UL ) * portTICK_PERIOD_MS )\r
47 \r
48 /* Constants required to handle critical sections. */\r
49 #define portNO_CRITICAL_NESTING                 ( ( uint32_t ) 0 )\r
50 \r
51 \r
52 #define portINT_LEVEL_SENSITIVE  0\r
53 #define portPIT_ENABLE          ( ( uint16_t ) 0x1 << 24 )\r
54 #define portPIT_INT_ENABLE      ( ( uint16_t ) 0x1 << 25 )\r
55 /*-----------------------------------------------------------*/\r
56 \r
57 /* Setup the PIT to generate the tick interrupts. */\r
58 static void prvSetupTimerInterrupt( void );\r
59 \r
60 /* ulCriticalNesting will get set to zero when the first task starts.  It\r
61 cannot be initialised to 0 as this will cause interrupts to be enabled\r
62 during the kernel initialisation process. */\r
63 uint32_t ulCriticalNesting = ( uint32_t ) 9999;\r
64 \r
65 /*-----------------------------------------------------------*/\r
66 \r
67 /*\r
68  * Initialise the stack of a task to look exactly as if a call to\r
69  * portSAVE_CONTEXT had been called.\r
70  *\r
71  * See header file for description.\r
72  */\r
73 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )\r
74 {\r
75 StackType_t *pxOriginalTOS;\r
76 \r
77         pxOriginalTOS = pxTopOfStack;\r
78 \r
79         /* To ensure asserts in tasks.c don't fail, although in this case the assert\r
80         is not really required. */\r
81         pxTopOfStack--;\r
82 \r
83         /* Setup the initial stack of the task.  The stack is set exactly as\r
84         expected by the portRESTORE_CONTEXT() macro. */\r
85 \r
86         /* First on the stack is the return address - which in this case is the\r
87         start of the task.  The offset is added to make the return address appear\r
88         as it would within an IRQ ISR. */\r
89         *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;          \r
90         pxTopOfStack--;\r
91 \r
92         *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa;     /* R14 */\r
93         pxTopOfStack--; \r
94         *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */\r
95         pxTopOfStack--;\r
96         *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */\r
97         pxTopOfStack--; \r
98         *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */\r
99         pxTopOfStack--; \r
100         *pxTopOfStack = ( StackType_t ) 0x10101010;     /* R10 */\r
101         pxTopOfStack--; \r
102         *pxTopOfStack = ( StackType_t ) 0x09090909;     /* R9 */\r
103         pxTopOfStack--; \r
104         *pxTopOfStack = ( StackType_t ) 0x08080808;     /* R8 */\r
105         pxTopOfStack--; \r
106         *pxTopOfStack = ( StackType_t ) 0x07070707;     /* R7 */\r
107         pxTopOfStack--; \r
108         *pxTopOfStack = ( StackType_t ) 0x06060606;     /* R6 */\r
109         pxTopOfStack--; \r
110         *pxTopOfStack = ( StackType_t ) 0x05050505;     /* R5 */\r
111         pxTopOfStack--; \r
112         *pxTopOfStack = ( StackType_t ) 0x04040404;     /* R4 */\r
113         pxTopOfStack--; \r
114         *pxTopOfStack = ( StackType_t ) 0x03030303;     /* R3 */\r
115         pxTopOfStack--; \r
116         *pxTopOfStack = ( StackType_t ) 0x02020202;     /* R2 */\r
117         pxTopOfStack--; \r
118         *pxTopOfStack = ( StackType_t ) 0x01010101;     /* R1 */\r
119         pxTopOfStack--; \r
120 \r
121         /* When the task starts is will expect to find the function parameter in\r
122         R0. */\r
123         *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
124         pxTopOfStack--;\r
125 \r
126         /* The status register is set for system mode, with interrupts enabled. */\r
127         *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;\r
128         \r
129         if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00UL )\r
130         {\r
131                 /* We want the task to start in thumb mode. */\r
132                 *pxTopOfStack |= portTHUMB_MODE_BIT;\r
133         }       \r
134         \r
135         pxTopOfStack--;\r
136 \r
137         /* Interrupt flags cannot always be stored on the stack and will\r
138         instead be stored in a variable, which is then saved as part of the\r
139         tasks context. */\r
140         *pxTopOfStack = portNO_CRITICAL_NESTING;\r
141 \r
142         return pxTopOfStack;    \r
143 }\r
144 /*-----------------------------------------------------------*/\r
145 \r
146 BaseType_t xPortStartScheduler( void )\r
147 {\r
148 extern void vPortStartFirstTask( void );\r
149 \r
150         /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
151         here already. */\r
152         prvSetupTimerInterrupt();\r
153 \r
154         /* Start the first task. */\r
155         vPortStartFirstTask();  \r
156 \r
157         /* Should not get here! */\r
158         return 0;\r
159 }\r
160 /*-----------------------------------------------------------*/\r
161 \r
162 void vPortEndScheduler( void )\r
163 {\r
164         /* It is unlikely that the ARM port will require this function as there\r
165         is nothing to return to.  */\r
166 }\r
167 /*-----------------------------------------------------------*/\r
168 \r
169 #if configUSE_PREEMPTION == 0\r
170 \r
171         /* The cooperative scheduler requires a normal IRQ service routine to\r
172         simply increment the system tick. */\r
173         static __arm __irq void vPortNonPreemptiveTick( void );\r
174         static __arm __irq void vPortNonPreemptiveTick( void )\r
175         {\r
176                 uint32_t ulDummy;\r
177                 \r
178                 /* Increment the tick count - which may wake some tasks but as the\r
179                 preemptive scheduler is not being used any woken task is not given\r
180                 processor time no matter what its priority. */\r
181                 xTaskIncrementTick();\r
182                 \r
183                 /* Clear the PIT interrupt. */\r
184                 ulDummy = AT91C_BASE_PITC->PITC_PIVR;\r
185                 \r
186                 /* End the interrupt in the AIC. */\r
187                 AT91C_BASE_AIC->AIC_EOICR = ulDummy;\r
188         }\r
189 \r
190 #else\r
191 \r
192         /* Currently the IAR port requires the preemptive tick function to be\r
193         defined in an asm file. */\r
194 \r
195 #endif\r
196 \r
197 /*-----------------------------------------------------------*/\r
198 \r
199 static void prvSetupTimerInterrupt( void )\r
200 {\r
201 AT91PS_PITC pxPIT = AT91C_BASE_PITC;\r
202 \r
203         /* Setup the AIC for PIT interrupts.  The interrupt routine chosen depends\r
204         on whether the preemptive or cooperative scheduler is being used. */\r
205         #if configUSE_PREEMPTION == 0\r
206 \r
207                 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_SYS, AT91C_AIC_PRIOR_HIGHEST, portINT_LEVEL_SENSITIVE, ( void (*)(void) ) vPortNonPreemptiveTick );\r
208 \r
209         #else\r
210                 \r
211                 extern void ( vPortPreemptiveTick )( void );\r
212                 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_SYS, AT91C_AIC_PRIOR_HIGHEST, portINT_LEVEL_SENSITIVE, ( void (*)(void) ) vPortPreemptiveTick );\r
213 \r
214         #endif\r
215 \r
216         /* Configure the PIT period. */\r
217         pxPIT->PITC_PIMR = portPIT_ENABLE | portPIT_INT_ENABLE | portPIT_COUNTER_VALUE;\r
218 \r
219         /* Enable the interrupt.  Global interrupts are disables at this point so\r
220         this is safe. */\r
221         AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_SYS );\r
222 }\r
223 /*-----------------------------------------------------------*/\r
224 \r
225 void vPortEnterCritical( void )\r
226 {\r
227         /* Disable interrupts first! */\r
228         __disable_interrupt();\r
229 \r
230         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
231         directly.  Increment ulCriticalNesting to keep a count of how many times\r
232         portENTER_CRITICAL() has been called. */\r
233         ulCriticalNesting++;\r
234 }\r
235 /*-----------------------------------------------------------*/\r
236 \r
237 void vPortExitCritical( void )\r
238 {\r
239         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
240         {\r
241                 /* Decrement the nesting count as we are leaving a critical section. */\r
242                 ulCriticalNesting--;\r
243 \r
244                 /* If the nesting level has reached zero then interrupts should be\r
245                 re-enabled. */\r
246                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
247                 {\r
248                         __enable_interrupt();\r
249                 }\r
250         }\r
251 }\r
252 /*-----------------------------------------------------------*/\r
253 \r
254 \r
255 \r
256 \r
257 \r
258 \r