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