ATMega640 port crashing at context switch

thesa1nt01 wrote on Thursday, January 06, 2011:

Salutations all,

We are working on porting the GCC ATMega323 FreeRTOS code to the ATMega640 on the Axon platform for use with a robot and we are not able to context switch. When vPortYield or vPortYieldFromTick is called, as soon as we step to portRESTORE_CONTEXT, registers 00-30 get the value 0x00 (R01 and R29 already had 0x00 it seems) and R31 keeps 0xFF, X and Y pointer get 0x0000 and Z pointer gets 0xFF00. Following this we are stepped back to int main().

We have two basic tasks, and only the initially created task gets to call taskYIELD.

I have scoured the forums and applied a few changes, to be listed, but most notably, since the program counter is three bytes long, we tried to account for the third byte as suggested by this post:

https://sourceforge.net/projects/freertos/forums/forum/382005/topic/1536028

both before, and after the initial two bytes, with no affect, and even came across a post where someone solved the problem by removing the third byte from their code.

We are primarily working in the simulator at this point, but have reproduced the error on two other simulators and two identical hardware platforms.

FreeRTOS V6.1.0
AVR Studio 4.18.716
WinAVR 20100110 (I think this is a version number but we also are using the latest version on other laptops)

The following sections were modified:

port.c

/* Start tasks with interrupts enables. */
#define portFLAGS_INT_ENABLED					( ( portSTACK_TYPE ) 0x80 )
/* Hardware constants for timer 1. */
#define portCLEAR_COUNTER_ON_MATCH				( ( unsigned char ) 0x08 )
#define portPRESCALE_64							( ( unsigned char ) 0x03 )
#define portCLOCK_PRESCALER						( ( unsigned long ) 64 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE	( ( unsigned char ) 0x02 )
/*-----------------------------------------------------------*/




/* Enable the interrupt - this is okay as interrupt are currently globally
	disabled. */
	ucLowByte = TIMSK1;
	ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;
	TIMSK1 = ucLowByte;

portable.h

#ifdef GCC_MEGA_AVR 
	#include "../portable/GCC/ATMega640/portmacro.h"
#endif

FreeRTOSConfig.h

#define configUSE_PREEMPTION		0
#define configUSE_IDLE_HOOK			0
#define configUSE_TICK_HOOK			0
#define configCPU_CLOCK_HZ			( ( unsigned long ) 16000000 )
#define configTICK_RATE_HZ			( ( portTickType ) 1000 )
#define configMAX_PRIORITIES		( ( unsigned portBASE_TYPE ) 4 )
#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 85 )
#define configTOTAL_HEAP_SIZE		( (size_t ) ( 1500 ) )
#define configMAX_TASK_NAME_LEN		( 8 )
#define configUSE_TRACE_FACILITY	0
#define configUSE_16_BIT_TICKS		1
#define configIDLE_SHOULD_YIELD		1
#define configQUEUE_REGISTRY_SIZE	0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		1
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet		0
#define INCLUDE_uxTaskPriorityGet		0
#define INCLUDE_vTaskDelete				1
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			0
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1

We disabled the preemption in order to determine whether or not the tick had anything to do with it.
There were no change in symptoms.

Here’s the main:

#include <FreeRTOS.h>
#include <task.h>
int i, j;
void vTaskA(void* pvParameters){
	for(;;){
		i++;
		taskYIELD();
	}
}
void vTaskB(void* pvParameters){
	for(;;){
		j++;
		taskYIELD();
	}
}
int main(){
	
	xTaskCreate(vTaskB, "B", 10, NULL, 1, NULL);
	xTaskCreate(vTaskA, "A", 10, NULL, 1, NULL);
	vTaskStartScheduler();
	for(;;);
	return 0;
}

Also, we compiled at optimization O3 and O0, with no change.

I hope this is enough information. I’m sure there is some simple silly solution, because there doesn’t seem to be much left!
:slight_smile:

Thanks in advance.

rtel wrote on Monday, January 10, 2011:

Does this help?

http://interactive.freertos.org/entries/139197-avr-atxmega128a1-winavr

You could also try searching avrfreaks.net, or seeing if somebody has a port there.

