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