Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

ATMega644 and FreeRTOS - not working

Posted by DietmarE on November 26, 2007
Can somebody please help me with the required changes to compile a - working - project for the ATMega32 for the ATMega644? I have found exactly two suggested changes in the world wide web (beyond adjusting the TOTAL_HEAP_SIZE to the extra memory of the 644) ... and they don't work:

1. adjust port.c as demonstrated here:

--------------------------------------------------------------------------------------
#define portFLAGS_INT_ENABLED ( ( portSTACK_TYPE ) 0x80 )

#define portCLEAR_COUNTER_ON_MATCH ( ( unsigned portCHAR ) 0x08 )
#define portPRESCALE_64 ( ( unsigned portCHAR ) 0x05 )
#define portCLOCK_PRESCALER ( ( unsigned portLONG ) 64 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE ( ( unsigned portCHAR )
0x02 )

static void prvTimerInterrupt( void )

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

2. change port.c to deal with the fact that the program counter might have three bytes(datasheet says it has three bytes in one place, 16 bit in another place), by pushing 0 onto the stack after the two bytes that are pushed onto the stack in the ATMega32 code:

/* 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--;

*pxTopOfStack = ( portSTACK_TYPE )0;
pxTopOfStack--;

RE: ATMega644 and FreeRTOS - not working

Posted by DietmarE on November 26, 2007
Forogot to mention that prvSetupTimerInterrupt() was ajusted accordingly, ie.

...

ucLowByte = TIMSK1;
ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;
TIMSK1 = ucLowByte;

...

RE: ATMega644 and FreeRTOS - not working

Posted by JMR on December 5, 2007
I'm having problems getting the RTOS to run on my mega640 (different peripherals).

I have the timer tick ticking but after the first context switch the processor resets.
So I suspect a stack issue...
Now tracing things in assembler the reset happens because after the return from interrupt the program counter is loaded with an address. From what I could make out is that the PC gets the contents of the z-register which also happens to be R30-R31.
I'm in the process of figuring out what I need to do to fix this and as soon as I've got working code I'll post the solution here, unless someone else has solved this and let's us all know :)

RE: ATMega644 and FreeRTOS - not working

Posted by JMR on December 5, 2007
Right,
Just spent the last two hours tracing the start-up and the first timer tick/context switch.
What I found is that the pxPortInitialiseStack function seems to put values into the tasks stack instead of the contents of the registers R0 to R31. Which results in a return address from the interrupt of 0x3031 which in my case is uninitialised at 0xFFFF and thus causes a reset.

Richard (or others) can I just check with you that the intended aim of this function is indeed to copy the register values into the task's stack? If that's indeed the case then I'm on the right track and all I need to do is fix the function's code accordingly...

I sure hope I'm on the right track.

RE: ATMega644 and FreeRTOS - not working

Posted by Richard on December 5, 2007
pxPortInitialiseStack sets up the stack that is used by the task when it first starts running. It fills the RAM used by the task as its stack with values that will get popped into the task registers when the task starts. It does not at that point write to any registers.

The AVR port is quite mature so I'm surprised you are having issues with it. Are you using WinAVR? If so, which version?

Also, I know some AVRs have three program counter bytes now, whereas the port assumes two program counter bytes. Does the device you are using have two or three?

Regards.

RE: ATMega644 and FreeRTOS - not working

Posted by JMR on December 5, 2007
I'm using WinAVR 20070525 and FreeRTOS 4.6.1.
The program counter is a 2 byte entity.

What is happening is that in pxPortInitialiseStack the task's stack is initialised with the number of the register.
So that the task's stack has 0x30, 0x31 for the entries it will use for the registers R30 and R31 respectively in the restore context macro.

When the tick interrupt reaches the reti, the program counter gets the value 0x3130 which is in the middle of nowhere.


RE: ATMega644 and FreeRTOS - not working

Posted by Richard on December 5, 2007
I have just tried taking a clean FreeRTOS.org installation, building it with WinAVR 20070525, and running it in the AVRStudio simulator up to the point where the first task started. Everything seemed to work with no problems.

I turned the optimisation off to see what was going on better, could this be the source of the issue?

There was a message from somebody successfully using the port on an ATMega128 a few days back. Are there any differences in the processor core between the 128 and 32, and the core you are using?

Regards.

RE: ATMega644 and FreeRTOS - not working

Posted by Jay on December 5, 2007
The only differences I can see are the amount of Flash RAM 128K versus 64K and the 644 supports 20MHz


http://www.atmel.com/dyn/products/devices.asp?family_id=607#760
//-----
ATMEGA644: 64-Kbyte self-programming Flash Program Memory, 4-Kbyte SRAM, 2-KByte EEPROM, 8 Channel 10-bit A/D-converter. JTAG interface for on-chip-debug. Up to 20 MIPS throughput at 20 MHz. 1.8 - 5.5 Volt Operation.

//-----
ATMEGA128: 128-Kbyte self-programming Flash Program Memory, 4-Kbyte SRAM, 4-Kbyte EEPROM, 8 Channel 10-bit A/D-converter. JTAG interface for on-chip-debug. Up to 16 MIPS throughput at 16 MHz. 2.7 - 5.5 Volt operation.

FWIW,
Jay

RE: ATMega644 and FreeRTOS - not working

Posted by Jay on December 5, 2007
JM Rub, you never said which port you are starting with. IS it the AVR_ATMega323_WinAVR demo?

Can you post your FreeRTOSconfig.h? Also, did you have to rename/define the correct ports from the Timer interrrupt configuration? (in port.c)

Jay

RE: ATMega644 and FreeRTOS - not working

Posted by JMR on December 6, 2007
Guys,

I started off with the ATMega323_WinAVR port and fixed up the various parts that didn't compile at first for the ATMega640.

Below is my config.h, port.c and main.c files Note I've stripped it to the bare minimum (I want to check that my timer interrupt works before I get into debugging my application (I'm and adept of the KISS method :) )

JMR

FreeRTOSconfig.h:
------8<-----------------------8<-----------------------------------------------------
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include <avr/io.h>

/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*----------------------------------------------------------*/

