rtel wrote on Friday, 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.