2 * FreeRTOS Kernel V10.0.1
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://www.FreeRTOS.org
23 * http://aws.amazon.com/freertos
28 /*-----------------------------------------------------------
29 * Implementation of functions defined in portable.h for the ST STR91x ARM9
31 *----------------------------------------------------------*/
33 /* Library includes. */
36 /* Standard includes. */
40 /* Scheduler includes. */
44 #ifndef configUSE_WATCHDOG_TICK
45 #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.
48 /* Constants required to setup the initial stack. */
49 #ifndef _RUN_TASK_IN_ARM_MODE_
50 #define portINITIAL_SPSR ( ( StackType_t ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
52 #define portINITIAL_SPSR ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
55 #define portINSTRUCTION_SIZE ( ( StackType_t ) 4 )
57 /* Constants required to handle critical sections. */
58 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
61 #define abs(x) ((x)>0 ? (x) : -(x))
65 * Toggle a led using the following algorithm:
66 * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
68 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
72 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
76 #define TOGGLE_LED(port,pin) \
77 if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET ) \
79 (port)->DR[(pin) <<2] = 0x00; \
83 (port)->DR[(pin) <<2] = (pin); \
87 /*-----------------------------------------------------------*/
89 /* Setup the watchdog to generate the tick interrupts. */
90 static void prvSetupTimerInterrupt( void );
92 /* ulCriticalNesting will get set to zero when the first task starts. It
93 cannot be initialised to 0 as this will cause interrupts to be enabled
94 during the kernel initialisation process. */
95 uint32_t ulCriticalNesting = ( uint32_t ) 9999;
97 /* Tick interrupt routines for cooperative and preemptive operation
98 respectively. The preemptive version is not defined as __irq as it is called
99 from an asm wrapper function. */
100 void WDG_IRQHandler( void );
102 /* VIC interrupt default handler. */
103 static void prvDefaultHandler( void );
105 #if configUSE_WATCHDOG_TICK == 0
106 /* Used to update the OCR timer register */
107 static u16 s_nPulseLength;
110 /*-----------------------------------------------------------*/
113 * Initialise the stack of a task to look exactly as if a call to
114 * portSAVE_CONTEXT had been called.
116 * See header file for description.
118 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
120 StackType_t *pxOriginalTOS;
122 pxOriginalTOS = pxTopOfStack;
124 /* To ensure asserts in tasks.c don't fail, although in this case the assert
125 is not really required. */
128 /* Setup the initial stack of the task. The stack is set exactly as
129 expected by the portRESTORE_CONTEXT() macro. */
131 /* First on the stack is the return address - which in this case is the
132 start of the task. The offset is added to make the return address appear
133 as it would within an IRQ ISR. */
134 *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
137 *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa; /* R14 */
139 *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
141 *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
143 *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
145 *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
147 *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
149 *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
151 *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
153 *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
155 *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
157 *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
159 *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
161 *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
163 *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
166 /* When the task starts is will expect to find the function parameter in
168 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
171 /* The status register is set for system mode, with interrupts enabled. */
172 *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
175 /* Interrupt flags cannot always be stored on the stack and will
176 instead be stored in a variable, which is then saved as part of the
178 *pxTopOfStack = portNO_CRITICAL_NESTING;
182 /*-----------------------------------------------------------*/
184 BaseType_t xPortStartScheduler( void )
186 extern void vPortStartFirstTask( void );
188 /* Start the timer that generates the tick ISR. Interrupts are disabled
190 prvSetupTimerInterrupt();
192 /* Start the first task. */
193 vPortStartFirstTask();
195 /* Should not get here! */
198 /*-----------------------------------------------------------*/
200 void vPortEndScheduler( void )
202 /* It is unlikely that the ARM port will require this function as there
203 is nothing to return to. */
205 /*-----------------------------------------------------------*/
207 /* This function is called from an asm wrapper, so does not require the __irq
209 #if configUSE_WATCHDOG_TICK == 1
211 static void prvFindFactors(u32 n, u16 *a, u32 *b)
213 /* This function is copied from the ST STR7 library and is
214 copyright STMicroelectronics. Reproduced with permission. */
218 int32_t err, err_min=n;
220 *a = a0 = ((n-1)/65536ul) + 1;
223 for (; *a <= 256; (*a)++)
226 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
227 if (abs(err) > (*a / 2))
230 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
232 if (abs(err) < abs(err_min))
244 /*-----------------------------------------------------------*/
246 static void prvSetupTimerInterrupt( void )
248 WDG_InitTypeDef xWdg;
250 uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
252 /* Configure the watchdog as a free running timer that generates a
253 periodic interrupt. */
255 SCU_APBPeriphClockConfig( __WDG, ENABLE );
257 WDG_StructInit(&xWdg);
258 prvFindFactors( n, &a, &b );
259 xWdg.WDG_Prescaler = a - 1;
260 xWdg.WDG_Preload = b - 1;
262 WDG_ITConfig(ENABLE);
264 /* Configure the VIC for the WDG interrupt. */
265 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );
266 VIC_ITCmd( WDG_ITLine, ENABLE );
268 /* Install the default handlers for both VIC's. */
269 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
270 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
274 /*-----------------------------------------------------------*/
276 void WDG_IRQHandler( void )
279 /* Increment the tick counter. */
280 if( xTaskIncrementTick() != pdFALSE )
282 /* Select a new task to execute. */
283 vTaskSwitchContext();
286 /* Clear the interrupt in the watchdog. */
293 static void prvFindFactors(u32 n, u8 *a, u16 *b)
295 /* This function is copied from the ST STR7 library and is
296 copyright STMicroelectronics. Reproduced with permission. */
300 int32_t err, err_min=n;
303 *a = a0 = ((n-1)/256) + 1;
306 for (; *a <= 256; (*a)++)
309 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
310 if (abs(err) > (*a / 2))
313 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
315 if (abs(err) < abs(err_min))
327 /*-----------------------------------------------------------*/
329 static void prvSetupTimerInterrupt( void )
333 uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
335 TIM_InitTypeDef timer;
337 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
339 TIM_StructInit(&timer);
340 prvFindFactors( n, &a, &b );
342 timer.TIM_Mode = TIM_OCM_CHANNEL_1;
343 timer.TIM_OC1_Modes = TIM_TIMING;
344 timer.TIM_Clock_Source = TIM_CLK_APB;
345 timer.TIM_Clock_Edge = TIM_CLK_EDGE_RISING;
346 timer.TIM_Prescaler = a-1;
347 timer.TIM_Pulse_Level_1 = TIM_HIGH;
348 timer.TIM_Pulse_Length_1 = s_nPulseLength = b-1;
350 TIM_Init (TIM2, &timer);
351 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);
352 /* Configure the VIC for the WDG interrupt. */
353 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );
354 VIC_ITCmd( TIM2_ITLine, ENABLE );
356 /* Install the default handlers for both VIC's. */
357 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
358 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
360 TIM_CounterCmd(TIM2, TIM_CLEAR);
361 TIM_CounterCmd(TIM2, TIM_START);
363 /*-----------------------------------------------------------*/
365 void TIM2_IRQHandler( void )
367 /* Reset the timer counter to avioid overflow. */
368 TIM2->OC1R += s_nPulseLength;
370 /* Increment the tick counter. */
371 if( xTaskIncrementTick() != pdFALSE )
373 /* Select a new task to run. */
374 vTaskSwitchContext();
377 /* Clear the interrupt in the watchdog. */
378 TIM2->SR &= ~TIM_FLAG_OC1;
381 #endif /* USE_WATCHDOG_TICK */
383 /*-----------------------------------------------------------*/
385 __arm __interwork void vPortEnterCritical( void )
387 /* Disable interrupts first! */
388 portDISABLE_INTERRUPTS();
390 /* Now interrupts are disabled ulCriticalNesting can be accessed
391 directly. Increment ulCriticalNesting to keep a count of how many times
392 portENTER_CRITICAL() has been called. */
395 /*-----------------------------------------------------------*/
397 __arm __interwork void vPortExitCritical( void )
399 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
401 /* Decrement the nesting count as we are leaving a critical section. */
404 /* If the nesting level has reached zero then interrupts should be
406 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
408 portENABLE_INTERRUPTS();
412 /*-----------------------------------------------------------*/
414 static void prvDefaultHandler( void )