AT91SAM7X, uIP Demo, Interrupts

dercmdr wrote on Wednesday, May 16, 2007:

Hi!

I am using the uIP Demo as a base for my project. Now I have to use two interrupts. I wrote isr Routines similar to the EMAC routine. Now I have the problem, that sometimes the interrupts doesn’t work. For Example: When I trigger the interrupt on a PIO several times, it suddenly doesn’t work anymore. When I then trigger another PIO interrupt, which ist handled by the same routine, the first interrupt works again a few times, and so on. What happens when I post an item in a queue in an isr while the queue is full? Is it a problem if I use a semaphore in an isr and the isr has to wait for it? I checked all the registers and everything except the interrupt pending register looks ok. I have no idea how to solve this problem and hope someone can help me.

Thx!

nobody wrote on Wednesday, May 16, 2007:

Definitely do not use blocking API calls in interrupts.  In fact, don’t use any API calls that do not end in FromISR.

Sometimes it is best to get the interrupts working in a basic proejct without the freertos.  Then when that works add in the freertos.  This way you limit the source of the problem to make it easier to find where it is.

dercmdr wrote on Wednesday, May 16, 2007:

I tested the interrupts without freertos and they work without problems. So they should work.

In the interrupts I only use xQueueSendFromISR, which should be no problem. I think it is possible that the task which receives the queue item is not fast enough so the queue is not empty at the next isr call. Could that cause such a problem?

In fact the blocking interrupt remains even after a debugger reset. It disappears when I cut the power. Seems to be some hardware thing or something that remains while a debugger reset.

chaalar wrote on Wednesday, May 16, 2007:

It sounds like you are having problems about handling PIO interrupts. Can you post your interrupt routine so that someone may figure out what’s going on.

xQueueSendFromISR should not cause something strange in your interrupt routine in case queue is full.

dercmdr wrote on Wednesday, May 16, 2007:

OK here is the code of the isr which is called from the asm wrapper:

{
  unsigned int unSend[2]={0,0};
  portBASE_TYPE xSwitchRequired = pdFALSE;
  unSend[0]=AT91C_BASE_PIOA->PIO_ISR;
  unSend[1]=AT91C_BASE_PIOB->PIO_ISR;
 
  xSwitchRequired = xQueueSendFromISR(gqhDIIRQ,unSend,pdFALSE);

  portEND_SWITCHING_ISR( xSwitchRequired );
 
  AT91C_BASE_AIC->AIC_EOICR = 0;
}

The rest of the work is done in a high priority task as recommended, which is woken by the queue.

nobody wrote on Wednesday, May 16, 2007:

Which compiler are you using?

dercmdr wrote on Wednesday, May 16, 2007:

IAR Embedded Workbench

dercmdr wrote on Friday, May 18, 2007:

I now found out that the same error occurs without freertos. I wrote comparable code for use without an operating system, which produces exactly the same behaviour.

Further I found out that when an interrupt gets disabled, it is disabled for the whole port and not just for the one PIO line. Only an interrupt on the other port can reenable interrupts on the port. Anyone familiar with this behaviour?

embeddedc wrote on Friday, May 18, 2007:

Are you clearing the EIC (interrupt controller) as well as the actual interrupt source?

dercmdr wrote on Friday, May 18, 2007:

I read PIO->ISR which should clear the PIO interrupt and I write AIC_EOICR at the end of the isr. Is there anything else to clean?

chaalar wrote on Sunday, May 20, 2007:

On Sam7X you can not disable only one PIO line. All the pio lines are ORed to the interrupt controller. You should definitely re-enable interrupts before leaving ISR.(or some other appropriate place)

I guess you are having very short burst of interrupts. I mean it seems like there are pulses on your PIO line which have durations comparable 5-10 microseconds. Can you verify this?

If this is the case, since you will have two PIO interrupts for one pulse, your interrupt routine can be called more frequently then you expected which may cause you some trouble for the interrupt handling.

dercmdr wrote on Monday, May 21, 2007:

I got an interrupt approximately every 10 ms (according to the mains frequency).

I tried re-enabling and disabling / re-enabling interrupts at the end of the interrupt routine but it did not change anything, although I don’t see why the interrupts should become disabled, because I do not disable them in my program.

dercmdr wrote on Monday, May 21, 2007:

