]> git.sur5r.net Git - freertos/blob - Source/portable/RVDS/ARM_CM3/port.c
Updated version numbers to V4.1.3.
[freertos] / Source / portable / RVDS / ARM_CM3 / port.c
1 /*\r
2         FreeRTOS.org V4.1.3 - Copyright (C) 2003-2006 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS.org is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS.org; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS.org, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section \r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27         See http://www.FreeRTOS.org for documentation, latest information, license \r
28         and contact details.  Please ensure to read the configuration and relevant \r
29         port sections of the online documentation.\r
30         ***************************************************************************\r
31 */\r
32 \r
33 /*\r
34         Changes between V4.0.0 and V4.0.1\r
35 \r
36         + Reduced the code used to setup the initial stack frame.\r
37         + The kernel no longer has to install or handle the fault interrupt.\r
38 */\r
39 \r
40 /*-----------------------------------------------------------\r
41  * Implementation of functions defined in portable.h for the ARM CM3 port.\r
42  *----------------------------------------------------------*/\r
43 \r
44 /* Scheduler includes. */\r
45 #include "FreeRTOS.h"\r
46 #include "task.h"\r
47 \r
48 /* Constants required to manipulate the NVIC. */\r
49 #define portNVIC_SYSTICK_CTRL           ( ( volatile unsigned portLONG *) 0xe000e010 )\r
50 #define portNVIC_SYSTICK_LOAD           ( ( volatile unsigned portLONG *) 0xe000e014 )\r
51 #define portNVIC_INT_CTRL                       ( ( volatile unsigned portLONG *) 0xe000ed04 )\r
52 #define portNVIC_SYSPRI2                        ( ( volatile unsigned portLONG *) 0xe000ed20 )\r
53 #define portNVIC_SYSPRI1                        ( ( volatile unsigned portLONG *) 0xe000ed1c )\r
54 #define portNVIC_HARD_FAULT_STATUS      0xe000ed2c\r
55 #define portNVIC_FORCED_FAULT_BIT       0x40000000\r
56 #define portNVIC_SYSTICK_CLK            0x00000004\r
57 #define portNVIC_SYSTICK_INT            0x00000002\r
58 #define portNVIC_SYSTICK_ENABLE         0x00000001\r
59 #define portNVIC_PENDSVSET                      0x10000000\r
60 #define portNVIC_PENDSV_PRI                     0x00ff0000\r
61 #define portNVIC_SVCALL_PRI                     0xff000000\r
62 #define portNVIC_SYSTICK_PRI            0xff000000\r
63 \r
64 /* Constants required to set up the initial stack. */\r
65 #define portINITIAL_XPSR                        ( 0x01000000 )\r
66 \r
67 /* Each task maintains its own interrupt status in the critical nesting\r
68 variable. */\r
69 unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa;\r
70 \r
71 /* Constant hardware definitions to assist asm code. */\r
72 const unsigned long ulHardFaultStatus = portNVIC_HARD_FAULT_STATUS;\r
73 const unsigned long ulNVICIntCtrl = ( unsigned long ) 0xe000ed04;\r
74 const unsigned long ulForceFaultBit = portNVIC_FORCED_FAULT_BIT;\r
75 const unsigned long ulPendSVBit = portNVIC_PENDSVSET;\r
76 \r
77 /* \r
78  * Setup the timer to generate the tick interrupts.\r
79  */\r
80 static void prvSetupTimerInterrupt( void );\r
81 \r
82 /*\r
83  * Set the MSP/PSP to a known value.\r
84  */\r
85 void prvSetMSP( unsigned long ulValue );\r
86 void prvSetPSP( unsigned long ulValue );\r
87 \r
88 /*-----------------------------------------------------------*/\r
89 \r
90 /* \r
91  * See header file for description. \r
92  */\r
93 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
94 {\r
95         /* Simulate the stack frame as it would be created by a context switch\r
96         interrupt. */\r
97         *pxTopOfStack = portINITIAL_XPSR;       /* xPSR */\r
98         pxTopOfStack--;\r
99         *pxTopOfStack = ( portSTACK_TYPE ) pxCode;      /* PC */\r
100         pxTopOfStack--;\r
101         *pxTopOfStack = 0xfffffffd;     /* LR */\r
102         pxTopOfStack -= 5;      /* R12, R3, R2 and R1. */\r
103         *pxTopOfStack = ( portSTACK_TYPE ) pvParameters;        /* R0 */\r
104         pxTopOfStack -= 9;      /* R11, R10, R9, R8, R7, R6, R5 and R4. */\r
105         *pxTopOfStack = 0x00000000; /* uxCriticalNesting. */\r
106 \r
107         return pxTopOfStack;\r
108 }\r
109 /*-----------------------------------------------------------*/\r
110 \r
111 __asm void prvSetPSP( unsigned long ulValue )\r
112 {\r
113         PRESERVE8\r
114         msr psp, r0\r
115         bx lr;\r
116 }\r
117 /*-----------------------------------------------------------*/\r
118 \r
119 __asm void prvSetMSP( unsigned long ulValue )\r
120 {\r
121         PRESERVE8\r
122         msr msp, r0\r
123         bx lr;\r
124 }\r
125 /*-----------------------------------------------------------*/\r
126 \r
127 /* \r
128  * See header file for description. \r
129  */\r
130 portBASE_TYPE xPortStartScheduler( void )\r
131 {\r
132         /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
133         here already. */\r
134         prvSetupTimerInterrupt();\r
135 \r
136         /* Make PendSV, CallSV and SysTick the lowest priority interrupts. */\r
137         *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;\r
138         *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;\r
139         *(portNVIC_SYSPRI1) |= portNVIC_SVCALL_PRI;\r
140 \r
141         /* Start the first task. */\r
142         prvSetPSP( 0 );\r
143         prvSetMSP( *((unsigned portLONG *) 0 ) );\r
144         *(portNVIC_INT_CTRL) |= portNVIC_PENDSVSET;\r
145 \r
146         /* Enable interrupts */\r
147         portENABLE_INTERRUPTS();\r
148 \r
149         /* Should not get here! */\r
150         return 0;\r
151 }\r
152 /*-----------------------------------------------------------*/\r
153 \r
154 void vPortEndScheduler( void )\r
155 {\r
156         /* It is unlikely that the CM3 port will require this function as there\r
157         is nothing to return to.  */\r
158 }\r
159 /*-----------------------------------------------------------*/\r
160 \r
161 void vPortYieldFromISR( void )\r
162 {\r
163         /* Set a PendSV to request a context switch. */\r
164         *(portNVIC_INT_CTRL) |= portNVIC_PENDSVSET;     \r
165         portENABLE_INTERRUPTS();\r
166 }\r
167 /*-----------------------------------------------------------*/\r
168 \r
169 __asm void vPortDisableInterrupts( void )\r
170 {\r
171         PRESERVE8\r
172         cpsid i;\r
173         bx lr;\r
174 }\r
175 /*-----------------------------------------------------------*/\r
176 \r
177 __asm void vPortEnableInterrupts( void )\r
178 {\r
179         PRESERVE8\r
180         cpsie i;\r
181         bx lr;\r
182 }\r
183 /*-----------------------------------------------------------*/\r
184 \r
185 void vPortEnterCritical( void )\r
186 {\r
187         vPortDisableInterrupts();\r
188         uxCriticalNesting++;\r
189 }\r
190 /*-----------------------------------------------------------*/\r
191 \r
192 void vPortExitCritical( void )\r
193 {\r
194         uxCriticalNesting--;\r
195         if( uxCriticalNesting == 0 )\r
196         {\r
197                 vPortEnableInterrupts();\r
198         }\r
199 }\r
200 /*-----------------------------------------------------------*/\r
201 \r
202 __asm void xPortPendSVHandler( void )\r
203 {\r
204         extern uxCriticalNesting;\r
205         extern pxCurrentTCB;\r
206         extern vTaskSwitchContext;\r
207 \r
208         PRESERVE8\r
209 \r
210         /* Start first task if the stack has not yet been setup. */\r
211         mrs r0, psp\r
212         cbz r0, no_save\r
213 \r
214         /* Save the context into the TCB. */\r
215         sub r0, #0x20\r
216         stm r0, {r4-r11}\r
217         sub r0, #0x04\r
218         ldr r1, =uxCriticalNesting\r
219         ldr r1, [r1]\r
220         stm r0, {r1}\r
221         ldr r1, =pxCurrentTCB\r
222         ldr r1, [r1]\r
223         str r0, [r1]\r
224 \r
225 no_save;\r
226         \r
227         /* Find the task to execute. */\r
228         ldr r0, =vTaskSwitchContext\r
229         push {r14}\r
230         cpsid i\r
231         blx r0\r
232         cpsie i\r
233         pop {r14}       \r
234 \r
235         /* Restore the context. */\r
236         ldr r1, =pxCurrentTCB\r
237         ldr r1, [r1];\r
238         ldr r0, [r1];\r
239         ldm r0, {r1, r4-r11}\r
240         ldr r2, =uxCriticalNesting\r
241         str r1, [r2]\r
242         ldr r2, [r2]\r
243         add r0, #0x24\r
244         msr psp, r0\r
245         orr r14, #0xd\r
246 \r
247         /* Exit with interrupts in the state required by the task. */\r
248         cbnz r2, sv_disable_interrupts\r
249         \r
250         bx r14\r
251 \r
252 sv_disable_interrupts;\r
253         cpsid i\r
254         bx r14\r
255 }\r
256 /*-----------------------------------------------------------*/\r
257 \r
258 __asm void xPortSysTickHandler( void )\r
259 {\r
260         extern vTaskIncrementTick\r
261         PRESERVE8\r
262 \r
263         /* Call the scheduler tick function. */\r
264         ldr r0, =vTaskIncrementTick\r
265         push {r14}\r
266         cpsid i\r
267         blx r0\r
268         cpsie i\r
269         pop {r14}       \r
270 \r
271         /* If using preemption, also force a context switch. */\r
272         #if configUSE_PREEMPTION == 1\r
273         extern vPortYieldFromISR\r
274                 push {r14}\r
275                 ldr r0, =vPortYieldFromISR\r
276                 blx r0\r
277                 pop {r14}\r
278         #endif\r
279 \r
280         /* Exit with interrupts in the correct state. */\r
281         ldr r2, =uxCriticalNesting\r
282         ldr r2, [r2]\r
283         cbnz r2, tick_disable_interrupts\r
284 \r
285         bx r14\r
286 \r
287 tick_disable_interrupts;\r
288         cpsid i\r
289         bx r14\r
290 }\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 /*\r
294  * Setup the systick timer to generate the tick interrupts at the required\r
295  * frequency.\r
296  */\r
297 void prvSetupTimerInterrupt( void )\r
298 {\r
299         /* Configure SysTick to interrupt at the requested rate. */\r
300         *(portNVIC_SYSTICK_LOAD) = configCPU_CLOCK_HZ / configTICK_RATE_HZ;\r
301         *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;\r
302 }\r
303 \r
304 \r