Quality RTOS & Embedded Software

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


Loading

ATMega64 Problem

Posted by Nobody/Anonymous on December 28, 2006
I've configured the atmega port to use the timer OC3A of the ATMega 64. I can verify functionality of the idle and tick hook by toggling a pin and viewing the output with an oscope.

However, when I create a new task which toggles a pin and delays with vTaskDelayUntil, the task executes for a second or so and then stops executing (at least I am assuming the task is no longer executing since the pin isn't toggling) but the idle hook pin is still toggling.

Even when I create multiple tasks, each affecting a seperate pin, they all behave in the same manner.

Any suggestions?

Thanks,
Scott Nortman
MAKO Surgical Corp.
Ft. Lauderdale, FL

RE: ATMega64 Problem

Posted by Nobody/Anonymous on December 28, 2006
An update...

When I remove the call to vTaskDelayUntil inside the task's for(;;) loop, the tasks operates as expected and doesn't stop.

--Scott

RE: ATMega64 Problem

Posted by Nobody/Anonymous on December 29, 2006
The 64 has twice the RAM of the 32 part - am I right? Should run then as the demo runs on a 32. Normally otherwise I would say it was a stack problem most likely. Do you have any large variables on the stack? Can you increase the stack allocated to the task?

Are you using GCC?
Have you copied exactly the syntax used to write the tick isr from the demo?

RE: ATMega64 Problem

Posted by Nobody/Anonymous on December 29, 2006
Yes, the 64 has 4k of SRAM. I've already increased the allocated stack size from 85 to 100 bytes, even though I don't have any large variables.

I am using the latest release of WinAVR / avr-gcc.

Here is the snippet of code from port.c which uses the atmega64 timer 3OCA:

/* Added 12/28/2006 by Scott Nortman
*Port to ATMega64 timer 3 compare match B
*/
static void prvSetupTimerInterrupt( void )
{
unsigned portLONG ulCompareMatch;
unsigned portCHAR ucHighByte, ucLowByte;

/* Using 16bit timer 3 A 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 3B. 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 );
OCR3AH = ucHighByte;
OCR3AL = ucLowByte;

/* Setup clock source and compare match behavior for timer 3 A
*We want Clear Timer on Compare match mode 4, prescalar set to 64 */
TCCR3B |= ( (1<<WGM32) | (1<<CS31) | (1<<CS30) );

//debug
//set up pin to toggle to see if this ISR is executing as expected
TCCR3A |= (1<<COM3A0);

/* Enable the interrupt - this is okay as interrupt are currently globally
disabled. */
ETIMSK |= (1<<OCIE3A);
}
/*-----------------------------------------------------------*/

/* Changed below ISRs to work with OC3B */

#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_COMPARE3A( void ) __attribute__ ( ( signal, naked ) );
void SIG_OUTPUT_COMPARE3A( 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_COMPARE3A( void ) __attribute__ ( ( signal ) );
void SIG_OUTPUT_COMPARE3A( void )
{
vTaskIncrementTick();
}
#endif


Note that I've set up the hardware pin to toggle, which I can view on an oscope to verify that the ISR is executing as expected.

Here is the task code:

void vTaskCodePC1( void *pvParameters )
{

portTickType xLastWakeTime;
const portTickType xFrequency = 250;

/* The parameters are not used. */
( void ) pvParameters;

xLastWakeTime = xTaskGetTickCount();


for(;;){

vTaskDelayUntil(&xLastWakeTime, xFrequency );

PORTC ^= 1<<PC1;
}

}

Here is the code from main which sets up the task:

xTaskCreate( vTaskCodePC1, "PC1", configMINIMAL_STACK_SIZE, NULL, 1, NULL );

vTaskStartScheduler();

I've verified that the config file is set up properly, the IO pin is set as an output, and I still can't seem to figure this out...

Thanks,
Scott


RE: ATMega64 Problem

Posted by Nobody/Anonymous on December 29, 2006
FYI, the top comment is incorrect, I am using OC3A

RE: ATMega64 Problem

Posted by Scott Nortman on December 29, 2006
More comments...

The tasks do indeed run continuously when the call to vTaskDelayUntil is commented out. As soo as I try to delay, it appears as though the task is only called once and then never gets called again.

I've also tried delaying with vTaskDelay, and the same problem occurs.

--Scott

RE: ATMega64 Problem

Posted by Jeff Smith on December 29, 2006
Maybe it is not resuming the thread right. Mine does that if it is not properly save/restoring the context. For example imbalanced push/pull on stack.

RE: ATMega64 Problem

Posted by Richard on December 29, 2006
Coincidentally I have just been having a conversation with somebody working on an AT90USB128 with a similar problem. They had switched to use a different timer, and the problem turned out to be in the new timer code.

I have to admit to not following the thread completely but here is what I suggest doing:

1) Create two tasks that do nothing but manually switch to each other, with interrupts disabled:

void task1( void * pv )
{
unsigned long c = 0;

____portDISABLE_INTERRUPTS();

____for( ;; )
____{
________c++;
________taskYIELD();
____}
}

void task2( void * pv )
{
unsigned long d = 0;

____portDISABLE_INTERRUPTS();

____for( ;; )
____{
________d++;
________taskYIELD();
____}
}


Interrupts remaining disabled means the timer cannot interfere. Run these tasks in the AVRStudio simulator, stepping through the simple code to ensure C and D increment at the same rate as the tasks take it in turn to run (create them both at priority 1 so the idle task does not interfere).


2) Write another simple program that does nothing but execute the timer interrupt. Do not include any FreeRTOS code, simple toggle an LED in the ISR.

