]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/IAR/STR91x/port.c
Convert more ports to use xTaskIncrementTick() in place of vTaskIncrementTick().
[freertos] / FreeRTOS / Source / portable / IAR / STR91x / port.c
1 /*\r
2     FreeRTOS V7.4.2 - 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 it can 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                         if( xTaskIncrementTick() != pdFALSE )\r
328                         {               \r
329                                 /* Select a new task to execute. */\r
330                                 vTaskSwitchContext();\r
331                         }\r
332                 \r
333                         /* Clear the interrupt in the watchdog. */\r
334                         WDG->SR &= ~0x0001;\r
335                 }\r
336         }\r
337 \r
338 #else\r
339 \r
340         static void prvFindFactors(u32 n, u8 *a, u16 *b)\r
341         {\r
342                 /* This function is copied from the ST STR7 library and is\r
343                 copyright STMicroelectronics.  Reproduced with permission. */\r
344         \r
345                 u16 b0;\r
346                 u8 a0;\r
347                 long err, err_min=n;\r
348         \r
349         \r
350                 *a = a0 = ((n-1)/256) + 1;\r
351                 *b = b0 = n / *a;\r
352         \r
353                 for (; *a <= 256; (*a)++)\r
354                 {\r
355                         *b = n / *a;\r
356                         err = (long)*a * (long)*b - (long)n;\r
357                         if (abs(err) > (*a / 2))\r
358                         {\r
359                                 (*b)++;\r
360                                 err = (long)*a * (long)*b - (long)n;\r
361                         }\r
362                         if (abs(err) < abs(err_min))\r
363                         {\r
364                                 err_min = err;\r
365                                 a0 = *a;\r
366                                 b0 = *b;\r
367                                 if (err == 0) break;\r
368                         }\r
369                 }\r
370         \r
371                 *a = a0;\r
372                 *b = b0;\r
373         }\r
374         /*-----------------------------------------------------------*/\r
375 \r
376         static void prvSetupTimerInterrupt( void )\r
377         {\r
378                 unsigned char a;\r
379                 unsigned short b;\r
380                 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;\r
381                 \r
382                 TIM_InitTypeDef timer;\r
383                 \r
384                 SCU_APBPeriphClockConfig( __TIM23, ENABLE );\r
385                 TIM_DeInit(TIM2);\r
386                 TIM_StructInit(&timer);\r
387                 prvFindFactors( n, &a, &b );\r
388                 \r
389                 timer.TIM_Mode           = TIM_OCM_CHANNEL_1;\r
390                 timer.TIM_OC1_Modes      = TIM_TIMING;\r
391                 timer.TIM_Clock_Source   = TIM_CLK_APB;\r
392                 timer.TIM_Clock_Edge     = TIM_CLK_EDGE_RISING;\r
393                 timer.TIM_Prescaler      = a-1;\r
394                 timer.TIM_Pulse_Level_1  = TIM_HIGH;\r
395                 timer.TIM_Pulse_Length_1 = s_nPulseLength  = b-1;\r
396                 \r
397                 TIM_Init (TIM2, &timer);\r
398                 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);\r
399                 /* Configure the VIC for the WDG interrupt. */\r
400                 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );\r
401                 VIC_ITCmd( TIM2_ITLine, ENABLE );\r
402                 \r
403                 /* Install the default handlers for both VIC's. */\r
404                 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;\r
405                 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;\r
406                 \r
407                 TIM_CounterCmd(TIM2, TIM_CLEAR);\r
408                 TIM_CounterCmd(TIM2, TIM_START);\r
409         }\r
410         /*-----------------------------------------------------------*/\r
411 \r
412         void TIM2_IRQHandler( void )\r
413         {\r
414                 /* Reset the timer counter to avioid overflow. */\r
415                 TIM2->OC1R += s_nPulseLength;\r
416                 \r
417                 /* Increment the tick counter. */\r
418                 vTaskIncrementTick();\r
419                 \r
420                 #if configUSE_PREEMPTION == 1\r
421                 {\r
422                         /* The new tick value might unblock a task.  Ensure the highest task that\r
423                         is ready to execute is the task that will execute when the tick ISR\r
424                         exits. */\r
425                         vTaskSwitchContext();\r
426                 }\r
427                 #endif\r
428                 \r
429                 /* Clear the interrupt in the watchdog. */\r
430                 TIM2->SR &= ~TIM_FLAG_OC1;\r
431         }\r
432 \r
433 #endif /* USE_WATCHDOG_TICK */\r
434 \r
435 /*-----------------------------------------------------------*/\r
436 \r
437 __arm __interwork void vPortEnterCritical( void )\r
438 {\r
439         /* Disable interrupts first! */\r
440         portDISABLE_INTERRUPTS();\r
441 \r
442         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
443         directly.  Increment ulCriticalNesting to keep a count of how many times\r
444         portENTER_CRITICAL() has been called. */\r
445         ulCriticalNesting++;\r
446 }\r
447 /*-----------------------------------------------------------*/\r
448 \r
449 __arm __interwork void vPortExitCritical( void )\r
450 {\r
451         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
452         {\r
453                 /* Decrement the nesting count as we are leaving a critical section. */\r
454                 ulCriticalNesting--;\r
455 \r
456                 /* If the nesting level has reached zero then interrupts should be\r
457                 re-enabled. */\r
458                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
459                 {\r
460                         portENABLE_INTERRUPTS();\r
461                 }\r
462         }\r
463 }\r
464 /*-----------------------------------------------------------*/\r
465 \r
466 static void prvDefaultHandler( void )\r
467 {\r
468 }\r
469 \r
470 \r
471 \r
472 \r
473 \r