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