]> git.sur5r.net Git - freertos/blob - Source/portable/IAR/STR91x/port.c
Modify the stack set up when ARM7/9 tasks are created to ensure the assert() calls...
[freertos] / Source / portable / IAR / STR91x / port.c
1 /*\r
2     FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
3         \r
4 \r
5     ***************************************************************************\r
6      *                                                                       *\r
7      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
8      *    Complete, revised, and edited pdf reference manuals are also       *\r
9      *    available.                                                         *\r
10      *                                                                       *\r
11      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
12      *    ensuring you get running as quickly as possible and with an        *\r
13      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
14      *    the FreeRTOS project to continue with its mission of providing     *\r
15      *    professional grade, cross platform, de facto standard solutions    *\r
16      *    for microcontrollers - completely free of charge!                  *\r
17      *                                                                       *\r
18      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
19      *                                                                       *\r
20      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
21      *                                                                       *\r
22     ***************************************************************************\r
23 \r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     >>>NOTE<<< The modification to the GPL is included to allow you to\r
31     distribute a combined work that includes FreeRTOS without being obliged to\r
32     provide the source code for proprietary components outside of the FreeRTOS\r
33     kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
34     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
35     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public\r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 /*-----------------------------------------------------------\r
55  * Implementation of functions defined in portable.h for the ST STR91x ARM9\r
56  * port.\r
57  *----------------------------------------------------------*/\r
58 \r
59 /* Library includes. */\r
60 #include "91x_lib.h"\r
61 \r
62 /* Standard includes. */\r
63 #include <stdlib.h>\r
64 #include <assert.h>\r
65 \r
66 /* Scheduler includes. */\r
67 #include "FreeRTOS.h"\r
68 #include "task.h"\r
69 \r
70 #ifndef configUSE_WATCHDOG_TICK\r
71         #error configUSE_WATCHDOG_TICK must be set to either 1 or 0 in FreeRTOSConfig.h to use either the Watchdog or timer 2 to generate the tick interrupt respectively.\r
72 #endif\r
73 \r
74 /* Constants required to setup the initial stack. */\r
75 #ifndef _RUN_TASK_IN_ARM_MODE_\r
76         #define portINITIAL_SPSR                        ( ( portSTACK_TYPE ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */\r
77 #else\r
78         #define portINITIAL_SPSR                        ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */\r
79 #endif\r
80 \r
81 #define portINSTRUCTION_SIZE                    ( ( portSTACK_TYPE ) 4 )\r
82 \r
83 /* Constants required to handle critical sections. */\r
84 #define portNO_CRITICAL_NESTING                 ( ( unsigned long ) 0 )\r
85 \r
86 #ifndef abs\r
87         #define abs(x) ((x)>0 ? (x) : -(x))\r
88 #endif\r
89 \r
90 /**\r
91  * Toggle a led using the following algorithm:\r
92  * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )\r
93  * {\r
94  *   GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );\r
95  * }\r
96  * else\r
97  * {\r
98  *   GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );\r
99  * }\r
100  *\r
101  */\r
102 #define TOGGLE_LED(port,pin)                                                                    \\r
103         if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET )          \\r
104         {                                                                                                                       \\r
105         (port)->DR[(pin) <<2] = 0x00;                                                   \\r
106         }                                                                                                                       \\r
107         else                                                                                                            \\r
108         {                                                                                                                       \\r
109         (port)->DR[(pin) <<2] = (pin);                                                  \\r
110         }\r
111 \r
112 \r
113 /*-----------------------------------------------------------*/\r
114 \r
115 /* Setup the watchdog to generate the tick interrupts. */\r
116 static void prvSetupTimerInterrupt( void );\r
117 \r
118 /* ulCriticalNesting will get set to zero when the first task starts.  It\r
119 cannot be initialised to 0 as this will cause interrupts to be enabled\r
120 during the kernel initialisation process. */\r
121 unsigned long ulCriticalNesting = ( unsigned long ) 9999;\r
122 \r
123 /* Tick interrupt routines for cooperative and preemptive operation\r
124 respectively.  The preemptive version is not defined as __irq as it is called\r
125 from an asm wrapper function. */\r
126 void WDG_IRQHandler( void );\r
127 \r
128 /* VIC interrupt default handler. */\r
129 static void prvDefaultHandler( void );\r
130 \r
131 #if configUSE_WATCHDOG_TICK == 0\r
132         /* Used to update the OCR timer register */\r
133         static u16 s_nPulseLength;\r
134 #endif\r
135 \r
136 /*-----------------------------------------------------------*/\r
137 \r
138 /*\r
139  * Initialise the stack of a task to look exactly as if a call to\r
140  * portSAVE_CONTEXT had been called.\r
141  *\r
142  * See header file for description.\r
143  */\r
144 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
145 {\r
146         portSTACK_TYPE *pxOriginalTOS;\r
147 \r
148         pxOriginalTOS = pxTopOfStack;\r
149 \r
150         /* To ensure asserts in tasks.c don't fail, although in this case the assert\r
151         is not really required. */\r
152         pxTopOfStack--;\r
153 \r
154         /* Setup the initial stack of the task.  The stack is set exactly as\r
155         expected by the portRESTORE_CONTEXT() macro. */\r
156 \r
157         /* First on the stack is the return address - which in this case is the\r
158         start of the task.  The offset is added to make the return address appear\r
159         as it would within an IRQ ISR. */\r
160         *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;               \r
161         pxTopOfStack--;\r
162 \r
163         *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa;  /* R14 */\r
164         pxTopOfStack--; \r
165         *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */\r
166         pxTopOfStack--;\r
167         *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212;  /* R12 */\r
168         pxTopOfStack--; \r
169         *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111;  /* R11 */\r
170         pxTopOfStack--; \r
171         *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010;  /* R10 */\r
172         pxTopOfStack--; \r
173         *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909;  /* R9 */\r
174         pxTopOfStack--; \r
175         *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808;  /* R8 */\r
176         pxTopOfStack--; \r
177         *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707;  /* R7 */\r
178         pxTopOfStack--; \r
179         *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606;  /* R6 */\r
180         pxTopOfStack--; \r
181         *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505;  /* R5 */\r
182         pxTopOfStack--; \r
183         *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404;  /* R4 */\r
184         pxTopOfStack--; \r
185         *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303;  /* R3 */\r
186         pxTopOfStack--; \r
187         *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202;  /* R2 */\r
188         pxTopOfStack--; \r
189         *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101;  /* R1 */\r
190         pxTopOfStack--; \r
191 \r
192         /* When the task starts is will expect to find the function parameter in\r
193         R0. */\r
194         *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */\r
195         pxTopOfStack--;\r
196 \r
197         /* The status register is set for system mode, with interrupts enabled. */\r
198         *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;\r
199         pxTopOfStack--;\r
200 \r
201         /* Interrupt flags cannot always be stored on the stack and will\r
202         instead be stored in a variable, which is then saved as part of the\r
203         tasks context. */\r
204         *pxTopOfStack = portNO_CRITICAL_NESTING;\r
205 \r
206         return pxTopOfStack;    \r
207 }\r
208 /*-----------------------------------------------------------*/\r
209 \r
210 portBASE_TYPE xPortStartScheduler( void )\r
211 {\r
212 extern void vPortStartFirstTask( void );\r
213 \r
214         /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
215         here already. */\r
216         prvSetupTimerInterrupt();\r
217 \r
218         /* Start the first task. */\r
219         vPortStartFirstTask();  \r
220 \r
221         /* Should not get here! */\r
222         return 0;\r
223 }\r
224 /*-----------------------------------------------------------*/\r
225 \r
226 void vPortEndScheduler( void )\r
227 {\r
228         /* It is unlikely that the ARM port will require this function as there\r
229         is nothing to return to.  */\r
230 }\r
231 /*-----------------------------------------------------------*/\r
232 \r
233 /* This function is called from an asm wrapper, so does not require the __irq\r
234 keyword. */\r
235 #if configUSE_WATCHDOG_TICK == 1\r
236 \r
237         static void prvFindFactors(u32 n, u16 *a, u32 *b)\r
238         {\r
239                 /* This function is copied from the ST STR7 library and is\r
240                 copyright STMicroelectronics.  Reproduced with permission. */\r
241         \r
242                 u32 b0;\r
243                 u16 a0;\r
244                 long err, err_min=n;\r
245         \r
246                 *a = a0 = ((n-1)/65536ul) + 1;\r
247                 *b = b0 = n / *a;\r
248         \r
249                 for (; *a <= 256; (*a)++)\r
250                 {\r
251                         *b = n / *a;\r
252                         err = (long)*a * (long)*b - (long)n;\r
253                         if (abs(err) > (*a / 2))\r
254                         {\r
255                                 (*b)++;\r
256                                 err = (long)*a * (long)*b - (long)n;\r
257                         }\r
258                         if (abs(err) < abs(err_min))\r
259                         {\r
260                                 err_min = err;\r
261                                 a0 = *a;\r
262                                 b0 = *b;\r
263                                 if (err == 0) break;\r
264                         }\r
265                 }\r
266         \r
267                 *a = a0;\r
268                 *b = b0;\r
269         }\r
270         /*-----------------------------------------------------------*/\r
271 \r
272         static void prvSetupTimerInterrupt( void )\r
273         {\r
274         WDG_InitTypeDef xWdg;\r
275         unsigned short a;\r
276         unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;\r
277         \r
278                 /* Configure the watchdog as a free running timer that generates a\r
279                 periodic interrupt. */\r
280         \r
281                 SCU_APBPeriphClockConfig( __WDG, ENABLE );\r
282                 WDG_DeInit();\r
283                 WDG_StructInit(&xWdg);\r
284                 prvFindFactors( n, &a, &b );\r
285                 xWdg.WDG_Prescaler = a - 1;\r
286                 xWdg.WDG_Preload = b - 1;\r
287                 WDG_Init( &xWdg );\r
288                 WDG_ITConfig(ENABLE);\r
289                 \r
290                 /* Configure the VIC for the WDG interrupt. */\r
291                 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );\r
292                 VIC_ITCmd( WDG_ITLine, ENABLE );\r
293                 \r
294                 /* Install the default handlers for both VIC's. */\r
295                 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;\r
296                 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;\r
297                 \r
298                 WDG_Cmd(ENABLE);\r
299         }\r
300         /*-----------------------------------------------------------*/\r
301 \r
302         void WDG_IRQHandler( void )\r
303         {\r
304                 {\r
305                         /* Increment the tick counter. */\r
306                         vTaskIncrementTick();\r
307                 \r
308                         #if configUSE_PREEMPTION == 1\r
309                         {\r
310                                 /* The new tick value might unblock a task.  Ensure the highest task that\r
311                                 is ready to execute is the task that will execute when the tick ISR\r
312                                 exits. */\r
313                                 vTaskSwitchContext();\r
314                         }\r
315                         #endif /* configUSE_PREEMPTION. */\r
316                 \r
317                         /* Clear the interrupt in the watchdog. */\r
318                         WDG->SR &= ~0x0001;\r
319                 }\r
320         }\r
321 \r
322 #else\r
323 \r
324         static void prvFindFactors(u32 n, u8 *a, u16 *b)\r
325         {\r
326                 /* This function is copied from the ST STR7 library and is\r
327                 copyright STMicroelectronics.  Reproduced with permission. */\r
328         \r
329                 u16 b0;\r
330                 u8 a0;\r
331                 long err, err_min=n;\r
332         \r
333         \r
334                 *a = a0 = ((n-1)/256) + 1;\r
335                 *b = b0 = n / *a;\r
336         \r
337                 for (; *a <= 256; (*a)++)\r
338                 {\r
339                         *b = n / *a;\r
340                         err = (long)*a * (long)*b - (long)n;\r
341                         if (abs(err) > (*a / 2))\r
342                         {\r
343                                 (*b)++;\r
344                                 err = (long)*a * (long)*b - (long)n;\r
345                         }\r
346                         if (abs(err) < abs(err_min))\r
347                         {\r
348                                 err_min = err;\r
349                                 a0 = *a;\r
350                                 b0 = *b;\r
351                                 if (err == 0) break;\r
352                         }\r
353                 }\r
354         \r
355                 *a = a0;\r
356                 *b = b0;\r
357         }\r
358         /*-----------------------------------------------------------*/\r
359 \r
360         static void prvSetupTimerInterrupt( void )\r
361         {\r
362                 unsigned char a;\r
363                 unsigned short b;\r
364                 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;\r
365                 \r
366                 TIM_InitTypeDef timer;\r
367                 \r
368                 SCU_APBPeriphClockConfig( __TIM23, ENABLE );\r
369                 TIM_DeInit(TIM2);\r
370                 TIM_StructInit(&timer);\r
371                 prvFindFactors( n, &a, &b );\r
372                 \r
373                 timer.TIM_Mode           = TIM_OCM_CHANNEL_1;\r
374                 timer.TIM_OC1_Modes      = TIM_TIMING;\r
375                 timer.TIM_Clock_Source   = TIM_CLK_APB;\r
376                 timer.TIM_Clock_Edge     = TIM_CLK_EDGE_RISING;\r
377                 timer.TIM_Prescaler      = a-1;\r
378                 timer.TIM_Pulse_Level_1  = TIM_HIGH;\r
379                 timer.TIM_Pulse_Length_1 = s_nPulseLength  = b-1;\r
380                 \r
381                 TIM_Init (TIM2, &timer);\r
382                 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);\r
383                 /* Configure the VIC for the WDG interrupt. */\r
384                 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );\r
385                 VIC_ITCmd( TIM2_ITLine, ENABLE );\r
386                 \r
387                 /* Install the default handlers for both VIC's. */\r
388                 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;\r
389                 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;\r
390                 \r
391                 TIM_CounterCmd(TIM2, TIM_CLEAR);\r
392                 TIM_CounterCmd(TIM2, TIM_START);\r
393         }\r
394         /*-----------------------------------------------------------*/\r
395 \r
396         void TIM2_IRQHandler( void )\r
397         {\r
398                 /* Reset the timer counter to avioid overflow. */\r
399                 TIM2->OC1R += s_nPulseLength;\r
400                 \r
401                 /* Increment the tick counter. */\r
402                 vTaskIncrementTick();\r
403                 \r
404                 #if configUSE_PREEMPTION == 1\r
405                 {\r
406                         /* The new tick value might unblock a task.  Ensure the highest task that\r
407                         is ready to execute is the task that will execute when the tick ISR\r
408                         exits. */\r
409                         vTaskSwitchContext();\r
410                 }\r
411                 #endif\r
412                 \r
413                 /* Clear the interrupt in the watchdog. */\r
414                 TIM2->SR &= ~TIM_FLAG_OC1;\r
415         }\r
416 \r
417 #endif /* USE_WATCHDOG_TICK */\r
418 \r
419 /*-----------------------------------------------------------*/\r
420 \r
421 __arm __interwork void vPortEnterCritical( void )\r
422 {\r
423         /* Disable interrupts first! */\r
424         portDISABLE_INTERRUPTS();\r
425 \r
426         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
427         directly.  Increment ulCriticalNesting to keep a count of how many times\r
428         portENTER_CRITICAL() has been called. */\r
429         ulCriticalNesting++;\r
430 }\r
431 /*-----------------------------------------------------------*/\r
432 \r
433 __arm __interwork void vPortExitCritical( void )\r
434 {\r
435         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
436         {\r
437                 /* Decrement the nesting count as we are leaving a critical section. */\r
438                 ulCriticalNesting--;\r
439 \r
440                 /* If the nesting level has reached zero then interrupts should be\r
441                 re-enabled. */\r
442                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
443                 {\r
444                         portENABLE_INTERRUPTS();\r
445                 }\r
446         }\r
447 }\r
448 /*-----------------------------------------------------------*/\r
449 \r
450 static void prvDefaultHandler( void )\r
451 {\r
452 }\r
453 \r
454 \r
455 \r
456 \r
457 \r