2 * FreeRTOS Kernel V10.4.3 LTS Patch 3
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. If you wish to use our Amazon
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * https://www.FreeRTOS.org
24 * https://github.com/FreeRTOS
30 #include <avr/interrupt.h>
31 #include "porthardware.h"
35 /*-----------------------------------------------------------
36 * Implementation of functions defined in portable.h for the AVR port.
37 *----------------------------------------------------------*/
39 /* Start tasks with interrupts enables. */
40 #define portFLAGS_INT_ENABLED ( ( StackType_t ) 0x80 )
42 /*-----------------------------------------------------------*/
44 /* We require the address of the pxCurrentTCB variable, but don't want to know
45 * any details of its type. */
46 typedef void RTOS_TCB_t;
47 extern volatile RTOS_TCB_t * volatile pxCurrentTCB;
49 /*-----------------------------------------------------------*/
52 * Macro to save all the general purpose registers, the save the stack pointer
55 * The first thing we do is save the flags then disable interrupts. This is to
56 * guard our stack against having a context switch interrupt after we have already
57 * pushed the registers onto the stack - causing the 32 registers to be on the
60 * r1 is set to zero as the compiler expects it to be thus, however some
61 * of the math routines make use of R1.
63 * The interrupts will have been disabled during the call to portSAVE_CONTEXT()
64 * so we need not worry about reading/writing to the stack pointer.
67 #define portSAVE_CONTEXT() \
68 asm volatile ( "push r0 \n\t" \
69 "in r0, __SREG__ \n\t" \
72 "in r0, __RAMPZ__ \n\t" \
106 "lds r26, pxCurrentTCB \n\t" \
107 "lds r27, pxCurrentTCB + 1 \n\t" \
108 "in r0, __SP_L__ \n\t" \
110 "in r0, __SP_H__ \n\t" \
114 * Opposite to portSAVE_CONTEXT(). Interrupts will have been disabled during
115 * the context save so we can write to the stack pointer.
118 #define portRESTORE_CONTEXT() \
119 asm volatile ( "lds r26, pxCurrentTCB \n\t" \
120 "lds r27, pxCurrentTCB + 1 \n\t" \
122 "out __SP_L__, r28 \n\t" \
124 "out __SP_H__, r29 \n\t" \
157 "out __RAMPZ__, r0 \n\t" \
159 "out __SREG__, r0 \n\t" \
162 /*-----------------------------------------------------------*/
165 * Perform hardware setup to enable ticks from timer.
167 static void prvSetupTimerInterrupt( void );
168 /*-----------------------------------------------------------*/
171 * See header file for description.
173 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
174 TaskFunction_t pxCode,
175 void * pvParameters )
179 /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */
181 /* Place a few bytes of known values on the bottom of the stack.
182 * This is just useful for debugging. Uncomment if needed. */
183 /* *pxTopOfStack = 0x11; */
184 /* pxTopOfStack--; */
185 /* *pxTopOfStack = 0x22; */
186 /* pxTopOfStack--; */
187 /* *pxTopOfStack = 0x33; */
188 /* pxTopOfStack--; */
190 /* The start of the task code will be popped off the stack last, so place
192 usAddress = ( uint16_t ) pxCode;
193 *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
197 *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
200 /* Next simulate the stack as if after a call to portSAVE_CONTEXT().
201 * portSAVE_CONTEXT places the flags on the stack immediately after r0
202 * to ensure the interrupts get disabled as soon as possible, and so ensuring
203 * the stack use is minimal should a context switch interrupt occur. */
204 *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */
206 *pxTopOfStack = portFLAGS_INT_ENABLED;
208 *pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */
211 /* Now the remaining registers. The compiler expects R1 to be 0. */
212 *pxTopOfStack = ( StackType_t ) 0x00; /* R1 */
214 /* Leave R2 - R23 untouched */
217 /* Place the parameter on the stack in the expected location. */
218 usAddress = ( uint16_t ) pvParameters;
219 *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
223 *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
225 /* Leave register R26 - R31 untouched */
228 /*lint +e950 +e611 +e923 */
232 /*-----------------------------------------------------------*/
234 BaseType_t xPortStartScheduler( void )
236 /* Setup the hardware to generate the tick. */
237 prvSetupTimerInterrupt();
239 /* Restore the context of the first task that is going to run. */
240 portRESTORE_CONTEXT();
242 /* Simulate a function call end as generated by the compiler. We will now
243 * jump to the start of the task the context of which we have just restored. */
244 asm volatile ( "ret" );
246 /* Should not get here. */
249 /*-----------------------------------------------------------*/
251 void vPortEndScheduler( void )
253 /* vPortEndScheduler is not implemented in this port. */
255 /*-----------------------------------------------------------*/
258 * Manual context switch. The first thing we do is save the registers so we
259 * can use a naked attribute.
261 void vPortYield( void ) __attribute__( ( naked ) );
262 void vPortYield( void )
265 vTaskSwitchContext();
266 portRESTORE_CONTEXT();
267 asm volatile ( "ret" );
269 /*-----------------------------------------------------------*/
272 * Manual context switch callable from ISRs. The first thing
273 * we do is save the registers so we can use a naked attribute.
275 void vPortYieldFromISR( void ) __attribute__( ( naked ) );
276 void vPortYieldFromISR( void )
279 vTaskSwitchContext();
280 portRESTORE_CONTEXT();
281 asm volatile ( "reti" );
283 /*-----------------------------------------------------------*/
286 * Context switch function used by the tick. This must be identical to
287 * vPortYield() from the call to vTaskSwitchContext() onwards. The only
288 * difference from vPortYield() is the tick count is incremented as the
289 * call comes from the tick ISR.
291 void vPortYieldFromTick( void ) __attribute__( ( naked ) );
292 void vPortYieldFromTick( void )
296 if( xTaskIncrementTick() != pdFALSE )
298 vTaskSwitchContext();
301 portRESTORE_CONTEXT();
303 asm volatile ( "reti" );
305 /*-----------------------------------------------------------*/
308 * Setup timer to generate a tick interrupt.
310 static void prvSetupTimerInterrupt( void )
314 /*-----------------------------------------------------------*/
316 #if configUSE_PREEMPTION == 1
319 * Tick ISR for preemptive scheduler. We can use a naked attribute as
320 * the context is saved at the start of vPortYieldFromTick(). The tick
321 * count is incremented after the context is saved.
323 ISR( TICK_INT_vect, ISR_NAKED )
325 /* Clear tick interrupt flag. */
326 CLR_INT( INT_FLAGS, INT_MASK );
328 vPortYieldFromTick();
330 asm volatile ( "reti" );
332 #else /* if configUSE_PREEMPTION == 1 */
335 * Tick ISR for the cooperative scheduler. All this does is increment the
336 * tick count. We don't need to switch context, this can only be done by
337 * manual calls to taskYIELD();
341 /* Clear tick interrupt flag. */
342 INT_FLAGS = INT_MASK;
343 xTaskIncrementTick();
345 #endif /* if configUSE_PREEMPTION == 1 */