]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/GCC/ARM7_AT91FR40008/port.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS / Source / portable / GCC / ARM7_AT91FR40008 / port.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\r
3  * Copyright (C) 2020 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  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 /*-----------------------------------------------------------\r
30  * Implementation of functions defined in portable.h for the Atmel AT91R40008\r
31  * port.\r
32  *\r
33  * Components that can be compiled to either ARM or THUMB mode are\r
34  * contained in this file.  The ISR routines, which can only be compiled\r
35  * to ARM mode are contained in portISR.c.\r
36  *----------------------------------------------------------*/\r
37 \r
38 /* Standard includes. */\r
39 #include <stdlib.h>\r
40 \r
41 /* Scheduler includes. */\r
42 #include "FreeRTOS.h"\r
43 #include "task.h"\r
44 \r
45 /* Hardware specific definitions. */\r
46 #include "AT91R40008.h"\r
47 #include "pio.h"\r
48 #include "aic.h"\r
49 #include "tc.h"\r
50 \r
51 /* Constants required to setup the task context. */\r
52 #define portINITIAL_SPSR                                ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */\r
53 #define portTHUMB_MODE_BIT                              ( ( StackType_t ) 0x20 )\r
54 #define portINSTRUCTION_SIZE                    ( ( StackType_t ) 4 )\r
55 #define portNO_CRITICAL_SECTION_NESTING ( ( StackType_t ) 0 )\r
56 #define portTICK_PRIORITY_6                             ( 6 )\r
57 /*-----------------------------------------------------------*/\r
58 \r
59 /* Setup the timer to generate the tick interrupts. */\r
60 static void prvSetupTimerInterrupt( void );\r
61 \r
62 /* \r
63  * The scheduler can only be started from ARM mode, so \r
64  * vPortISRStartFirstSTask() is defined in portISR.c. \r
65  */\r
66 extern void vPortISRStartFirstTask( void );\r
67 \r
68 /*-----------------------------------------------------------*/\r
69 \r
70 /* \r
71  * Initialise the stack of a task to look exactly as if a call to \r
72  * portSAVE_CONTEXT had been called.\r
73  *\r
74  * See header file for description. \r
75  */\r
76 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )\r
77 {\r
78 StackType_t *pxOriginalTOS;\r
79 \r
80         pxOriginalTOS = pxTopOfStack;\r
81         \r
82         /* To ensure asserts in tasks.c don't fail, although in this case the assert\r
83         is not really required. */\r
84         pxTopOfStack--;\r
85 \r
86         /* Setup the initial stack of the task.  The stack is set exactly as \r
87         expected by the portRESTORE_CONTEXT() macro. */\r
88 \r
89         /* First on the stack is the return address - which in this case is the\r
90         start of the task.  The offset is added to make the return address appear\r
91         as it would within an IRQ ISR. */\r
92         *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;          \r
93         pxTopOfStack--;\r
94 \r
95         *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa;     /* R14 */\r
96         pxTopOfStack--; \r
97         *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */\r
98         pxTopOfStack--;\r
99         *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */\r
100         pxTopOfStack--; \r
101         *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */\r
102         pxTopOfStack--; \r
103         *pxTopOfStack = ( StackType_t ) 0x10101010;     /* R10 */\r
104         pxTopOfStack--; \r
105         *pxTopOfStack = ( StackType_t ) 0x09090909;     /* R9 */\r
106         pxTopOfStack--; \r
107         *pxTopOfStack = ( StackType_t ) 0x08080808;     /* R8 */\r
108         pxTopOfStack--; \r
109         *pxTopOfStack = ( StackType_t ) 0x07070707;     /* R7 */\r
110         pxTopOfStack--; \r
111         *pxTopOfStack = ( StackType_t ) 0x06060606;     /* R6 */\r
112         pxTopOfStack--; \r
113         *pxTopOfStack = ( StackType_t ) 0x05050505;     /* R5 */\r
114         pxTopOfStack--; \r
115         *pxTopOfStack = ( StackType_t ) 0x04040404;     /* R4 */\r
116         pxTopOfStack--; \r
117         *pxTopOfStack = ( StackType_t ) 0x03030303;     /* R3 */\r
118         pxTopOfStack--; \r
119         *pxTopOfStack = ( StackType_t ) 0x02020202;     /* R2 */\r
120         pxTopOfStack--; \r
121         *pxTopOfStack = ( StackType_t ) 0x01010101;     /* R1 */\r
122         pxTopOfStack--; \r
123 \r
124         /* When the task starts is will expect to find the function parameter in\r
125         R0. */\r
126         *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
127         pxTopOfStack--;\r
128 \r
129         /* The last thing onto the stack is the status register, which is set for\r
130         system mode, with interrupts enabled. */\r
131         *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;\r
132 \r
133         #ifdef THUMB_INTERWORK\r
134         {\r
135                 /* We want the task to start in thumb mode. */\r
136                 *pxTopOfStack |= portTHUMB_MODE_BIT;\r
137         }\r
138         #endif\r
139 \r
140         pxTopOfStack--;\r
141 \r
142         /* Some optimisation levels use the stack differently to others.  This \r
143         means the interrupt flags cannot always be stored on the stack and will\r
144         instead be stored in a variable, which is then saved as part of the\r
145         tasks context. */\r
146         *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;\r
147 \r
148         return pxTopOfStack;\r
149 }\r
150 /*-----------------------------------------------------------*/\r
151 \r
152 BaseType_t xPortStartScheduler( void )\r
153 {\r
154         /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
155         here already. */\r
156         prvSetupTimerInterrupt();\r
157 \r
158         /* Start the first task. */\r
159         vPortISRStartFirstTask();       \r
160 \r
161         /* Should not get here! */\r
162         return 0;\r
163 }\r
164 /*-----------------------------------------------------------*/\r
165 \r
166 void vPortEndScheduler( void )\r
167 {\r
168         /* It is unlikely that the ARM port will require this function as there\r
169         is nothing to return to.  */\r
170 }\r
171 /*-----------------------------------------------------------*/\r
172 \r
173 /*\r
174  * Setup the tick timer to generate the tick interrupts at the required frequency.\r
175  */\r
176 static void prvSetupTimerInterrupt( void )\r
177 {\r
178 volatile uint32_t ulDummy;\r
179 \r
180         /* Enable clock to the tick timer... */\r
181         AT91C_BASE_PS->PS_PCER = portTIMER_CLK_ENABLE_BIT;\r
182 \r
183         /* Stop the tick timer... */\r
184         portTIMER_REG_BASE_PTR->TC_CCR = TC_CLKDIS;\r
185 \r
186         /* Start with tick timer interrupts disabled... */\r
187         portTIMER_REG_BASE_PTR->TC_IDR = 0xFFFFFFFF;\r
188 \r
189         /* Clear any pending tick timer interrupts... */\r
190         ulDummy = portTIMER_REG_BASE_PTR->TC_SR;\r
191 \r
192         /* Store interrupt handler function address in tick timer vector register...\r
193         The ISR installed depends on whether the preemptive or cooperative\r
194         scheduler is being used. */\r
195         #if configUSE_PREEMPTION == 1\r
196         {\r
197                 extern void ( vPreemptiveTick )( void );\r
198                 AT91C_BASE_AIC->AIC_SVR[portTIMER_AIC_CHANNEL] = ( uint32_t ) vPreemptiveTick;\r
199         }\r
200         #else  // else use cooperative scheduler\r
201         {\r
202                 extern void ( vNonPreemptiveTick )( void );\r
203                 AT91C_BASE_AIC->AIC_SVR[portTIMER_AIC_CHANNEL] = ( uint32_t ) vNonPreemptiveTick;\r
204         }\r
205         #endif\r
206 \r
207         /* Tick timer interrupt level-sensitive, priority 6... */\r
208         AT91C_BASE_AIC->AIC_SMR[ portTIMER_AIC_CHANNEL ] = AIC_SRCTYPE_INT_LEVEL_SENSITIVE | portTICK_PRIORITY_6;\r
209 \r
210         /* Enable the tick timer interrupt...\r
211 \r
212         First at timer level */\r
213         portTIMER_REG_BASE_PTR->TC_IER = TC_CPCS;\r
214 \r
215         /* Then at the AIC level. */\r
216         AT91C_BASE_AIC->AIC_IECR = (1 << portTIMER_AIC_CHANNEL);\r
217 \r
218         /* Calculate timer compare value to achieve the desired tick rate... */\r
219         if( (configCPU_CLOCK_HZ / (configTICK_RATE_HZ * 2) ) <= 0xFFFF )\r
220         {\r
221                 /* The tick rate is fast enough for us to use the faster timer input\r
222                 clock (main clock / 2). */\r
223                 portTIMER_REG_BASE_PTR->TC_CMR = TC_WAVE | TC_CLKS_MCK2 | TC_BURST_NONE | TC_CPCTRG;\r
224                 portTIMER_REG_BASE_PTR->TC_RC  = configCPU_CLOCK_HZ / (configTICK_RATE_HZ * 2);\r
225         }\r
226         else\r
227         {\r
228                 /* We must use a slower timer input clock (main clock / 8) because the\r
229                 tick rate is too slow for the faster input clock. */\r
230                 portTIMER_REG_BASE_PTR->TC_CMR = TC_WAVE | TC_CLKS_MCK8 | TC_BURST_NONE | TC_CPCTRG;\r
231                 portTIMER_REG_BASE_PTR->TC_RC  = configCPU_CLOCK_HZ / (configTICK_RATE_HZ * 8);\r
232         }\r
233 \r
234         /* Start tick timer... */\r
235         portTIMER_REG_BASE_PTR->TC_CCR = TC_SWTRG | TC_CLKEN;\r
236 }\r
237 /*-----------------------------------------------------------*/\r
238 \r