Regards.

jmr1972 wrote on Monday, January 10, 2011:

Hi,
I did have a working port to the Xmega644 but haven’t touched it in 2 years+ so won’t be able to help with getting the port into the latest FreeRTOS version.
I seem to remember having to modify the portSAVE_CONTEXT() and portRESTORE_CONTEXT() macros to get it to work as well as the tick interrupt part of the port.c file.
here’s the contents of port.c:

/*
	FreeRTOS.org V4.6.1 - Copyright (C) 2003-2007 Richard Barry.
	This file is part of the FreeRTOS.org distribution.
	FreeRTOS.org is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	FreeRTOS.org is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with FreeRTOS.org; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
	A special exception to the GPL can be applied should you wish to distribute
	a combined work that includes FreeRTOS.org, without being obliged to provide
	the source code for any proprietary components.  See the licensing section 
	of http://www.FreeRTOS.org for full details of how and when the exception
	can be applied.
	***************************************************************************
	See http://www.FreeRTOS.org for documentation, latest information, license 
	and contact details.  Please ensure to read the configuration and relevant 
	port sections of the online documentation.
	Also see http://www.SafeRTOS.com a version that has been certified for use
	in safety critical systems, plus commercial licensing, development and
	support options.
	***************************************************************************
*/
/* 
Changes from V2.6.0
	+ AVR port - Replaced the inb() and outb() functions with direct memory
	  access.  This allows the port to be built with the 20050414 build of
	  WinAVR.
*/
#include <stdlib.h>
#include <avr/interrupt.h>
#include "FreeRTOS.h"
#include "task.h"
/*-----------------------------------------------------------
 * Implementation of functions defined in portable.h for the AVR port.
 *----------------------------------------------------------*/
/* Start tasks with interrupts enables. */
#define portFLAGS_INT_ENABLED					( ( portSTACK_TYPE ) 0x80 )
/* Hardware constants for timer 1. */
#define portCLEAR_COUNTER_ON_MATCH				( ( unsigned portCHAR ) 0x08 )
#define portPRESCALE_64							( ( unsigned portCHAR ) 0x03 )
#define portCLOCK_PRESCALER						( ( unsigned portLONG ) 64 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE	( ( unsigned portCHAR ) 0x02 )
/*-----------------------------------------------------------*/
/* We require the address of the pxCurrentTCB variable, but don't want to know
any details of its type. */
typedef void tskTCB;
extern volatile tskTCB * volatile pxCurrentTCB;
/*-----------------------------------------------------------*/
/* 
 * 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 
 * 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. 
 * 
 * r1 is set to zero as the compiler expects it to be thus, however some
 * of the math routines make use of R1. 
 * 
 * The interrupts will have been disabled during the call to portSAVE_CONTEXT()
 * so we need not worry about reading/writing to the stack pointer. 
 */
#define portSAVE_CONTEXT()									\
	asm volatile (	"push	r0						\n\t"	\
					"in		r0, __SREG__			\n\t"	\
					"cli							\n\t"	\
					"push	r0						\n\t"	\
					"push	r1						\n\t"	\
					"clr	r1						\n\t"	\
					"push	r2						\n\t"	\
					"push	r3						\n\t"	\
					"push	r4						\n\t"	\
					"push	r5						\n\t"	\
					"push	r6						\n\t"	\
					"push	r7						\n\t"	\
					"push	r8						\n\t"	\
					"push	r9						\n\t"	\
					"push	r10						\n\t"	\
					"push	r11						\n\t"	\
					"push	r12						\n\t"	\
					"push	r13						\n\t"	\
					"push	r14						\n\t"	\
					"push	r15						\n\t"	\
					"push	r16						\n\t"	\
					"push	r17						\n\t"	\
					"push	r18						\n\t"	\
					"push	r19						\n\t"	\
					"push	r20						\n\t"	\
					"push	r21						\n\t"	\
					"push	r22						\n\t"	\
					"push	r23						\n\t"	\
					"push	r24						\n\t"	\
					"push	r25						\n\t"	\
					"push	r26						\n\t"	\
					"push	r27						\n\t"	\
					"push	r28						\n\t"	\
					"push	r29						\n\t"	\
					"push	r30						\n\t"	\
					"push	r31						\n\t"	\
					"lds	r26, pxCurrentTCB		\n\t"	\
					"lds	r27, pxCurrentTCB + 1	\n\t"	\
					"in		r0, 0x3d				\n\t"	\
					"st		x+, r0					\n\t"	\
					"in		r0, 0x3e				\n\t"	\
					"st		x+, r0					\n\t"	\
				);