I think I finally found it, but no solution till now. Heres the problem:

In my ISR I read PIOA->PIO_ISR and PIOB->PIO_ISR. The I put the values in a queue and end the isr with writing to AT91C_BASE_AIC->AIC_EOICR.

I think that the AIC interrupt pending bit is only set when PIO_ISR changes from 0 to 1. PIO_ISR is resettet when read. Now when I am reading PIO_ISR in my isr it is resettet to 0. If another interrupt occurs before writing to AIC_EOICR, the bit in PIO_ISR changes from 0 to 1. Since the isr is still running, the interrupt pending bit is still there. Now when I write to AIC_EOICR, the pending bit gets resettet and since the PIO_ISR bit ist still on 1, no new pending bit is being generated, so no more interrupts from the peripherial. When I generate an interrupt on the other PIO controller, both PIO_ISR registers are being read and after it the interrupts work again until the error happens again. This would explain everything. Only thing is I am not sure if an interrupt pending bit for a PIO Controller is only generated when PIO_ISR goes from 0 to 1, but I think this is the case from what I saw while debugging.

Now how can I prevent this error? I tried disabling interrupts, but the same error occurs. Only thing that seems to work is reading PIO_ISR directly before writing AIC_EOICR. But in doing this I can miss interrupts. I thought of writing some irq disabling and enabling code in the asm wrapper, but I am unsure what exactly I would have to write there.

Has anyone an idea which could fix this problem?

Thx!

peter_z wrote on Friday, May 25, 2007:

Hello Torben,

I think you should clear the interrupt before calling portEND, like this:

AT91C_BASE_AIC->AIC_EOICR = 0;
portEND_SWITCHING_ISR( xSwitchRequired );

But why do a ‘switch ISR’? This is just an interrupt during a running task and we can continue this task after handling the interrupt.
I think a ‘port restore’ is adequate:
portRESTORE_CONTEXT();

Regards,
Peter

dercmdr wrote on Wednesday, May 30, 2007:

Hi Peter,

portRESTORE_CONTEXT is being called in the asm wrapper after the isr hast finished. So I call portEND_SWITCHING_ISR in the isr and portRESTORE_CONTEXT after the isr. This is the way it is done in the uIP example in the EMAC isr. I was wondering why portEND_SWITCHING_ISR is necessary. As far as I understand it allows a woken task to get in the running state directly after the isr. Is this wrong? What is the difference if I do not use portEND_SWITCHING_ISR?

davedoors wrote on Wednesday, May 30, 2007:

Coincidentally we were just discussing that in the thread https://sourceforge.net/forum/forum.php?thread_id=1744949&forum_id=382005 - look toward the end.  The macros are only needed if you want the task to run immediately.

Dave.

dercmdr wrote on Wednesday, May 30, 2007:

So portEND_SWITCHING_ISR switches directly to the activated task, lets it do its work and returns to the isr? Or does it set the activated task to be the next activated task after leaving the isr? I am slightly confused about this now.

The macro portRESTORE_CONTEXT is used in the asm wrapper and I didn’t change this. As far as I understood from other FreeRTOS ports, a asm wrapper is needed, or would it also work without any asm wrapper at all?

davedoors wrote on Wednesday, May 30, 2007:

I’m jumping into this thread without reading the whole thing so maybe am confusing things.

The macros at the end of the ISR allow the scheduler to select the next task to run.  In this way it is possible for the ISR to interrupt one task, but then return to another task. 

This is useful if the ISR wakes a high priority task.  If the ISR wakes a task of lower priority than the task that was originally interrupted, then the ISR will return to the originally interrupted task. 

Also if interrupts require a lot of processing it permits you to perform the processing within an ISR handler task rather than in the interrupt itself.  This has the advantage of allowing interrupts to remain enabled while the processing is performed - thus the ISR can be very quick and interrupt nesting is not required.  But maybe I’m getting too far of topic here :wink:

In any case, the asm wrapper is only needed if you want a context switch to occur within the ISR.  If this is not the case then you can write the ISR just as a normal ISR using the syntax required by your compiler.

Dave.

dercmdr wrote on Thursday, May 31, 2007:

