On an LPC2134 based system using GCC, I’ve got an issue where FreeRTOS causes a data abort when I use portEXIT_SWITCHING_ISR.
I’ve got an I2C driver where the ISR simply reads the I2C status and passes it to a task to process. At the end of the I2C ISR I’ve got this:
portEXIT_SWITCHING_ISR( xSemaphoreGiveFromISR( hI2Csemaphore, pdFALSE ) );
which works for a random number of I2C interrupts (usually a few hundreds) after which the processor fires a data abort. If I simply pass pdFALSE to the portEXIT_SWITCHING_ISR macro, the code works fine but my throughput is hit because only one interrupt can be processed per schedule cycle. The task waiting on the semaphore is high priority (max priority – 1).
When the data abort happens, the processor is invariably in the vListInsertEnd() function on the line saying
pxNewListItem->pxNext = pxIndex->pxNext;
and pxIndex is pointing to somewhere in the internal register address space (0xE001XXXX), which leads me to believe that there is an issue with the task list handling being re-entered when it shouldn’t be. There seems to be very little protection code around the list code.
I’ve compiled in both "all ARM" mode and in "mostly thumb with ISRs in ARM" mode. Both perform the same.
Anyone got any clues to what could be happening?
Most likely a stack size problem.
There is not much protection in the list code as it is trusted code. The list code will malfunction if it has already been corrupted – indicating an error outside of the list code itself.
Generally it would not be a good idea to pass a function as a parameter to a macro, but in this case I think there is no problem.
Try increasing the stack sizes, or at least examining the stack high water marks to see if an are susceptible.
Yes, thanks, I will look at that, although generally I am not using much stack.
Interesting note though. I’ve just recompiled with -O1 instead of -O0, having seen someone else reporting issues with -O0 and the problem seems to have gone away. Spooky. You’d think -O0 was safer?
I’ve done quite a bit more work on this and can basically only get it working at -O3. The -O1 option just took a lot longer to break, but it still breaks.
Of course, debugging code with -O3 is a complete pain. I wonder if this issue is something to do with the comment in PortISR around line 195:
"/* The code generated by the GCC compiler uses the stack in different ways at
different optimisation levels. The interrupt flags can therefore not always
be saved to the stack. Instead the critical section nesting level is stored
in a variable, which is then saved as part of the stack context. */
I’m not sure what is meant by "the interrupt flags" in this comment. Anyone who knows what the sentiment is here?
The original ARM7 port used stack pushes to hold the status register. This worked fine at some optimisation levels but not others so it was changed to use the critical section nesting method instead. This is less efficient but works at all optimisation levels. It should be safe no matter what as it makes no assumptions as to what the compiler is doing.
Have you tried the -fomit-frame-pointer option that somebody mentioned before fixed the -O0 problem?
Are you using GNUARM or WinARM? I have only used GNUARM and have never seen a problem at -O0, people who have problems seem to be the WinARM users, but I’m not sure if this is anything to do with it.
I would image that due to the very aggressive optimisation performed by GCC that problems could occur at -O3, so it is odd that -O0 should show the symptoms – unless of coarse it is a simple stack overflow caused by the less efficient unoptimised code???
I’m using winarm. I’ve not tried -fomit-frame-pointer as yet, I didn’t learn about its effect on the issue until late Friday night. I’ll try that on Monday.
I’ll let you know how I get on.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.