/* 
 * Opposite to portSAVE_CONTEXT().  Interrupts will have been disabled during
 * the context save so we can write to the stack pointer. 
 */
#define portRESTORE_CONTEXT()								\
	asm volatile (	"lds	r26, pxCurrentTCB		\n\t"	\
					"lds	r27, pxCurrentTCB + 1	\n\t"	\
					"ld		r28, x+					\n\t"	\
					"out	__SP_L__, r28			\n\t"	\
					"ld		r29, x+					\n\t"	\
					"out	__SP_H__, r29			\n\t"	\
					"pop	r31						\n\t"	\
					"pop	r30						\n\t"	\
					"pop	r29						\n\t"	\
					"pop	r28						\n\t"	\
					"pop	r27						\n\t"	\
					"pop	r26						\n\t"	\
					"pop	r25						\n\t"	\
					"pop	r24						\n\t"	\
					"pop	r23						\n\t"	\
					"pop	r22						\n\t"	\
					"pop	r21						\n\t"	\
					"pop	r20						\n\t"	\
					"pop	r19						\n\t"	\
					"pop	r18						\n\t"	\
					"pop	r17						\n\t"	\
					"pop	r16						\n\t"	\
					"pop	r15						\n\t"	\
					"pop	r14						\n\t"	\
					"pop	r13						\n\t"	\
					"pop	r12						\n\t"	\
					"pop	r11						\n\t"	\
					"pop	r10						\n\t"	\
					"pop	r9						\n\t"	\
					"pop	r8						\n\t"	\
					"pop	r7						\n\t"	\
					"pop	r6						\n\t"	\
					"pop	r5						\n\t"	\
					"pop	r4						\n\t"	\
					"pop	r3						\n\t"	\
					"pop	r2						\n\t"	\
					"pop	r1						\n\t"	\
					"pop	r0						\n\t"	\
					"out	__SREG__, r0			\n\t"	\
					"pop	r0						\n\t"	\
				);
/*-----------------------------------------------------------*/
/*
 * Perform hardware setup to enable ticks from timer 1, compare match A.
 */
