str730x prefetch abort after ISR returns

johughes2002 wrote on Monday, January 05, 2009:

Hi,

I’ve been working on an str730 port for a while, based on the str750x code.

I had the scheduler running very smoothly with several tasks, etc, and started working on my actual app. Only then have I run into a very odd issue.

In my app I’m setting up an ISR in addition to the tick ISR to respond to both rising and falling edges (push button) on a GPIO port and stick a message onto a queue: http://pastebin.com/m7eb2ae2a

The messages are received by another task which processes them.

I’m setting up the hardware for the ISR as follows:

EIC_ExternalITFilterConfig( ENABLE );
EIC_ExternalITTriggerConfig(EXTERNAL_IT14, EXTIT_TRIGGER_Rising_Falling);
EIC_IRQChannelPriorityConfig(EXTIT14_IRQChannel, 1);
EIC_IRQChannelConfig(EXTIT14_IRQChannel, ENABLE);

Now, this runs about 80% of the time without issue. But the odd time I push the button, I get a Prefetch Abort. The most reliable way of reproducing the issue is to just hammer on the button as fast as possible.

Setting a breakpoint on the prefetch handler doesn’t help much. $lr is typically holding something like 0xe1a00000. Subtracting 4 gives me the address that was attempted to prefetch, but I have no idea which line was telling it to prefetch there.

The IRQ Handler is nearly the same as the str750 port: context is saved and restored automatically before the ISR routine is called: http://pastebin.com/m5d0de0b6

portSAVE_CONTEXT and portRESTORE_CONTEXT are verbatim the same as str750.

After trying and playing with everything I could think of for the past few days, I still haven’t come up with any really good idea for what is possibly wrong. The issue appears to be a race condition somewhere.

A hunch might be this: In the IRQHandlers "ReturnAddress" section, the IPR bits (interrupt pending) are cleared, and then portRESTORE_CONTEXT is called. Would it not be possible then that an interrupt occurs during portRESTORE_CONTEXT, or during the ReturnAddress section, and somehow corrupts the stack?

Any hits would be very helpful. I’m at a loss on this one.

davedoors wrote on Monday, January 05, 2009:

It looks like the function pvEventCreate() is doing some dynamic memory allocation. Does this use a critical section? If so that could be the problem. Critical sections cannot be used from interrupts. Maybe you need to provide some statically allocated buffers, or provide a version of the memory functions that can be used from interrupts. Generally dynamic memory allocation in interrupt can be problematic in any case because of the time it takes to perform.

johughes2002 wrote on Monday, January 05, 2009:

pvEventCreate() does call pvPortMalloc()

I’ll try doing it with a pre-allocated buffer. Thanks for the tip.

johughes2002 wrote on Tuesday, January 06, 2009:

Ok,

I trimmed down my ISR routine so that pvEventCreate() will return a pointer to a pre-allocated, pre initialised struct. This seems to have helped, but hasn’t completely solved the problem. I’m still getting random prefetch aborts.

I experimented a bit more, and found that I could eliminate the aborts if I didn’t make the call xQueueSendFromISR()

I then gutted everything, so that all that’s running is the ISR sending things to the queue, and the receiver sitting on xQueueReceive (and doing nothing else), and I’m still getting the odd prefetch abort.

There must be some race condition entering or exiting the IRQ, but I’m at a loss as to what it may be.

rtel wrote on Tuesday, January 06, 2009:

> I experimented a bit more, and found that I could eliminate
> the aborts if I didn’t make the call xQueueSendFromISR()

The first thing to check is that you are not simply overflowing the task stack.


Next - looking at your code it seems you are posting a pointer to a pointer onto the queue.  This is quite a common thing to do but also makes it easy to get into a muddle when you read the value off the queue, so just double check your code is doing what you actually intend there.  Also check the memory being pointed to is not being used or deleted anywhere else. 

I know I am just stating the obvious so far…but sometimes its worth doing.

> I then gutted everything, so that all that’s running is the
> ISR sending things to the queue, and the receiver sitting on
> xQueueReceive (and doing nothing else), and I’m still getting
> the odd prefetch abort.

You mentioned that you changed the code for entering and exiting the queue so the context save was performed before the handler C function was called.  The code you posted does not look familiar, but it’s a while since I used the STR7.  Are you using IAR?  If you look at the GCC demo there is a file that does exactly what you want (I think?).  Have a look at the function IRQHandler in FreeRTOS\WorkingCopy3\Demo\ARM7_STR75x_GCC\SystemFiles\crt0_STR75x_FreeRTOS.s.  I don’t know if that will help or not.  Make sure the stack pointer is exactly in the same place when exiting the asm function as when you went in.

>
> There must be some race condition entering or exiting the
> IRQ, but I’m at a loss as to what it may be.

On an ARM7 interrupts should be disabled as you enter the IRQ, and I cannot see that you are enabling them again, so you should not be getting any clashes with the tick interurpt - which I presume is the only other interrupt that is executing?

Regards.