ATmegaxxxx - clarify initial stack setup

This commit is contained in:
Phillip Stevens 2020-04-11 18:37:00 +10:00
parent 10fcd90af1
commit 62682ebe5b

View file

@ -1,6 +1,6 @@
/*
* FreeRTOS Kernel V10.3.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@ -206,7 +206,7 @@ void wdt_interrupt_reset_enable (const uint8_t value)
* Macro to save all the general purpose registers, the save the stack pointer
* into the TCB.
*
* The first thing we do is save the flags then disable interrupts. This is to
* The first thing we do is save the flags then disable interrupts. This is to
* guard our stack against having a context switch interrupt after we have already
* pushed the registers onto the stack - causing the 32 registers to be on the
* stack twice.
@ -221,7 +221,7 @@ void wdt_interrupt_reset_enable (const uint8_t value)
* #endif
*
* #if defined(__AVR_3_BYTE_PC__)
* #define __EIND__ 0x3C
* #define __EIND__ 0x3C
* #endif
*
* The interrupts will have been disabled during the call to portSAVE_CONTEXT()
@ -542,35 +542,28 @@ uint16_t usAddress;
/* The start of the task code will be popped off the stack last, so place
it on first. */
usAddress = ( uint16_t ) pxCode;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
usAddress >>= 8;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
#if defined(__AVR_3_BYTE_PC__)
/* The AVR ATmega2560/ATmega2561 have 256KBytes of program memory and a 17-bit
* program counter. When a code address is stored on the stack, it takes 3 bytes
* program counter. When a code address is stored on the stack, it takes 3 bytes
* instead of 2 for the other ATmega* chips.
*
* Store 0 as the top byte since we force all task routines to the bottom 128K
* of flash. We do this by using the .lowtext label in the linker script.
*
* In order to do this properly, we would need to get a full 3-byte pointer to
* pxCode. That requires a change to GCC. Not likely to happen any time soon.
* pxCode. That requires a change to GCC. Not likely to happen any time soon.
*/
usAddress = ( uint16_t ) pxCode;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
usAddress >>= 8;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
*pxTopOfStack = 0;
pxTopOfStack--;
#else
usAddress = ( uint16_t ) pxCode;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
usAddress >>= 8;
*pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
pxTopOfStack--;
#endif
/* Next simulate the stack as if after a call to portSAVE_CONTEXT().
@ -598,7 +591,7 @@ uint16_t usAddress;
pxTopOfStack--;
#endif
/* Now the remaining registers. The compiler expects R1 to be 0. */
/* Now the remaining registers. The compiler expects R1 to be 0. */
*pxTopOfStack = ( StackType_t ) 0x00; /* R1 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x02; /* R2 */
@ -680,7 +673,7 @@ BaseType_t xPortStartScheduler( void )
/* Restore the context of the first task that is going to run. */
portRESTORE_CONTEXT();
/* Simulate a function call end as generated by the compiler. We will now
/* Simulate a function call end as generated by the compiler. We will now
jump to the start of the task the context of which we have just restored. */
__asm__ __volatile__ ( "ret" );
@ -705,7 +698,7 @@ void vPortEndScheduler( void )
/*-----------------------------------------------------------*/
/*
* Manual context switch. The first thing we do is save the registers so we
* Manual context switch. The first thing we do is save the registers so we
* can use a naked attribute.
*/
void vPortYield( void ) __attribute__ ( ( hot, flatten, naked ) );
@ -720,8 +713,8 @@ void vPortYield( void )
/*-----------------------------------------------------------*/
/*
* Context switch function used by the tick. This must be identical to
* vPortYield() from the call to vTaskSwitchContext() onwards. The only
* Context switch function used by the tick. This must be identical to
* vPortYield() from the call to vTaskSwitchContext() onwards. The only
* difference from vPortYield() is the tick count is incremented as the
* call comes from the tick ISR.
*/
@ -774,7 +767,7 @@ uint8_t ucLowByte;
/* Adjust for correct value. */
ulCompareMatch -= ( uint32_t ) 1;
/* Setup compare match value for compare match A. Interrupts are disabled
/* Setup compare match value for compare match A. Interrupts are disabled
before this is called so we need not worry here. */
ucLowByte = ( uint8_t ) ( ulCompareMatch & ( uint32_t ) 0xff );
portOCRL = ucLowByte;
@ -798,8 +791,8 @@ uint8_t ucLowByte;
#if configUSE_PREEMPTION == 1
/*
* Tick ISR for preemptive scheduler. We can use a naked attribute as
* the context is saved at the start of vPortYieldFromTick(). The tick
* Tick ISR for preemptive scheduler. We can use a naked attribute as
* the context is saved at the start of vPortYieldFromTick(). The tick
* count is incremented after the context is saved.
*
* use ISR_NOBLOCK where there is an important timer running, that should preempt the scheduler.
@ -816,8 +809,8 @@ uint8_t ucLowByte;
#else
/*
* Tick ISR for the cooperative scheduler. All this does is increment the
* tick count. We don't need to switch context, this can only be done by
* Tick ISR for the cooperative scheduler. All this does is increment the
* tick count. We don't need to switch context, this can only be done by
* manual calls to taskYIELD();
*
* use ISR_NOBLOCK where there is an important timer running, that should preempt the scheduler.