FreeRTOS Support Archive
The FreeRTOS support forum is used to obtain active support directly from Real
Time Engineers Ltd. In return for using our top quality software and services for
free, we request you play fair and do your bit to help others too! Sign up
to receive notifications of new support topics then help where you can.
This is a read only archive of threads posted to the FreeRTOS support forum.
The archive is updated every week, so will not always contain the very latest posts.
Use these archive pages to search previous posts. Use the Live FreeRTOS Forum
link to reply to a post, or start a new support thread.
[FreeRTOS Home] [Live FreeRTOS Forum] [FAQ] [Archive Top] [April 2011 Threads] Xmega128A1 Port strange behaviourPosted by nachus001 on April 1, 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
RE: Xmega128A1 Port strange behaviourPosted by Richard on April 2, 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.
RE: Xmega128A1 Port strange behaviourPosted by nachus001 on April 2, 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
RE: Xmega128A1 Port strange behaviourPosted by nachus001 on April 4, 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
RE: Xmega128A1 Port strange behaviourPosted by nachus001 on 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
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|