static void prvSetupTimerInterrupt( void );
/*-----------------------------------------------------------*/
/* 
 * See header file for description. 
 */
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
unsigned portSHORT usAddress;
	/* Place a few bytes of known values on the bottom of the stack. 
	This is just useful for debugging. */
	*pxTopOfStack = 0x11;
	pxTopOfStack--;
	*pxTopOfStack = 0x22;
	pxTopOfStack--;
	*pxTopOfStack = 0x33;
	pxTopOfStack--;
	/* Simulate how the stack would look after a call to vPortYield() generated by 
	the compiler. */
	/*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */
	/* The start of the task code will be popped off the stack last, so place
	it on first. */
	usAddress = ( unsigned portSHORT ) pxCode;
	*pxTopOfStack = ( portSTACK_TYPE ) ( usAddress & ( unsigned portSHORT ) 0x00ff );
	pxTopOfStack--;
	usAddress >>= 8;
	*pxTopOfStack = ( portSTACK_TYPE ) ( usAddress & ( unsigned portSHORT ) 0x00ff );
	pxTopOfStack--;
	/* Next simulate the stack as if after a call to portSAVE_CONTEXT().  
	portSAVE_CONTEXT places the flags on the stack immediately after r0
	to ensure the interrupts get disabled as soon as possible, and so ensuring
	the stack use is minimal should a context switch interrupt occur. */
	*pxTopOfStack = ( portSTACK_TYPE ) 0x00;	/* R0 */
	pxTopOfStack--;
	*pxTopOfStack = portFLAGS_INT_ENABLED;
	pxTopOfStack--;
	/* Now the remaining registers.   The compiler expects R1 to be 0. */
	*pxTopOfStack = ( portSTACK_TYPE ) 0x00;	/* R1 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x02;	/* R2 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x03;	/* R3 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x04;	/* R4 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x05;	/* R5 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x06;	/* R6 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x07;	/* R7 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x08;	/* R8 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x09;	/* R9 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x10;	/* R10 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x11;	/* R11 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x12;	/* R12 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x13;	/* R13 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x14;	/* R14 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x15;	/* R15 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x16;	/* R16 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x17;	/* R17 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x18;	/* R18 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x19;	/* R19 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x20;	/* R20 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x21;	/* R21 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x22;	/* R22 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x23;	/* R23 */
	pxTopOfStack--;
	/* Place the parameter on the stack in the expected location. */
	usAddress = ( unsigned portSHORT ) pvParameters;
	*pxTopOfStack = ( portSTACK_TYPE ) ( usAddress & ( unsigned portSHORT ) 0x00ff );
	pxTopOfStack--;
	usAddress >>= 8;
	*pxTopOfStack = ( portSTACK_TYPE ) ( usAddress & ( unsigned portSHORT ) 0x00ff );
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x26;	/* R26 X */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x27;	/* R27 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x28;	/* R28 Y */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x29;	/* R29 */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x30;	/* R30 Z */
	pxTopOfStack--;
	*pxTopOfStack = ( portSTACK_TYPE ) 0x031;	/* R31 */
	pxTopOfStack--;
	/*lint +e950 +e611 +e923 */
	return pxTopOfStack;
}
/*-----------------------------------------------------------*/
portBASE_TYPE xPortStartScheduler( void )
{
	/* In this port we ignore the parameter and use the configUSE_PREEMPTION
	definition instead. */
	/* Setup the hardware to generate the tick. */
	prvSetupTimerInterrupt();
	/* 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
	jump to the start of the task the context of which we have just restored. */
	asm volatile ( "ret" );
	/* Should not get here. */
	return pdTRUE;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
	/* It is unlikely that the AVR port will get stopped.  If required simply
	disable the tick interrupt here. */
}
/*-----------------------------------------------------------*/
/*
 * Manual context switch.  The first thing we do is save the registers so we
 * can use a naked attribute.
 */
void vPortYield( void ) __attribute__ ( ( naked ) );
void vPortYield( void )
{
	portSAVE_CONTEXT();
	vTaskSwitchContext();
	portRESTORE_CONTEXT();
	asm volatile ( "ret" );
}
/*-----------------------------------------------------------*/
/*
 * 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.
 */
void vPortYieldFromTick( void ) __attribute__ ( ( naked ) );
void vPortYieldFromTick( void )
{
	portSAVE_CONTEXT();
	vTaskIncrementTick();
	vTaskSwitchContext();
	portRESTORE_CONTEXT();
	asm volatile ( "ret" );
}
/*-----------------------------------------------------------*/
/*
 * Setup timer 1 compare match A to generate a tick interrupt.
 */