#define configUSE_PREEMPTION1
#define configUSE_IDLE_HOOK1
#define configUSE_TICK_HOOK0
#define configCPU_CLOCK_HZ( ( unsigned portLONG ) 11059200 )
#define configTICK_RATE_HZ( ( portTickType ) 20 )
#define configMAX_PRIORITIES( ( unsigned portBASE_TYPE ) 4 )
#define configMINIMAL_STACK_SIZE( ( unsigned portSHORT ) 85 )
#define configTOTAL_HEAP_SIZE( (size_t ) ( 2500 ) )
#define configMAX_TASK_NAME_LEN( 8 )
#define configUSE_TRACE_FACILITY0
#define configUSE_16_BIT_TICKS1
#define configIDLE_SHOULD_YIELD1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#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_vTaskPrioritySet0
#define INCLUDE_uxTaskPriorityGet0
#define INCLUDE_vTaskDelete0
#define INCLUDE_vTaskCleanUpResources0
#define INCLUDE_vTaskSuspend1
#define INCLUDE_vTaskDelayUntil1
#define INCLUDE_vTaskDelay1


#endif /* FREERTOS_CONFIG_H */
------8<-----------------------8<-----------------------------------------------------
port.c:
------8<-----------------------8<-----------------------------------------------------
#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 ) 0x64 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE( ( unsigned portCHAR ) 0x02 )
------8<-----------------------8<-----------------------------------------------------
Cut out the various macros and functions as they haven't changed...
------8<-----------------------8<-----------------------------------------------------


/*
* 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 / configTICK_RATE_HZ;

/* We only have 16 bits so have to scale to get our required tick rate. */
ulCompareMatch /= portCLOCK_PRESCALER;

/* Adjust for correct value. */
ulCompareMatch -= ( unsigned portLONG ) 1;

