I am porting FreeRTOS on PowerPC arch processor P4080, basically followed the example port PPC405.
Its all successful, everything is working fine except for vTaskDelay.
Whenever there is a a call to vTaskDelay the processor gets a halted. The exception is not consistent i.e., sometimes it's Data TLB error, sometimes it's Program Error, and sometime it's just Target Reset. I have tested all other functionalities, they are working fine.
But the amazing thing is, whenever I try to do step-input debugging - I never get any problem, vTaskDelay works just fine. But I run the program, I get this error.
- Can anyone tell me where could be the problem?
- Any other way to debug the issue?
Kindly help me solve it asap. As I am nearing to my master thesis dead line, without this being solved I can't proceed further. ( I am using Re-entrant NEWLIB for printf -- its working FINE, for all other functionality test)
/* Scheduler includes. */
volatile portTickType TempLocalVar4,TempLocalVar5;
printf("\r%d\n",TempLocalVar4); //print the TICK count before delay
TempLocalVar5=xTaskGetTickCount(); //Get the Tick count after delay
int main( void )
xTaskCreate(task1, "task1", configMINIMALSTACKSIZE, NULL, 7, &t1);
for( ;; );
In the output I can only one see 45(tick count). I can surely say that its not a problem of printf function,
because, even if I remove printf and just do something like
Still I can see that the value of 'a', will be 1.
Thanks for your help.
If running it slowly by single stepping on the debugger works but running it quickly doesn't then maybe you need some memory barrier instructions in the porting code?
Yes, can you please give me an example for it? Or a link to it?
As you are creating your own port there is no existing code that can be linked to. You can look at the Cortex-M port layers or the PIC32 port layers to find examples for other architectures, but your best bet is to look up "barrier" in the architecture reference manual to see where they should be placed. Typically you might expect barrier instructions after writing to hardware (for example, enabling/disabling interrupts to ensure the interrupt is really disabled before executing the code that needs interrupts disabled, or on before saving the task context, etc.).
If you take the call to vTaskDelay() out, does the code still run? If you create your task at the idle priority it should switch between your task and the idle task on each tick interrupt.
Yes, if I take out vTaskDelay(), my code runs perfectly. Even Context Switches happen as expected for every tick ISR, taskYIELD() too works correctly when 2 or more task are running with same priority. All the functions of Task Control , Kernel control (Macros) work flawlessly.
Yes, will have a look into the memory barrier. P4080 arch is very similar to FreeRTOS supported PPC405 arch. Infact, I used it to make all the port.c (syscalls.s) file.
I have attached a document of screen shots. For vTaskDelay testing, I used step-input.
That is a big clue then.
taskYIELD() calls yield directly. vTaskDelay() calls taskYIELD() indirectly, so in nearly every case the yield mechanism is the same. I say nearly every case because vTaskDelay() actually call portYIELDWITHINAPI(), but normally portYIELDWITHINAPI() is just #defined to taskYIELD/portYIELD().
One big difference though is the CPU context when the yield is performed. In some, but not all, cases the yield in vTaskDelay() can be performed inside a critical section, and your port code needs to handle that. There are generally two ways of handling it:
1) If the yield function is 'soft' in that it is held pending until the critical section is exited, then you need to nothing as a yield cannot happen unless the critical nesting count is zero anyway.
2) If you yield function will happen immediately, even if you are in a critical section (which is typical for a trap type instruction) then you will need to store the critical nesting count as part of the task context. Then when you exit the critical section you also restore the critical nesting count count, and if the count is 0 restore interrupts in their enabled state, and if the critical nesting count is not zero restore interrupts in their disabled state.
The memory barrier instruction on enable/disable of interrupts is still very much relevant in this scenario.
Thank you very much @Real Time Engineers Ltd, I shall work on it, as you described. Will get back to you with the observations and results.