2 FreeRTOS.org V4.6.0 - Copyright (C) 2003-2007 Richard Barry.
\r
4 This file is part of the FreeRTOS distribution.
\r
6 FreeRTOS is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
36 /*-----------------------------------------------------------
\r
37 * Implementation of functions defined in portable.h for the ST STR91x ARM9
\r
39 *----------------------------------------------------------*/
\r
41 /* Library includes. */
\r
42 #include "91x_lib.h"
\r
44 /* Standard includes. */
\r
48 /* Scheduler includes. */
\r
49 #include "FreeRTOS.h"
\r
52 #ifndef configUSE_WATCHDOG_TICK
\r
53 #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
56 /* Constants required to setup the initial stack. */
\r
57 #ifndef _RUN_TASK_IN_ARM_MODE_
\r
58 #define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
\r
60 #define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
\r
63 #define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 4 )
\r
65 /* Constants required to handle critical sections. */
\r
66 #define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 )
\r
69 #define abs(x) ((x)>0 ? (x) : -(x))
\r
73 * Toggle a led using the following algorithm:
\r
74 * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
\r
76 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
80 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
\r
84 #define TOGGLE_LED(port,pin) \
\r
85 if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET ) \
\r
87 (port)->DR[(pin) <<2] = 0x00; \
\r
91 (port)->DR[(pin) <<2] = (pin); \
\r
95 /*-----------------------------------------------------------*/
\r
97 /* Setup the watchdog to generate the tick interrupts. */
\r
98 static void prvSetupTimerInterrupt( void );
\r
100 /* ulCriticalNesting will get set to zero when the first task starts. It
\r
101 cannot be initialised to 0 as this will cause interrupts to be enabled
\r
102 during the kernel initialisation process. */
\r
103 unsigned portLONG ulCriticalNesting = ( unsigned portLONG ) 9999;
\r
105 /* Tick interrupt routines for cooperative and preemptive operation
\r
106 respectively. The preemptive version is not defined as __irq as it is called
\r
107 from an asm wrapper function. */
\r
108 void WDG_IRQHandler( void );
\r
110 /* VIC interrupt default handler. */
\r
111 static void prvDefaultHandler( void );
\r
113 #if configUSE_WATCHDOG_TICK == 0
\r
114 /* Used to update the OCR timer register */
\r
115 static u16 s_nPulseLength;
\r
118 /*-----------------------------------------------------------*/
\r
121 * Initialise the stack of a task to look exactly as if a call to
\r
122 * portSAVE_CONTEXT had been called.
\r
124 * See header file for description.
\r
126 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
128 portSTACK_TYPE *pxOriginalTOS;
\r
130 pxOriginalTOS = pxTopOfStack;
\r
132 /* Setup the initial stack of the task. The stack is set exactly as
\r
133 expected by the portRESTORE_CONTEXT() macro. */
\r
135 /* First on the stack is the return address - which in this case is the
\r
136 start of the task. The offset is added to make the return address appear
\r
137 as it would within an IRQ ISR. */
\r
138 *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
\r
141 *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
\r
143 *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
\r
145 *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
\r
147 *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
\r
149 *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
\r
151 *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
\r
153 *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
\r
155 *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
\r
157 *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
\r
159 *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
\r
161 *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
\r
163 *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
\r
165 *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
\r
167 *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
\r
170 /* When the task starts is will expect to find the function parameter in
\r
172 *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
\r
175 /* The status register is set for system mode, with interrupts enabled. */
\r
176 *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
\r
179 /* Interrupt flags cannot always be stored on the stack and will
\r
180 instead be stored in a variable, which is then saved as part of the
\r
182 *pxTopOfStack = portNO_CRITICAL_NESTING;
\r
184 return pxTopOfStack;
\r
186 /*-----------------------------------------------------------*/
\r
188 portBASE_TYPE xPortStartScheduler( void )
\r
190 extern void vPortStartFirstTask( void );
\r
192 /* Start the timer that generates the tick ISR. Interrupts are disabled
\r
194 prvSetupTimerInterrupt();
\r
196 /* Start the first task. */
\r
197 vPortStartFirstTask();
\r
199 /* Should not get here! */
\r
202 /*-----------------------------------------------------------*/
\r
204 void vPortEndScheduler( void )
\r
206 /* It is unlikely that the ARM port will require this function as there
\r
207 is nothing to return to. */
\r
209 /*-----------------------------------------------------------*/
\r
211 /* This function is called from an asm wrapper, so does not require the __irq
\r
213 #if configUSE_WATCHDOG_TICK == 1
\r
215 static void prvFindFactors(u32 n, u16 *a, u32 *b)
\r
217 /* This function is copied from the ST STR7 library and is
\r
218 copyright STMicroelectronics. Reproduced with permission. */
\r
222 long err, err_min=n;
\r
224 *a = a0 = ((n-1)/65536ul) + 1;
\r
227 for (; *a <= 256; (*a)++)
\r
230 err = (long)*a * (long)*b - (long)n;
\r
231 if (abs(err) > (*a / 2))
\r
234 err = (long)*a * (long)*b - (long)n;
\r
236 if (abs(err) < abs(err_min))
\r
241 if (err == 0) break;
\r
248 /*-----------------------------------------------------------*/
\r
250 static void prvSetupTimerInterrupt( void )
\r
252 WDG_InitTypeDef xWdg;
\r
253 unsigned portSHORT a;
\r
254 unsigned portLONG n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
\r
256 /* Configure the watchdog as a free running timer that generates a
\r
257 periodic interrupt. */
\r
259 SCU_APBPeriphClockConfig( __WDG, ENABLE );
\r
261 WDG_StructInit(&xWdg);
\r
262 prvFindFactors( n, &a, &b );
\r
263 xWdg.WDG_Prescaler = a - 1;
\r
264 xWdg.WDG_Preload = b - 1;
\r
266 WDG_ITConfig(ENABLE);
\r
268 /* Configure the VIC for the WDG interrupt. */
\r
269 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );
\r
270 VIC_ITCmd( WDG_ITLine, ENABLE );
\r
272 /* Install the default handlers for both VIC's. */
\r
273 VIC0->DVAR = ( unsigned portLONG ) prvDefaultHandler;
\r
274 VIC1->DVAR = ( unsigned portLONG ) prvDefaultHandler;
\r
278 /*-----------------------------------------------------------*/
\r
280 void WDG_IRQHandler( void )
\r
283 /* Increment the tick counter. */
\r
284 vTaskIncrementTick();
\r
286 #if configUSE_PREEMPTION == 1
\r
288 /* The new tick value might unblock a task. Ensure the highest task that
\r
289 is ready to execute is the task that will execute when the tick ISR
\r
291 vTaskSwitchContext();
\r
293 #endif /* configUSE_PREEMPTION. */
\r
295 /* Clear the interrupt in the watchdog. */
\r
296 WDG->SR &= ~0x0001;
\r
302 static void prvFindFactors(u32 n, u8 *a, u16 *b)
\r
304 /* This function is copied from the ST STR7 library and is
\r
305 copyright STMicroelectronics. Reproduced with permission. */
\r
309 long err, err_min=n;
\r
312 *a = a0 = ((n-1)/256) + 1;
\r
315 for (; *a <= 256; (*a)++)
\r
318 err = (long)*a * (long)*b - (long)n;
\r
319 if (abs(err) > (*a / 2))
\r
322 err = (long)*a * (long)*b - (long)n;
\r
324 if (abs(err) < abs(err_min))
\r
329 if (err == 0) break;
\r
336 /*-----------------------------------------------------------*/
\r
338 static void prvSetupTimerInterrupt( void )
\r
340 unsigned portCHAR a;
\r
341 unsigned portSHORT b;
\r
342 unsigned portLONG n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
\r
344 TIM_InitTypeDef timer;
\r
346 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
\r
348 TIM_StructInit(&timer);
\r
349 prvFindFactors( n, &a, &b );
\r
351 timer.TIM_Mode = TIM_OCM_CHANNEL_1;
\r
352 timer.TIM_OC1_Modes = TIM_TIMING;
\r
353 timer.TIM_Clock_Source = TIM_CLK_APB;
\r
354 timer.TIM_Clock_Edge = TIM_CLK_EDGE_RISING;
\r
355 timer.TIM_Prescaler = a-1;
\r
356 timer.TIM_Pulse_Level_1 = TIM_HIGH;
\r
357 timer.TIM_Pulse_Length_1 = s_nPulseLength = b-1;
\r
359 TIM_Init (TIM2, &timer);
\r
360 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);
\r
361 /* Configure the VIC for the WDG interrupt. */
\r
362 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );
\r
363 VIC_ITCmd( TIM2_ITLine, ENABLE );
\r
365 /* Install the default handlers for both VIC's. */
\r
366 VIC0->DVAR = ( unsigned portLONG ) prvDefaultHandler;
\r
367 VIC1->DVAR = ( unsigned portLONG ) prvDefaultHandler;
\r
369 TIM_CounterCmd(TIM2, TIM_CLEAR);
\r
370 TIM_CounterCmd(TIM2, TIM_START);
\r
372 /*-----------------------------------------------------------*/
\r
374 void TIM2_IRQHandler( void )
\r
376 /* Reset the timer counter to avioid overflow. */
\r
377 TIM2->OC1R += s_nPulseLength;
\r
379 /* Increment the tick counter. */
\r
380 vTaskIncrementTick();
\r
382 #if configUSE_PREEMPTION == 1
\r
384 /* The new tick value might unblock a task. Ensure the highest task that
\r
385 is ready to execute is the task that will execute when the tick ISR
\r
387 vTaskSwitchContext();
\r
391 /* Clear the interrupt in the watchdog. */
\r
392 TIM2->SR &= ~TIM_FLAG_OC1;
\r
395 #endif /* USE_WATCHDOG_TICK */
\r
397 /*-----------------------------------------------------------*/
\r
399 __arm __interwork void vPortEnterCritical( void )
\r
401 /* Disable interrupts first! */
\r
402 portDISABLE_INTERRUPTS();
\r
404 /* Now interrupts are disabled ulCriticalNesting can be accessed
\r
405 directly. Increment ulCriticalNesting to keep a count of how many times
\r
406 portENTER_CRITICAL() has been called. */
\r
407 ulCriticalNesting++;
\r
409 /*-----------------------------------------------------------*/
\r
411 __arm __interwork void vPortExitCritical( void )
\r
413 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
\r
415 /* Decrement the nesting count as we are leaving a critical section. */
\r
416 ulCriticalNesting--;
\r
418 /* If the nesting level has reached zero then interrupts should be
\r
420 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
\r
422 portENABLE_INTERRUPTS();
\r
426 /*-----------------------------------------------------------*/
\r
428 static void prvDefaultHandler( void )
\r