Xmega128A1 Port strange behaviour

ignacioam wrote on Friday, April 01, 2011:

Dear all:

I used the FreeRtos port for the Xmega that is contributed here
http://interactive.freertos.org/attachments/token/wfsz46do1a8zcfz/?name=AVR_ATXMega128A1_WinAVR.zip
My setup is the last Freertos version, which compiles OK with no errors. The only file I’ve changed is PORT.c

and after some investigation I came to find a strange behaviour of the software or port.
I have 2 tasks a mutex and a binary semaphore for synchronization, fired from an interrupt vector

Task 1 takes the mutex when available and reads “protected” data then returns the mutex,

Task 2 is idle most of the time waiting for a semaphore. When semaphore fires,  task 2 acess hardware, retrieves data from device, takes the mutex  and writes to the “protected data”, return the mutex then goes idle again

When I start the system like these

main()
{ /* pseudocoded for clarity*/
...
start_task_1@priority=5
start_task_2@priority =6
start_scheduler
}

the system works OK

but if I start the system with both tasks AT THE SAME PRIORITY
the system will only work if I start the task2 first
If I start Task1 first, the scheduler will switch to the task 1 code, but no to the task 2
In this case the task switcher will switch to task 1,  and will stop switching.
Even with all the two interrupts enabled (tick timer and semaphore vector) at the same LEVEL (both high or both low)
it doesn’t care. If I stop in a breakpoint placed in the task that’s working (Task 1) and watch the hardware, I see that both interrupts are enabled, the PMIC_CTRL register is enabled, and the I bit is set, but no interrupt gets processed (altough both are acknowledged since it’s individual flags so indicates,  and PMIC_STATUS indicates an interrupt being executed)

This is very strange, since I’ve worked before with FreeRtos and The ATmega128 (classic AVR) with no problems.
What do you thing is causing this? Is there something in the hardware tht I’m missing?

Thanks in advance
Ignacio

rtel wrote on Saturday, April 02, 2011:

I’m not familiar with that port, as it is a contributed port, but just some general tips:

1) Can you step through the code and see what is happening?
2) Is it possible you have a simple deadlock in your code?
3) Are you complying with all the usual rules about not using API function that don’t end if FromISR() from an interrupt?
4) Do you have the run time stack checking switched on?

Regards.

ignacioam wrote on Saturday, April 02, 2011:

Hi Richard:

Thanks for your response I’ll answer your questions

1 Yes I can,  and with Task1 working only I can see how it takes the mutex, returns the mutex and do other things
(which in no case do mess with interrupts or RTOS structures)

2 Frankly, I don’t know. Maybe there is a deadlock if I set task1 (which runs all the time) priority greater than task2 (which runs only when there’s a signal for it)

3 Yes I do. The ISR that fires Task 2 sets a semaphore with the proper “fromISR()” function

4 No. because I did’t suspected there were some stack problem. For the record, I set (in FreeRTOSconfig.h) the Heap size to 20000. I let default minimal stack size  and “TASK1” has a stack depth of 6000 bytes,  Task2 has 1000 bytes

Thank you
Ignacio

ignacioam wrote on Monday, April 04, 2011:

Hi Rick:

I have done some investigation on the topic, and I found something that puzzles me
about this port.
I have found why the interrupts get clobbered. Theyre not disabled, but suspended.
Ive found that this occurs because in the context switch timer tick, the ISR service exits with the “RET” instruction
not with “RETI” (which would reenable the interrupt controller)

Notice that in the Xmega architecture the interrupts are not disabled by an interrupt call at general level.
They are disabled by  “LEVEL” level, this is low, med and high levels. (for simplicity I use interrupts in only one level, usually all low) So, altough the interrupt enabling/disabling mechanism is controllable by the user, it’s not visible when operated by interrupt calls, and “RETI” has compatibility with the classic megaAVR in the sense that it will reenable all the interrupts in a given level, so it must be present to exit the ISR. 

Once clarified this, here’s what I’ve found
When I start TASK2 and TASK1 (as explained on my first post) Everything works as intended
If I single step with the dissasembler, I can trace that the ISR(TCC0_OVF_vect, ISR_NAKED)  is entered and
vPortYieldFromTick(); is executed properly. Terminating properly and exiting the ISR with “RETI”

Now, if I change the starting order of tasks (as explained in the first post), if I single step the program, once the tick ISR is reached the execution goes like this

ISR(TCC0_OVF_vect, ISR_NAKED)  <--- ENTERS HERE BY TIMER INTERRUPT
		{
		vPortYieldFromTick();   
		|
                |
                |----> calls {
                                   portSAVE_CONTEXT();
	                           vTaskIncrementTick();
	                           vTaskSwitchContext();
	                          portRESTORE_CONTEXT();  <---EXITS BY THE FINAL "RET" INSIDE HERE
                                  
                                  }
	                          
asm volatile ( "reti" );
	}

And the “reti” on the end of the interrupt service is never reached, so the interrupts are never served and the program gets hanged, with the control switched to  TASK1 (the first started task)

I can’t understand why this happens. ay be there is an error with the push/pop sequence (I checked this and appears to be OK) or some severe memory/context misalignement. But in this case I can’t say for sure, because the system would be resetting all the time, and that’s not the case.

Thanks in advance
Ignacio

ignacioam wrote on Monday, April 25, 2011:

Hi Richard:

From almost a month with the issue, I have made some progress.

First, I’ve modified the vPortYieldFromTick() function with a final “reti” instead of the original “ret”
and all worked OK.

All okay for the given tasks described here, in any startup order,  but when I added more tasks and semaphores, the system begun to fail again randomly. I debugged the application until I could trace the problem to the taskYield(); function

In my system, I have a number of interrupts being serviced which do force task switching when they have data for
the system tasks (usually, tasks that are top priority but are 99% of the time sleeping until there is data for them)
The interrupts routines are written more or less in this form

ISR(PORTA_INT0_vect)
	{
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; 
xSemaphoreGiveFromISR( TIME_task_semaphore, &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken != pdFALSE )
			{
				taskYIELD();
			}
	}

If I comment the “if” statement (and therefore the"taskYield()") , the program works normally and doesn´t hang, but if I uncomment the “if” in the code the program hangs as described earlier and by the same mechanism.

So I think I’ve spotted the problem as a task or context switching from interrupt.
The Xmega program counter is 24 bits wide (contrary to the ATmega which is 16 bits wide), so, when an interrupt is serviced three bytes are saved in the stack (and also three bytes from PC  have to be restored ) The port I’m using takes care of this, but, for some reason the system fails with taskYIELD() from an interrupt.

I don’t know why taskYield() fails from and ISR routine since it uses the same portSAVE_CONTEXT(); portRESTORE_CONTEXT(); vTaskSwitchContext(); as in vPortYieldFromTick(), and it works

Not to speak why it fails randomly, after calling two or three times taskYield() from different ISR’s before a failure… It also works when called from a normal task.  On the other hand there’s no “from_ISR” yield function for AVR (at least not from my knowledge) . This context forcing is as in the provided  “serial port” demo

Thanks in advance
Ignacio