Hi Dave!
Thanks for your explanations. Unfortunately I am unsure of a few things concerning interrupt handling and I am hoping you can help me on this.
At the moment I am using isrs the following way: An interrupt activates an interrupt handler, which runs portSAVE_CONTEXT and then jumps to a c interrupt handler, which puts an item in a queue, which activates a high priority task. After the c interrupthandler returns to the asm wrapper, portRESTORE_CONTEXT is being run. In my c interrupthandler I use portEND_SWITCHING_ISR to activate the high priority task. All interrupts have the same priority, so no nested interrupts should occur. Now there are two things which I do not understand:
Does portEND_SWITCHING_ISR immediately switch to the activated high priority task, which makes its work, and then returns to the c interrupthandler or does it make sure that after the c interrupthandler and the asm wrapper the high priority task gets activated?
What exactly do the portSAVE_CONTEXT and portRESTORE_CONTEXT macros do? Since I am using an AT91SAM7X and the uIP demo, I have only the EMAC interrupt as an example and in this it is done exactly as I do it now. Maybe I can have the interrupts handled faster without the asm wrapper or the portEND_SWITCHING_ISR macro? I think I read in the description of another port that interrupts have to be handled with an asm wrapper but in this port there is no really explanation of the interrupts other than the EMAC example.

Best regards.

Torben

rtel wrote on Thursday, May 31, 2007:

> Hi Dave!
> Thanks for your explanations. Unfortunately I am unsure of a
> few things concerning
> interrupt handling and I am hoping you can help me on this.
> At the moment I am using isrs the following way: An interrupt
> activates an interrupt
> handler, which runs portSAVE_CONTEXT and then jumps to a c
> interrupt handler,
> which puts an item in a queue, which activates a high
> priority task. After the
> c interrupthandler returns to the asm wrapper,
> portRESTORE_CONTEXT is being
> run.

From this snippet it sounds like you are using IAR, as GCC does not require the asm wrappers.  If so your description is correct.

> In my c interrupthandler I use portEND_SWITCHING_ISR to
> activate the high
> priority task. All interrupts have the same priority, so no
> nested interrupts
> should occur. Now there are two things which I do not understand:
> Does portEND_SWITCHING_ISR immediately switch to the
> activated high priority
> task, which makes its work, and then returns to the c
> interrupthandler

Again, assuming IAR, then the answer is really no.  portEND_SWITCHING_ISR just tells the scheduler that it might need to select a new task to run, as the interrupt itself has unblocked a task.  In this case portEND_SWITCHING_ISR is just a sequential function call, its just like calling any other function from within an interrupt.

If the unblocked task has the highest priority of all ready tasks then the scheduler will decide that this is the task that should be executed next.

> or does
> it make sure that after the c interrupthandler and the asm
> wrapper the high
> priority task gets activated?

That is correct.  portEND_SWITCHING_ISR has told the scheduler to check which is the highest priority ready task.  The asm wrapper at the end of the interrupt causes the processor to start executing the task selected by the scheduler.

Say task A has a priority of 0 and is running, task b a priority of 1 and is blocked:

1) An interrupt executes, interrupting task A.  The asm wrapper saves the context of task A and the interrupt C code then runs.

2) The interrupt C code wakes task b, which has a priority higher than A.

3) portEND_SWITCHING_ISR() is called, this causes the scheduler to recognise that task A is now in the ready state, and that it has a priority higher than task b.

4) The asm wrapper executes, causing the ISR to restore the context of (and start running) task B.

> What exactly do the portSAVE_CONTEXT and portRESTORE_CONTEXT
> macros do? Since
> I am using an AT91SAM7X and the uIP demo, I have only the
> EMAC interrupt as
> an example and in this it is done exactly as I do it now.
> Maybe I can have the
> interrupts handled faster without the asm wrapper or the
> portEND_SWITCHING_ISR
> macro? I think I read in the description of another port that
> interrupts have
> to be handled with an asm wrapper but in this port there is
> no really explanation
> of the interrupts other than the EMAC example.

The asm wrapper is only required if you want to return directly into another task.  In the example above, the interrupt interrupted task B, but returned to task A.  This is what you want if task A is urgent. 

If task A is not urgent then the asm wrapper can be removed and the interrupt written as per the IAR documentation.  In this case task A is put into the ready state and, as the higher priority task, will get selected the next time the tick interrupt occurs or task b blocks or yields.

Regards.