2 FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\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
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\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
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
54 /*-----------------------------------------------------------
\r
55 * Implementation of functions defined in portable.h for the ST STR91x ARM9
\r
57 *----------------------------------------------------------*/
\r
59 /* Library includes. */
\r
60 #include "91x_lib.h"
\r
62 /* Standard includes. */
\r
66 /* Scheduler includes. */
\r
67 #include "FreeRTOS.h"
\r
70 #ifndef configUSE_WATCHDOG_TICK
\r
71 #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
74 /* Constants required to setup the initial stack. */
\r
75 #ifndef _RUN_TASK_IN_ARM_MODE_
\r
76 #define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
\r
78 #define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
\r
81 #define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 4 )
\r
83 /* Constants required to handle critical sections. */
\r
84 #define portNO_CRITICAL_NESTING ( ( unsigned long ) 0 )
\r
87 #define abs(x) ((x)>0 ? (x) : -(x))
\r
91 * Toggle a led using the following algorithm:
\r
92 * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
\r
94 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
98 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
102 #define TOGGLE_LED(port,pin) \
\r
103 if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET ) \
\r
105 (port)->DR[(pin) <<2] = 0x00; \
\r
109 (port)->DR[(pin) <<2] = (pin); \
\r
113 /*-----------------------------------------------------------*/
\r
115 /* Setup the watchdog to generate the tick interrupts. */
\r
116 static void prvSetupTimerInterrupt( void );
\r
118 /* ulCriticalNesting will get set to zero when the first task starts. It
\r
119 cannot be initialised to 0 as this will cause interrupts to be enabled
\r
120 during the kernel initialisation process. */
\r
121 unsigned long ulCriticalNesting = ( unsigned long ) 9999;
\r
123 /* Tick interrupt routines for cooperative and preemptive operation
\r
124 respectively. The preemptive version is not defined as __irq as it is called
\r
125 from an asm wrapper function. */
\r
126 void WDG_IRQHandler( void );
\r
128 /* VIC interrupt default handler. */
\r
129 static void prvDefaultHandler( void );
\r
131 #if configUSE_WATCHDOG_TICK == 0
\r
132 /* Used to update the OCR timer register */
\r
133 static u16 s_nPulseLength;
\r
136 /*-----------------------------------------------------------*/
\r
139 * Initialise the stack of a task to look exactly as if a call to
\r
140 * portSAVE_CONTEXT had been called.
\r
142 * See header file for description.
\r
144 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
146 portSTACK_TYPE *pxOriginalTOS;
\r
148 pxOriginalTOS = pxTopOfStack;
\r
150 /* To ensure asserts in tasks.c don't fail, although in this case the assert
\r
151 is not really required. */
\r
154 /* Setup the initial stack of the task. The stack is set exactly as
\r
155 expected by the portRESTORE_CONTEXT() macro. */
\r
157 /* First on the stack is the return address - which in this case is the
\r
158 start of the task. The offset is added to make the return address appear
\r
159 as it would within an IRQ ISR. */
\r
160 *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
\r
163 *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
\r
165 *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
\r
167 *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
\r
169 *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
\r
171 *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
\r
173 *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
\r
175 *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
\r
177 *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
\r
179 *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
\r
181 *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
\r
183 *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
\r
185 *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
\r
187 *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
\r
189 *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
\r
192 /* When the task starts is will expect to find the function parameter in
\r
194 *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
\r
197 /* The status register is set for system mode, with interrupts enabled. */
\r
198 *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
\r
201 /* Interrupt flags cannot always be stored on the stack and will
\r
202 instead be stored in a variable, which is then saved as part of the
\r
204 *pxTopOfStack = portNO_CRITICAL_NESTING;
\r
206 return pxTopOfStack;
\r
208 /*-----------------------------------------------------------*/
\r
210 portBASE_TYPE xPortStartScheduler( void )
\r
212 extern void vPortStartFirstTask( void );
\r
214 /* Start the timer that generates the tick ISR. Interrupts are disabled
\r
216 prvSetupTimerInterrupt();
\r
218 /* Start the first task. */
\r
219 vPortStartFirstTask();
\r
221 /* Should not get here! */
\r
224 /*-----------------------------------------------------------*/
\r
226 void vPortEndScheduler( void )
\r
228 /* It is unlikely that the ARM port will require this function as there
\r
229 is nothing to return to. */
\r
231 /*-----------------------------------------------------------*/
\r
233 /* This function is called from an asm wrapper, so does not require the __irq
\r
235 #if configUSE_WATCHDOG_TICK == 1
\r
237 static void prvFindFactors(u32 n, u16 *a, u32 *b)
\r
239 /* This function is copied from the ST STR7 library and is
\r
240 copyright STMicroelectronics. Reproduced with permission. */
\r
244 long err, err_min=n;
\r
246 *a = a0 = ((n-1)/65536ul) + 1;
\r
249 for (; *a <= 256; (*a)++)
\r
252 err = (long)*a * (long)*b - (long)n;
\r
253 if (abs(err) > (*a / 2))
\r
256 err = (long)*a * (long)*b - (long)n;
\r
258 if (abs(err) < abs(err_min))
\r
263 if (err == 0) break;
\r
270 /*-----------------------------------------------------------*/
\r
272 static void prvSetupTimerInterrupt( void )
\r
274 WDG_InitTypeDef xWdg;
\r
276 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
\r
278 /* Configure the watchdog as a free running timer that generates a
\r
279 periodic interrupt. */
\r
281 SCU_APBPeriphClockConfig( __WDG, ENABLE );
\r
283 WDG_StructInit(&xWdg);
\r
284 prvFindFactors( n, &a, &b );
\r
285 xWdg.WDG_Prescaler = a - 1;
\r
286 xWdg.WDG_Preload = b - 1;
\r
288 WDG_ITConfig(ENABLE);
\r
290 /* Configure the VIC for the WDG interrupt. */
\r
291 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );
\r
292 VIC_ITCmd( WDG_ITLine, ENABLE );
\r
294 /* Install the default handlers for both VIC's. */
\r
295 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;
\r
296 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;
\r
300 /*-----------------------------------------------------------*/
\r
302 void WDG_IRQHandler( void )
\r
305 /* Increment the tick counter. */
\r
306 vTaskIncrementTick();
\r
308 #if configUSE_PREEMPTION == 1
\r
310 /* The new tick value might unblock a task. Ensure the highest task that
\r
311 is ready to execute is the task that will execute when the tick ISR
\r
313 vTaskSwitchContext();
\r
315 #endif /* configUSE_PREEMPTION. */
\r
317 /* Clear the interrupt in the watchdog. */
\r
318 WDG->SR &= ~0x0001;
\r
324 static void prvFindFactors(u32 n, u8 *a, u16 *b)
\r
326 /* This function is copied from the ST STR7 library and is
\r
327 copyright STMicroelectronics. Reproduced with permission. */
\r
331 long err, err_min=n;
\r
334 *a = a0 = ((n-1)/256) + 1;
\r
337 for (; *a <= 256; (*a)++)
\r
340 err = (long)*a * (long)*b - (long)n;
\r
341 if (abs(err) > (*a / 2))
\r
344 err = (long)*a * (long)*b - (long)n;
\r
346 if (abs(err) < abs(err_min))
\r
351 if (err == 0) break;
\r
358 /*-----------------------------------------------------------*/
\r
360 static void prvSetupTimerInterrupt( void )
\r
364 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
\r
366 TIM_InitTypeDef timer;
\r
368 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
\r
370 TIM_StructInit(&timer);
\r
371 prvFindFactors( n, &a, &b );
\r
373 timer.TIM_Mode = TIM_OCM_CHANNEL_1;
\r
374 timer.TIM_OC1_Modes = TIM_TIMING;
\r
375 timer.TIM_Clock_Source = TIM_CLK_APB;
\r
376 timer.TIM_Clock_Edge = TIM_CLK_EDGE_RISING;
\r
377 timer.TIM_Prescaler = a-1;
\r
378 timer.TIM_Pulse_Level_1 = TIM_HIGH;
\r
379 timer.TIM_Pulse_Length_1 = s_nPulseLength = b-1;
\r
381 TIM_Init (TIM2, &timer);
\r
382 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);
\r
383 /* Configure the VIC for the WDG interrupt. */
\r
384 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );
\r
385 VIC_ITCmd( TIM2_ITLine, ENABLE );
\r
387 /* Install the default handlers for both VIC's. */
\r
388 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;
\r
389 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;
\r
391 TIM_CounterCmd(TIM2, TIM_CLEAR);
\r
392 TIM_CounterCmd(TIM2, TIM_START);
\r
394 /*-----------------------------------------------------------*/
\r
396 void TIM2_IRQHandler( void )
\r
398 /* Reset the timer counter to avioid overflow. */
\r
399 TIM2->OC1R += s_nPulseLength;
\r
401 /* Increment the tick counter. */
\r
402 vTaskIncrementTick();
\r
404 #if configUSE_PREEMPTION == 1
\r
406 /* The new tick value might unblock a task. Ensure the highest task that
\r
407 is ready to execute is the task that will execute when the tick ISR
\r
409 vTaskSwitchContext();
\r
413 /* Clear the interrupt in the watchdog. */
\r
414 TIM2->SR &= ~TIM_FLAG_OC1;
\r
417 #endif /* USE_WATCHDOG_TICK */
\r
419 /*-----------------------------------------------------------*/
\r
421 __arm __interwork void vPortEnterCritical( void )
\r
423 /* Disable interrupts first! */
\r
424 portDISABLE_INTERRUPTS();
\r
426 /* Now interrupts are disabled ulCriticalNesting can be accessed
\r
427 directly. Increment ulCriticalNesting to keep a count of how many times
\r
428 portENTER_CRITICAL() has been called. */
\r
429 ulCriticalNesting++;
\r
431 /*-----------------------------------------------------------*/
\r
433 __arm __interwork void vPortExitCritical( void )
\r
435 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
437 /* Decrement the nesting count as we are leaving a critical section. */
\r
438 ulCriticalNesting--;
\r
440 /* If the nesting level has reached zero then interrupts should be
\r
442 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
\r
444 portENABLE_INTERRUPTS();
\r
448 /*-----------------------------------------------------------*/
\r
450 static void prvDefaultHandler( void )
\r