static void prvSetupTimerInterrupt( void )
{
unsigned portLONG ulCompareMatch;
unsigned portCHAR ucHighByte, ucLowByte;
	/* Using 16bit timer 1 to generate the tick.  Correct fuses must be
	selected for the configCPU_CLOCK_HZ clock. */
	ulCompareMatch = configCPU_CLOCK_HZ / portCLOCK_PRESCALER;
	/* calculates the RTOS tick rate based on the timer's tick rate. */
	ulCompareMatch /= configTICK_RATE_HZ;
	/* Adjust for correct value. */
	ulCompareMatch -= ( unsigned portLONG ) 1;
	//ulCompareMatch = (unsigned portLONG) 8639;
	/* Setup compare match value for compare match A.  Interrupts are disabled 
	before this is called so we need not worry here. */
	ucLowByte = ( unsigned portCHAR ) ( ulCompareMatch & ( unsigned portLONG ) 0xff );
	ulCompareMatch >>= 8;
	ucHighByte = ( unsigned portCHAR ) ( ulCompareMatch & ( unsigned portLONG ) 0xff );
	OCR1AH = ucHighByte;
	OCR1AL = ucLowByte;
	/* Setup clock source and compare match behaviour. */
	ucLowByte = portCLEAR_COUNTER_ON_MATCH | portPRESCALE_64;
	TCCR1B = ucLowByte;
	/* Enable the interrupt - this is okay as interrupt are currently globally
	disabled. */
	ucLowByte = TIMSK1;
	ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;
	TIMSK1 = 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
	 * count is incremented after the context is saved.
	 */
	void SIG_OUTPUT_COMPARE1A( void ) __attribute__ ( ( signal, naked ) );
	void SIG_OUTPUT_COMPARE1A( void )
	{
		vPortYieldFromTick();
		asm volatile ( "reti" );
	}
#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
	 * manual calls to taskYIELD();
	 */
	void SIG_OUTPUT_COMPARE1A( void ) __attribute__ ( ( signal ) );
	void SIG_OUTPUT_COMPARE1A( void )
	{
		vTaskIncrementTick();
	}
#endif

and here’s my portmacro.h

/*
	FreeRTOS.org V5.0.2 - Copyright (C) 2003-2008 Richard Barry.
	This file is part of the FreeRTOS.org distribution.
	FreeRTOS.org is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	FreeRTOS.org is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with FreeRTOS.org; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
	A special exception to the GPL can be applied should you wish to distribute
	a combined work that includes FreeRTOS.org, without being obliged to provide
	the source code for any proprietary components.  See the licensing section 
	of http://www.FreeRTOS.org for full details of how and when the exception
	can be applied.
    ***************************************************************************
    ***************************************************************************
    *                                                                         *
    * SAVE TIME AND MONEY!  We can port FreeRTOS.org to your own hardware,    *
    * and even write all or part of your application on your behalf.          *
    * See http://www.OpenRTOS.com for details of the services we provide to   *
    * expedite your project.                                                  *
    *                                                                         *
    ***************************************************************************
    ***************************************************************************
	Please ensure to read the configuration and relevant port sections of the
	online documentation.
	http://www.FreeRTOS.org - Documentation, latest information, license and 
	contact details.
	http://www.SafeRTOS.com - A version that is certified for use in safety 
	critical systems.
	http://www.OpenRTOS.com - Commercial support, development, porting, 
	licensing and training services.
*/
/*
Changes from V1.2.3
	+ portCPU_CLOSK_HZ definition changed to 8MHz base 10, previously it 
	  base 16.
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
 * Port specific definitions.  
 *
 * The settings in this file configure FreeRTOS correctly for the
 * given hardware and compiler.
 *
 * These settings should not be altered.
 *-----------------------------------------------------------
 */
/* Type definitions. */
#define portCHAR		char
#define portFLOAT		float
#define portDOUBLE		double
#define portLONG		long
#define portSHORT		int
#define portSTACK_TYPE	unsigned portCHAR
#define portBASE_TYPE	char
#if( configUSE_16_BIT_TICKS == 1 )
	typedef unsigned portSHORT portTickType;
	#define portMAX_DELAY ( portTickType ) 0xffff
#else
	typedef unsigned portLONG portTickType;
	#define portMAX_DELAY ( portTickType ) 0xffffffff
#endif
/*-----------------------------------------------------------*/	
/* Critical section management. */
#define portENTER_CRITICAL()		asm volatile ( "in		__tmp_reg__, __SREG__" :: );	\
									asm volatile ( "cli" :: );								\
									asm volatile ( "push	__tmp_reg__" :: )
#define portEXIT_CRITICAL()			asm volatile ( "pop		__tmp_reg__" :: );				\
									asm volatile ( "out		__SREG__, __tmp_reg__" :: )
#define portDISABLE_INTERRUPTS()	asm volatile ( "cli" :: );
#define portENABLE_INTERRUPTS()		asm volatile ( "sei" :: );
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH			( -1 )
#define portTICK_RATE_MS			( ( portTickType ) 1000 / configTICK_RATE_HZ )		
#define portBYTE_ALIGNMENT			1
#define portNOP()					asm volatile ( "nop" );
/*-----------------------------------------------------------*/
/* Kernel utilities. */
extern void vPortYield( void ) __attribute__ ( ( naked ) );
#define portYIELD()					vPortYield()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */

I think that’s all that needs modifying to get things up and running…

gezab wrote on Monday, January 10, 2011:

Hi,

Regarding the XMEGA, I think there have to be lots of modifications to the port files since (at least larger) XMEGAs use 24 bit addressing for the PC (and indirect calls/jumps and pointers - X, Y and Z) and have a different interrupt handling scheme. I am currently working on a project with ATXMEGA128A1, and I have a modified AVR port for FreeRTOS 6.1.0. Feel free to contact me if you need it.

However, I think the original part you intend to port FreeRTOS to (ATMEGA640) is not an XMEGA architecture.

Regards,
Geza

thesa1nt01 wrote on Tuesday, January 11, 2011:

Thanks all for your replies.
It turns out that my code was correct. I had ported it correctly according to the forums and the porting guide.
The problem was that I had set my stack depth for my tasks to only 10 bytes. This meant that when pxPortInitialiseStack was called the TCB for each task was over written after it was instantiated.
I set each to 100 bytes and all is well.

Thanks again.
Regards,

PS - Should I post a port somehow?

davedoors wrote on Tuesday, January 11, 2011:

Thats good. If you have some working code then its always good to post it on the interactive site. Here is a good place http://interactive.freertos.org/forums/103473-atmel

apollionis wrote on Tuesday, January 11, 2011:

Hi Gezab,

I would be very interesting to work with / to test your FreeRtos port for Xmega!

Regards,
apollionis

gezab wrote on Tuesday, January 11, 2011:

Hi apollionis,

Thanks for your interest, I have already uploaded it to http://www.freertos.org/index.html?http://interactive.freertos.org/forums/103473-atmel.

Some changes compared to the original AVR port:
- Interrupts are always enabled globally (I flag is always set), only low-level interrupts are disabled during context switch and in critical sections in the interrupt controller.
- Software stack is extended with interrupt control register, RAMPX, RAMPZ, EIND and RAMPD. RAMPY is not saved since it is used for addressing the software stack (the TCB could be extended with RAMPY as well because the software stack address is saved in the TCB, however, since no 64k boundary check is done in the macros, it is easier to make the linker allocate the heap in the lowest 64k of the RAM and set RAMPY to 0).
- High- and mid-level interrupts can be used for rapid system response to events (like in my system, too), however, they must not interfere with the OS since the OS is not aware of them (they can appear at any time if they do proper register and context saving and restoring). When restoring the hardware stack pointer from the software stack, interrupts need to be disabled globally because mid- and high-level interrupts are not disabled during context switch.
- Interrupt routines that want to use the OS need to be low-level.
- Interrupt routines that use portSAVE_CONTEXT and portRESTORE_CONTEXT as a wrapper must return with reti directly after portRESTORE_CONTEXT. The reti instruction does not alter the I flag on Xmega but checks the interrupt status register to find out which level the interrupt is executing on. Not returning with reti is likely to cause the system to hang because low-level interrupts are no longer allowed to run.

That is all I can remember for now, please contact me if any more information is needed.

Regards,
Geza

urka46 wrote on Monday, January 17, 2011:

Hi everybody!

I am also using FreeRTOS for xmega and (formerly Atmega). As a hint I might suggest to add this code to main.c to prevent crashing

BTW, xmega128 has 16-bit program counter, hasn’t it? xmega192 has 24-bit, though.
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName );
/* This function is called immediately after task context is saved into stack. This is the case
* when stack contains biggest amount of data. Hook function checks if there is a stack overflow
* for the current (switched) task.
* configCHECK_FOR_STACK_OVERFLOW should be defined as 1 to use StackOverflowHook.
*/

void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName )
{
/* stop execution and report error */
while(true) LED_set(RED);
}

and you will have to define

#define configCHECK_FOR_STACK_OVERFLOW 1

in FreeRTOSConfig.h

If I see red led, than I have to increase stack depth for a certain task.

gezab wrote on Monday, January 17, 2011:

ATxmega128A1 definitely has 1 24 bit PC. Return addresses on the HW stack are 3 bytes long.

Geza