/* 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.
*/
ISR(TIMER1_COMPA_vect)
{
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();
*/
ISR(TIMER1_COMPA_vect)
{
vTaskIncrementTick();
}
#endif

------8<-----------------------8<-----------------------------------------------------


main.c:
------8<-----------------------8<-----------------------------------------------------
#include <stdlib.h>
#include <string.h>

#ifdef GCC_MEGA_AVR
/* EEPROM routines used only with the WinAVR compiler. */
#include <avr/eeprom.h>
#endif

/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"

/* Demo file headers. */
//#include "PollQ.h"
//#include "integer.h"
//#include "serial.h"
//#include "comtest.h"
//#include "crflash.h"
//#include "print.h"
//#include "partest.h"
//#include "regtest.h"

/* Priority definitions for the tasks in the application. */
#define mainRADIO_TASK_PRIORITY( tskIDLE_PRIORITY + 1 )
#define mainGSM_TASK_PRIORITY( tskIDLE_PRIORITY + 1 )
#define mainGPS_TASK_PRIORITY( tskIDLE_PRIORITY + 1 )
#define mainPROTOCOL_TASK_PRIORITY( tskIDLE_PRIORITY + 1 )
#define mainCONTROL_TASK_PRIORITY( tskIDLE_PRIORITY + 2 )

/* Baud rate used by the serial port tasks. */
#define mainCOM_TEST_BAUD_RATE( ( unsigned portLONG ) 38400 )

/* LED used by the serial port tasks. This is toggled on each character Tx,
and mainCOM_TEST_LED + 1 is toggles on each character Rx. */
#define mainCOM_TEST_LED( 4 )

/* LED that is toggled by the check task. The check task periodically checks
that all the other tasks are operating without error. If no errors are found
the LED is toggled. If an error is found at any time the LED is never toggles
again. */
#define mainCHECK_TASK_LED( 7 )

/* The period between executions of the check task. 5 seconds */
#define mainCONTROL_PERIOD( ( portTickType ) 5000 / portTICK_RATE_MS )

/* An address in the EEPROM used to count resets. This is used to check that
the demo application is not unexpectedly resetting. */
#define mainRESET_COUNT_ADDRESS( ( void * ) 0x50 )


/*
* Called on boot to increment a count stored in the EEPROM. This is used to
* ensure the CPU does not reset unexpectedly.
*/
static void prvIncrementResetCount( void );

/*
* The various tasks for the application.
*/
void vRadioTask( void *pvParameters );
void vGSMTask( void *pvParameters );
void vGPSTask( void *pvParameters );
void vProtocolTask( void *pvParameters );
void vControlTask( void *pvParameters );

/*
* The idle hook is used to scheduler co-routines.
*/
void vApplicationIdleHook( void );

/*-----------------------------------------------------------*/

portSHORT main( void )
{
prvIncrementResetCount();

/* Create the tasks defined within this file. */
xTaskCreate( vRadioTask, "Radio", configMINIMAL_STACK_SIZE, NULL, mainRADIO_TASK_PRIORITY, NULL );
xTaskCreate( vGSMTask, "GSM", configMINIMAL_STACK_SIZE, NULL, mainGSM_TASK_PRIORITY, NULL );
xTaskCreate( vGPSTask, "GPS", configMINIMAL_STACK_SIZE, NULL, mainGPS_TASK_PRIORITY, NULL );
xTaskCreate( vProtocolTask, "Proto", configMINIMAL_STACK_SIZE, NULL, mainPROTOCOL_TASK_PRIORITY, NULL );
xTaskCreate( vControlTask, "Control", configMINIMAL_STACK_SIZE, NULL, mainCONTROL_TASK_PRIORITY, NULL );

/* In this port, to use preemptive scheduler define configUSE_PREEMPTION
as 1 in portmacro.h. To use the cooperative scheduler define
configUSE_PREEMPTION as 0. */
vTaskStartScheduler();

return 0;
}
/*-----------------------------------------------------------*/


/*-----------------------------------------------------------*/

static void prvIncrementResetCount( void )
{
unsigned portCHAR ucCount;

eeprom_read_block( &ucCount, mainRESET_COUNT_ADDRESS, sizeof( ucCount ) );
ucCount++;
eeprom_write_byte( mainRESET_COUNT_ADDRESS, ucCount );
}
/*-----------------------------------------------------------*/

void vApplicationIdleHook( void )
{
/* Do some background checks */

}

void vRadioTask( void *pvParameters )
{
volatile long cnt = 0;
for(;;)
{
cnt += 1;
}
}

void vGSMTask( void *pvParameters )
{
volatile long cnt = 0;
for(;;)
{
cnt += 1;
}
}

void vGPSTask( void *pvParameters )
{
volatile long cnt = 0;
for(;;)
{
cnt += 1;
}
}

void vProtocolTask( void *pvParameters )
{
volatile long cnt = 0;
for(;;)
{
cnt += 1;
}
}

void vControlTask( void *pvParameters )
{
volatile long cnt = 0;
for(;;)
{
cnt += 1;
}
}

RE: ATMega644 and FreeRTOS - not working

Posted by Jay on December 6, 2007
In your port.c you defined the interrupt enable bit as

#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE ( ( unsigned portCHAR ) 0x02 )

Which is the enable bit for Timer3. That's fine you can use Timer3, but you have to use Timer 3 ISR too.

In your port.c you have:

/*
* 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();
*/
ISR(TIMER1_COMPA_vect)
{
vTaskIncrementTick();
}

Did you redefine TIMER1_COMPA_vect as TIMER3_COMPA_vect somewhere?

Also, did you define
TIMSK = ucLowByte;

TIMSK to be ETIMSK ?

Jay

RE: ATMega644 and FreeRTOS - not working

Posted by JMR on December 7, 2007
> In your port.c you defined the interrupt enable bit as

> #define portCOMPARE_MATCH_A_INTERRUPT_ENABLE ( ( unsigned portCHAR ) 0x02 )

> Which is the enable bit for Timer3. That's fine you can use Timer3, but you have to use Timer 3 ISR too.
Err... Nope that _is_ the interrupt enable for timer 1 output compare A on my ATmega640. And this works as it is when returning _from_ the interrupt that things go wrong...

Now I have found the problem.
The original interrupt was declared as:
void SIG_OUTPUT_COMPARE1A( void ) __attribute__ ( ( signal, naked ) );
void SIG_OUTPUT_COMPARE1A( void )
This was replaced by:
ISR(TIMER1_COMPA_vect)
Since this is what is recommended in the AVR-libc manual....
Well... doing this breaks the RTOS.

Leaving the original declaration in place gets the tasks switching nicely...
Grrrrrrr. I hate when this happens.
On to checking what the difference is in the generated code.

RE: ATMega644 and FreeRTOS - not working

Posted by Jay on December 7, 2007
Err... Nope that _is_ the interrupt enable for timer 1 output compare A on my ATmega640. And this works as it is when returning _from_ the interrupt that things go wrong...

Hmmmm, I used the ATMega64 datasheet to look up the IE flags. Is the 640 part that much different?

In any event, you found it right?

Jay


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS