2 FreeRTOS V7.1.1 - Copyright (C) 2012 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 ***************************************************************************
\r
46 * Having a problem? Start by reading the FAQ "My application does *
\r
47 * not run, what could be wrong? *
\r
49 * http://www.FreeRTOS.org/FAQHelp.html *
\r
51 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, training, latest information,
\r
55 license and contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool.
\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
67 /*-----------------------------------------------------------
\r
68 * Implementation of functions defined in portable.h for the ST STR91x ARM9
\r
70 *----------------------------------------------------------*/
\r
72 /* Library includes. */
\r
73 #include "91x_lib.h"
\r
75 /* Standard includes. */
\r
79 /* Scheduler includes. */
\r
80 #include "FreeRTOS.h"
\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
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
91 #define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
\r
94 #define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 4 )
\r
96 /* Constants required to handle critical sections. */
\r
97 #define portNO_CRITICAL_NESTING ( ( unsigned long ) 0 )
\r
100 #define abs(x) ((x)>0 ? (x) : -(x))
\r
104 * Toggle a led using the following algorithm:
\r
105 * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
\r
107 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
111 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
115 #define TOGGLE_LED(port,pin) \
\r
116 if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET ) \
\r
118 (port)->DR[(pin) <<2] = 0x00; \
\r
122 (port)->DR[(pin) <<2] = (pin); \
\r
126 /*-----------------------------------------------------------*/
\r
128 /* Setup the watchdog to generate the tick interrupts. */
\r
129 static void prvSetupTimerInterrupt( void );
\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
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
141 /* VIC interrupt default handler. */
\r
142 static void prvDefaultHandler( void );
\r
144 #if configUSE_WATCHDOG_TICK == 0
\r
145 /* Used to update the OCR timer register */
\r
146 static u16 s_nPulseLength;
\r
149 /*-----------------------------------------------------------*/
\r
152 * Initialise the stack of a task to look exactly as if a call to
\r
153 * portSAVE_CONTEXT had been called.
\r
155 * See header file for description.
\r
157 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
159 portSTACK_TYPE *pxOriginalTOS;
\r
161 pxOriginalTOS = pxTopOfStack;
\r
163 /* To ensure asserts in tasks.c don't fail, although in this case the assert
\r
164 is not really required. */
\r
167 /* Setup the initial stack of the task. The stack is set exactly as
\r
168 expected by the portRESTORE_CONTEXT() macro. */
\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
176 *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
\r
178 *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
\r
180 *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
\r
182 *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
\r
184 *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
\r
186 *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
\r
188 *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
\r
190 *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
\r
192 *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
\r
194 *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
\r
196 *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
\r
198 *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
\r
200 *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
\r
202 *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
\r
205 /* When the task starts is will expect to find the function parameter in
\r
207 *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
\r
210 /* The status register is set for system mode, with interrupts enabled. */
\r
211 *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
\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
217 *pxTopOfStack = portNO_CRITICAL_NESTING;
\r
219 return pxTopOfStack;
\r
221 /*-----------------------------------------------------------*/
\r
223 portBASE_TYPE xPortStartScheduler( void )
\r
225 extern void vPortStartFirstTask( void );
\r
227 /* Start the timer that generates the tick ISR. Interrupts are disabled
\r
229 prvSetupTimerInterrupt();
\r
231 /* Start the first task. */
\r
232 vPortStartFirstTask();
\r
234 /* Should not get here! */
\r
237 /*-----------------------------------------------------------*/
\r
239 void vPortEndScheduler( void )
\r
241 /* It is unlikely that the ARM port will require this function as there
\r
242 is nothing to return to. */
\r
244 /*-----------------------------------------------------------*/
\r
246 /* This function is called from an asm wrapper, so does not require the __irq
\r
248 #if configUSE_WATCHDOG_TICK == 1
\r
250 static void prvFindFactors(u32 n, u16 *a, u32 *b)
\r
252 /* This function is copied from the ST STR7 library and is
\r
253 copyright STMicroelectronics. Reproduced with permission. */
\r
257 long err, err_min=n;
\r
259 *a = a0 = ((n-1)/65536ul) + 1;
\r
262 for (; *a <= 256; (*a)++)
\r
265 err = (long)*a * (long)*b - (long)n;
\r
266 if (abs(err) > (*a / 2))
\r
269 err = (long)*a * (long)*b - (long)n;
\r
271 if (abs(err) < abs(err_min))
\r
276 if (err == 0) break;
\r
283 /*-----------------------------------------------------------*/
\r
285 static void prvSetupTimerInterrupt( void )
\r
287 WDG_InitTypeDef xWdg;
\r
289 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
\r
291 /* Configure the watchdog as a free running timer that generates a
\r
292 periodic interrupt. */
\r
294 SCU_APBPeriphClockConfig( __WDG, ENABLE );
\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
301 WDG_ITConfig(ENABLE);
\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
307 /* Install the default handlers for both VIC's. */
\r
308 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;
\r
309 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;
\r
313 /*-----------------------------------------------------------*/
\r
315 void WDG_IRQHandler( void )
\r
318 /* Increment the tick counter. */
\r
319 vTaskIncrementTick();
\r
321 #if configUSE_PREEMPTION == 1
\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
326 vTaskSwitchContext();
\r
328 #endif /* configUSE_PREEMPTION. */
\r
330 /* Clear the interrupt in the watchdog. */
\r
331 WDG->SR &= ~0x0001;
\r
337 static void prvFindFactors(u32 n, u8 *a, u16 *b)
\r
339 /* This function is copied from the ST STR7 library and is
\r
340 copyright STMicroelectronics. Reproduced with permission. */
\r
344 long err, err_min=n;
\r
347 *a = a0 = ((n-1)/256) + 1;
\r
350 for (; *a <= 256; (*a)++)
\r
353 err = (long)*a * (long)*b - (long)n;
\r
354 if (abs(err) > (*a / 2))
\r
357 err = (long)*a * (long)*b - (long)n;
\r
359 if (abs(err) < abs(err_min))
\r
364 if (err == 0) break;
\r
371 /*-----------------------------------------------------------*/
\r
373 static void prvSetupTimerInterrupt( void )
\r
377 unsigned long n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
\r
379 TIM_InitTypeDef timer;
\r
381 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
\r
383 TIM_StructInit(&timer);
\r
384 prvFindFactors( n, &a, &b );
\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
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
400 /* Install the default handlers for both VIC's. */
\r
401 VIC0->DVAR = ( unsigned long ) prvDefaultHandler;
\r
402 VIC1->DVAR = ( unsigned long ) prvDefaultHandler;
\r
404 TIM_CounterCmd(TIM2, TIM_CLEAR);
\r
405 TIM_CounterCmd(TIM2, TIM_START);
\r
407 /*-----------------------------------------------------------*/
\r
409 void TIM2_IRQHandler( void )
\r
411 /* Reset the timer counter to avioid overflow. */
\r
412 TIM2->OC1R += s_nPulseLength;
\r
414 /* Increment the tick counter. */
\r
415 vTaskIncrementTick();
\r
417 #if configUSE_PREEMPTION == 1
\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
422 vTaskSwitchContext();
\r
426 /* Clear the interrupt in the watchdog. */
\r
427 TIM2->SR &= ~TIM_FLAG_OC1;
\r
430 #endif /* USE_WATCHDOG_TICK */
\r
432 /*-----------------------------------------------------------*/
\r
434 __arm __interwork void vPortEnterCritical( void )
\r
436 /* Disable interrupts first! */
\r
437 portDISABLE_INTERRUPTS();
\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
444 /*-----------------------------------------------------------*/
\r
446 __arm __interwork void vPortExitCritical( void )
\r
448 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
450 /* Decrement the nesting count as we are leaving a critical section. */
\r
451 ulCriticalNesting--;
\r
453 /* If the nesting level has reached zero then interrupts should be
\r
455 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
\r
457 portENABLE_INTERRUPTS();
\r
461 /*-----------------------------------------------------------*/
\r
463 static void prvDefaultHandler( void )
\r