int main( void )
{
____SetupTimerInterrupt();
____for( ;; )
____{
____}
}

Set a break point on the entry to main so you can detect if it ever resets - the breakpoint should only get hit once.

This will give you confidence that the timer and interrupt are configured correctly and being vectored to as expected without any other code getting in the way.

Once this is working then:

3) Combine the two programs, removing the portDISABLE_INTERRUPTS() at the top of the task so the interrupt fires while the tasks are switching to each other. The interrupt still does nothing other than toggle an LED. The tick count will not increment but this does not matter as no tasks are blocking.

Once this is working then:

4) Convert the ISR to the real FreeRTOS.org ISR, but comment out the calls to the kernel:

//using whichever interrupt you are using
void TIMER1_COMPA_vect( void ) __attribute__ ( ( signal, naked ) );
void TIMER1_COMPA_vect( void )
{
____vPortYieldFromTick();
____asm volatile ( "reti" );
}


void vPortYieldFromTick( void ) __attribute__ ( ( naked ) );
void vPortYieldFromTick( void )
{
____portSAVE_CONTEXT();
____/* vTaskIncrementTick();
____vTaskSwitchContext(); */
____portRESTORE_CONTEXT();
____asm volatile ( "ret" );
}

Note that the two vTaskxxx lines are commented out. Once this is working then the task context is being saved and restored correctly as the two dummy tasks yield to each other, but the tick is not switching between the tasks.

Once this is proven:

5) Comment back in the two commented out lines, and remove the taskYIELD() call in the two dummy tasks. Now the two dummy tasks should both execute but only switch within the tick interrupt.

void task1( void * pv )
{
unsigned long c = 0;

____for( ;; )
____{
________c++;
____}
}

void task2( void * pv )
{
unsigned long d = 0;

____for( ;; )
____{
________d++;
____}
}


Now the whole system is working other than attempting to block.

6) Finally leave task1 as is, and change the other to:

void task2( void * pv )
{
unsigned long d = 0;

____for( ;; )
____{
________d++;
________vTaskDelay( 5 );
____}
}


Now c within task 1 should increment at a much faster rate than d within task 2 as it will execute whenever task 2 is blocked.



See how far you get through these steps before things go pear shaped.

Regards.

RE: ATMega64 Problem

Posted by Scott Nortman on December 29, 2006
Richard,

Thank you for the suggestions, I will try the above steps. However, I do have a questions:

1) How can I simulate the code in a AVRStudio Simualtor? Do I need to build to a coff file (vs a hex file)?
2) How can I set a breakpoint? I have the JTAG / USB programmer; can this be done in AVR Studio? While viewing the mixed C and ASM sources?

Thanks,
Scott

RE: ATMega64 Problem

Posted by Richard on December 29, 2006
I use an elf file, I think coff will be ok but later versions of WinAVR favour elf over coff.

In AVR studio:

1) Select File|Open menu.
2) Browse to then double click on your elf file. AVRStudio will automatically create a project for you, for which you will be asked to enter a name (.aps extension by default).
3) A window will open that allows you to select the debug platform (Simulator required) and device.

Now you can run the code in the simulator - setting break points, stepping through the C or asm code, etc.

Regards.

RE: ATMega64 Problem

Posted by Nobody/Anonymous on December 30, 2006
Richard,

I've followed all of the steps you have suggested. I set up the tasks, stepped through them to verify that the variables are changing as expected, added watch points and breakpoints to insure that the ISR is indeed getting set up properly.

Everything works as expected until the call to vTaskDelay. At that point, the task never gets executed again.

I've tried to single step through the code, but it is a lot for me to learn before I can really know about all of the details about what is going on.

Do you have any other suggestions that I can try?

Thanks for you help!

--Scott Nortman

RE: ATMega64 Problem

Posted by Richard on December 31, 2006
Can you zip up your files and send them to me so I can take a look? If you could make this the smallest test program that exhibits the problem, and include your makefile.

My email address can be obtained from the Contacts page of the FreeRTOS.org site ( r *(DOT)* barry {{{at}}} freertos dot org ).

Regards.


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


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

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


Careers

FreeRTOS and other embedded software careers at AWS.



FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Renesas

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

Xilinx Microblaze and Zynq partner