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