2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
29 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the ST STR91x ARM9
32 *----------------------------------------------------------*/
34 /* Library includes. */
37 /* Standard includes. */
41 /* Scheduler includes. */
45 #ifndef configUSE_WATCHDOG_TICK
46 #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.
49 /* Constants required to setup the initial stack. */
50 #ifndef _RUN_TASK_IN_ARM_MODE_
51 #define portINITIAL_SPSR ( ( StackType_t ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
53 #define portINITIAL_SPSR ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
56 #define portINSTRUCTION_SIZE ( ( StackType_t ) 4 )
58 /* Constants required to handle critical sections. */
59 #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
62 #define abs( x ) ( ( x ) > 0 ? ( x ) : -( x ) )
66 * Toggle a led using the following algorithm:
67 * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
69 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
73 * GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
77 #define TOGGLE_LED( port, pin ) \
78 if( ( ( ( ( port )->DR[ ( pin ) << 2 ] ) ) & ( pin ) ) != Bit_RESET ) \
80 ( port )->DR[ ( pin ) << 2 ] = 0x00; \
84 ( port )->DR[ ( pin ) << 2 ] = ( pin ); \
88 /*-----------------------------------------------------------*/
90 /* Setup the watchdog to generate the tick interrupts. */
91 static void prvSetupTimerInterrupt( void );
93 /* ulCriticalNesting will get set to zero when the first task starts. It
94 * cannot be initialised to 0 as this will cause interrupts to be enabled
95 * during the kernel initialisation process. */
96 uint32_t ulCriticalNesting = ( uint32_t ) 9999;
98 /* Tick interrupt routines for cooperative and preemptive operation
99 * respectively. The preemptive version is not defined as __irq as it is called
100 * from an asm wrapper function. */
101 void WDG_IRQHandler( void );
103 /* VIC interrupt default handler. */
104 static void prvDefaultHandler( void );
106 #if configUSE_WATCHDOG_TICK == 0
107 /* Used to update the OCR timer register */
108 static u16 s_nPulseLength;
111 /*-----------------------------------------------------------*/
114 * Initialise the stack of a task to look exactly as if a call to
115 * portSAVE_CONTEXT had been called.
117 * See header file for description.
119 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
120 TaskFunction_t pxCode,
121 void * pvParameters )
123 StackType_t * pxOriginalTOS;
125 pxOriginalTOS = pxTopOfStack;
127 /* To ensure asserts in tasks.c don't fail, although in this case the assert
128 * is not really required. */
131 /* Setup the initial stack of the task. The stack is set exactly as
132 * expected by the portRESTORE_CONTEXT() macro. */
134 /* First on the stack is the return address - which in this case is the
135 * start of the task. The offset is added to make the return address appear
136 * as it would within an IRQ ISR. */
137 *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
140 *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa; /* R14 */
142 *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
144 *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
146 *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
148 *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
150 *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
152 *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
154 *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
156 *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
158 *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
160 *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
162 *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
164 *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
166 *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
169 /* When the task starts is will expect to find the function parameter in
171 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
174 /* The status register is set for system mode, with interrupts enabled. */
175 *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
178 /* Interrupt flags cannot always be stored on the stack and will
179 * instead be stored in a variable, which is then saved as part of the
181 *pxTopOfStack = portNO_CRITICAL_NESTING;
185 /*-----------------------------------------------------------*/
187 BaseType_t xPortStartScheduler( void )
189 extern void vPortStartFirstTask( void );
191 /* Start the timer that generates the tick ISR. Interrupts are disabled
193 prvSetupTimerInterrupt();
195 /* Start the first task. */
196 vPortStartFirstTask();
198 /* Should not get here! */
201 /*-----------------------------------------------------------*/
203 void vPortEndScheduler( void )
205 /* It is unlikely that the ARM port will require this function as there
206 * is nothing to return to. */
208 /*-----------------------------------------------------------*/
210 /* This function is called from an asm wrapper, so does not require the __irq
212 #if configUSE_WATCHDOG_TICK == 1
214 static void prvFindFactors( u32 n,
218 /* This function is copied from the ST STR7 library and is
219 * copyright STMicroelectronics. Reproduced with permission. */
223 int32_t err, err_min = n;
225 *a = a0 = ( ( n - 1 ) / 65536ul ) + 1;
228 for( ; *a <= 256; ( *a )++ )
231 err = ( int32_t ) *a * ( int32_t ) *b - ( int32_t ) n;
233 if( abs( err ) > ( *a / 2 ) )
236 err = ( int32_t ) *a * ( int32_t ) *b - ( int32_t ) n;
239 if( abs( err ) < abs( err_min ) )
255 /*-----------------------------------------------------------*/
257 static void prvSetupTimerInterrupt( void )
259 WDG_InitTypeDef xWdg;
261 uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
263 /* Configure the watchdog as a free running timer that generates a
264 * periodic interrupt. */
266 SCU_APBPeriphClockConfig( __WDG, ENABLE );
268 WDG_StructInit( &xWdg );
269 prvFindFactors( n, &a, &b );
270 xWdg.WDG_Prescaler = a - 1;
271 xWdg.WDG_Preload = b - 1;
273 WDG_ITConfig( ENABLE );
275 /* Configure the VIC for the WDG interrupt. */
276 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );
277 VIC_ITCmd( WDG_ITLine, ENABLE );
279 /* Install the default handlers for both VIC's. */
280 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
281 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
285 /*-----------------------------------------------------------*/
287 void WDG_IRQHandler( void )
290 /* Increment the tick counter. */
291 if( xTaskIncrementTick() != pdFALSE )
293 /* Select a new task to execute. */
294 vTaskSwitchContext();
297 /* Clear the interrupt in the watchdog. */
302 #else /* if configUSE_WATCHDOG_TICK == 1 */
304 static void prvFindFactors( u32 n,
308 /* This function is copied from the ST STR7 library and is
309 * copyright STMicroelectronics. Reproduced with permission. */
313 int32_t err, err_min = n;
316 *a = a0 = ( ( n - 1 ) / 256 ) + 1;
319 for( ; *a <= 256; ( *a )++ )
322 err = ( int32_t ) *a * ( int32_t ) *b - ( int32_t ) n;
324 if( abs( err ) > ( *a / 2 ) )
327 err = ( int32_t ) *a * ( int32_t ) *b - ( int32_t ) n;
330 if( abs( err ) < abs( err_min ) )
346 /*-----------------------------------------------------------*/
348 static void prvSetupTimerInterrupt( void )
352 uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
354 TIM_InitTypeDef timer;
356 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
358 TIM_StructInit( &timer );
359 prvFindFactors( n, &a, &b );
361 timer.TIM_Mode = TIM_OCM_CHANNEL_1;
362 timer.TIM_OC1_Modes = TIM_TIMING;
363 timer.TIM_Clock_Source = TIM_CLK_APB;
364 timer.TIM_Clock_Edge = TIM_CLK_EDGE_RISING;
365 timer.TIM_Prescaler = a - 1;
366 timer.TIM_Pulse_Level_1 = TIM_HIGH;
367 timer.TIM_Pulse_Length_1 = s_nPulseLength = b - 1;
369 TIM_Init( TIM2, &timer );
370 TIM_ITConfig( TIM2, TIM_IT_OC1, ENABLE );
371 /* Configure the VIC for the WDG interrupt. */
372 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );
373 VIC_ITCmd( TIM2_ITLine, ENABLE );
375 /* Install the default handlers for both VIC's. */
376 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
377 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
379 TIM_CounterCmd( TIM2, TIM_CLEAR );
380 TIM_CounterCmd( TIM2, TIM_START );
382 /*-----------------------------------------------------------*/
384 void TIM2_IRQHandler( void )
386 /* Reset the timer counter to avoid overflow. */
387 TIM2->OC1R += s_nPulseLength;
389 /* Increment the tick counter. */
390 if( xTaskIncrementTick() != pdFALSE )
392 /* Select a new task to run. */
393 vTaskSwitchContext();
396 /* Clear the interrupt in the watchdog. */
397 TIM2->SR &= ~TIM_FLAG_OC1;
400 #endif /* USE_WATCHDOG_TICK */
402 /*-----------------------------------------------------------*/
404 __arm __interwork void vPortEnterCritical( void )
406 /* Disable interrupts first! */
407 portDISABLE_INTERRUPTS();
409 /* Now that interrupts are disabled, ulCriticalNesting can be accessed
410 * directly. Increment ulCriticalNesting to keep a count of how many times
411 * portENTER_CRITICAL() has been called. */
414 /*-----------------------------------------------------------*/
416 __arm __interwork void vPortExitCritical( void )
418 if( ulCriticalNesting > portNO_CRITICAL_NESTING )
420 /* Decrement the nesting count as we are leaving a critical section. */
423 /* If the nesting level has reached zero then interrupts should be
425 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
427 portENABLE_INTERRUPTS();
431 /*-----------------------------------------------------------*/
433 static void prvDefaultHandler( void )