Interrupt issues

General discussion on mikroPascal PRO for PIC32.
Author
Message
LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Interrupt issues

#1 Post by LGR » 05 Dec 2012 21:05

I'm having issues with interrupts, and it's not exactly clear what the compiler is doing with context switching.

Let me start with the problem: I have a timer interrupt on timer 1, which interrupts every 100 ms, for various timers. I also have two UART interrupts, which are set for both receive and transmit. Everything works ok, as long as the incoming data to the UART is regular. The problem is when an overrun jam occurs. When I send a second string before the first one is completely received, the interrupts all stop, and it appears that the MPU is crashed. I can do this very repeatably. I have an LCD which shows interrupt routine counts, and the timer count counts up ten times a second, and the UART count counts for each byte sent and received. I can send strings over and over, and the counters respond properly, but when I send two strings, the counters for both interrupts freeze.

I'm not sure what's happening with the context saving, because I'm using 'ics ICS_AUTO'. If I use SRS, I can see why a crash would happen with three interrupts, but when I use SOFT, the UART interrupts stops at 3 bytes for some odd reason. What I want to know is how exactly does the compiler decide to use SOFT or SRS if AUTO is selected, and if SOFT is used, does it push everything on to the stack, so that the program will eventually return the same way it arrived?

Something isn't working the way it's supposed to, unless I'm not understanding correctly how it's supposed to work.
If you know what you're doing, you're not learning anything.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#2 Post by jpc » 06 Dec 2012 10:14

LGR,

would you have some minimal code that produces this? What PIC are you experiencing this with?
Au royaume des aveugles, les borgnes sont rois.

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Re: Interrupt issues

#3 Post by LGR » 06 Dec 2012 16:25

Actually, it's a rather large code that doing this. I'm not sure that the interrupt context saving is the problem, I just wanted to make sure I understood exactly what each method does. The documentation isn't clear, but I think "soft" means the stack. I just don't understand how "auto" decides what to do.

My intuition tells me that an array index or pointer is going out of range somewhere, but it's a maddeningly elusive thing.
If you know what you're doing, you're not learning anything.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#4 Post by jpc » 06 Dec 2012 16:47

i agree this needs clarification in the help but i never face problems like you describe when using AUTO, one possible problem i can see is when we do not set the priority-level of interrupts according to the level passed to the compiler in the declaration of the ISR ( ilevel). This is also mainly guessing but i can imagine the compiler to use this in relation to the contextsaving of individual ISR's.
This might be a possible improvement on the Interrupt assistant, ideally it would generate the code (or at least some pseudo code) to set the priority level according to the ilevel.
Au royaume des aveugles, les borgnes sont rois.

User avatar
janko.kaljevic
Posts: 3565
Joined: 16 Jun 2011 13:48

Re: Interrupt issues

#5 Post by janko.kaljevic » 06 Dec 2012 17:02

Hello,

Most important thing with interrupts on PIC32 controllers is to match interrupts levels.
For example when you set Interrupt priority bits for UART interrupt U2IP bits has to match ilevel number in interrupt declaration:

Code: Select all

procedure interrupt(); iv IVT_UART_2; [b]ilevel 7[/b]; ics ICS_SRS;
...
  U2IP0_bit := 1;            // set interrupt
  U2IP1_bit := 1;            // priority
  U2IP2_bit := 1;            // to 7
When you set context saving to ICS_SRS, it means that it will be used Shadow Register Set for this interrupt, and on PIC32795, you can choose which level this is in Edit project window. And usually you should choose SRS for highest interrupt priority, and only one interrupt should use SRS.
All other interrupts will use primary register set (ICS_SOFT)

ICS_AUTO means that compiler will choose which one will be SRS and which one SOFT.

Finally ICS_OFF means that there will be no context saving at all. This way interrupt prolog will be minimal, but it is user responsibility to save context on it's own.

Best regards.

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Re: Interrupt issues

#6 Post by LGR » 06 Dec 2012 18:03

JPC, in the past, I've had two issues. One is that when you set priority, it doesn't set subpriority, so it's incomplete. The second is probably related to the first; if I don't set the IPC register, it doesn't work, so setting the priority in the Interrupt Assistant isn't sufficient.

My initialization for UART1 looks like this:

Code: Select all

  U1BRG := (5000000 div modport1.baud) -1;   //set baud
  U1MODE := 0x8000; // UART enabled, U1TX and U1RX pins only, 1 stop bit
  U1STA := 0x5400; // 14 = interrupt when all chars xmitted, 
  // 12 = receiver enabled, 10 = transmitter enabled
  U1RXIE_bit := 1; U1TXIE_bit := 1;
  U1RXIF_bit := 0; U1TXIF_bit := 0;
  IPC6 := IPC6 or 0x1F;  // Interrupt priority 7/3
Without the IPC6 assignment, it doesn't work. I would think the interrupt header should take care of all of this, which is a real pain, because you have to look through three Microchip docs (UART, interrupts, and MCU) to determine which register and bits to set. :evil:
If you know what you're doing, you're not learning anything.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#7 Post by jpc » 06 Dec 2012 18:14

i never bothered with sub-priority, from my understanding this is not a real must until you need to refine the order of priorities within one priority level, however the main priorities MUST be set equal to Ilevel , i fully agree this might be done for us by the assistant ( in its current form it is of little use for P32 i think)
If you study the naming conventions of these registers it is not too difficult though to do it manually, instead of referring to specific IPC registers, i always use the bit declarations as provided by the definitionfiles :

Code: Select all

  U1IP0_bit := 0;              
  U1IP1_bit := 1;                   
  U1IP2_bit := 1;                     // Set UART1 interrupt to level 6
This avoids looking up each time in which IPC register those bits are hiding
Au royaume des aveugles, les borgnes sont rois.

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Re: Interrupt issues

#8 Post by LGR » 06 Dec 2012 22:37

But the one question that I didn't get an answer to is, does "SOFT" cause context to be saved on the stack, so that if one interrupt interrupts another interrupt, it will all resolve correctly?
If you know what you're doing, you're not learning anything.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#9 Post by jpc » 07 Dec 2012 09:44

you may be right pushing this question to its limits, for the time being only in the debugger i did this little test :

Code: Select all

program Nested_interrupts;
var uart_rd : char;

procedure indirect1;
begin
  nop;
end;


procedure tmr1isr(); iv IVT_TIMER_1; ilevel 1; ics ICS_AUTO;
begin
  indirect1;
  t1if_bit := 0;
end;

procedure tmr2isr(); iv IVT_TIMER_2; ilevel 2; ics ICS_AUTO;
begin
  nop;
  t2if_bit := 0;
end;

procedure tmr3isr(); iv IVT_TIMER_3; ilevel 3; ics ICS_AUTO;
begin
  nop;
  t3if_bit := 0;
end;

procedure tmr4isr(); iv IVT_TIMER_4; ilevel 4; ics ICS_AUTO;
begin
  nop;
  t4if_bit := 0;
end;

procedure tmr5isr(); iv IVT_TIMER_5; ilevel 5; ics ICS_AUTO;
begin
  nop;
  t5if_bit := 0;
end;

begin

  AD1PCFG := 0xFFFF;                  // Configure AN pins as digital I/O

  T1IP0_bit := 1;
  T1IP1_bit := 0;
  T1IP2_bit := 0;
  
  T2IP0_bit := 0;
  T2IP1_bit := 1;
  T2IP2_bit := 0;
  
  T3IP0_bit := 1;
  T3IP1_bit := 1;
  T3IP2_bit := 0;
  
  T4IP0_bit := 0;
  T4IP1_bit := 0;
  T4IP2_bit := 1;
  
  T5IP0_bit := 1;
  T5IP1_bit := 0;
  T5IP2_bit := 1;

  T1IE_bit := 1;                      // Enable Timer1 interrupt
  T2IE_bit := 1;                      // Enable Timer2 interrupt
  T3IE_bit := 1;                      // Enable Timer3 interrupt
  T4IE_bit := 1;                      // Enable Timer4 interrupt
  T5IE_bit := 1;                      // Enable Timer5 interrupt
  EnableInterrupts();                 // Enable interruts as previously set

  while (TRUE) do                     // Endless loop  wait for interrupt to occurs
  begin
    nop;
    nop;
    nop;
  end;
end.
i ran the code in the debugger until the main loop, then i triggered ISR1 and step through until in the procedure Indirect1, here i trigger ISR2, step into it, trigger ISR3 etc.
All seems to work ok, i will try to find a way of testing this on hardware, possibly forcing flags from within an ISR will do the trick (not sure this works on this architecture though)
Au royaume des aveugles, les borgnes sont rois.

User avatar
janko.kaljevic
Posts: 3565
Joined: 16 Jun 2011 13:48

Re: Interrupt issues

#10 Post by janko.kaljevic » 07 Dec 2012 14:47

Hello,

Very nice topic, and I am glad to contribute clearing most of the questions here on one place.

We can discuss adding IPC bits generation in interrupt assistant and I will forward this request for consideration in future.

ICS_SOFT will definitely do the context saving, and user do not has to be bothered with this part.
As I said the only time when this is not generated is when user explicitly declares ICS_OFF.
You can build any example with interrupt and check in listings file generated interrupt prolog.
And you will be able to see clearly differences between different ICS modes.

Please note that interrupt controller will disable all interrupts automatically when entering ISR.
But user can enable them manually (if he wants) at any moment of ISR. This way controller makes sure that interrupt prolog is not interrupted with other ISR.
For example you can do following:

Code: Select all

procedure tmr1isr(); iv IVT_TIMER_1; ilevel 1; ics ICS_AUTO;
begin
  EnableInterrupts();
  indirect1;
  t1if_bit := 0;
end;
this way you will allow nested interrupts.
PIC32-int.JPG
PIC32-int.JPG (43.44 KiB) Viewed 6501 times
http://ww1.microchip.com/downloads/en/D ... 61108G.pdf

Best regards.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#11 Post by jpc » 07 Dec 2012 14:54

Janko, are you sure this Enableinterrupts is required inside each ISR that would like to allow interrupting by higher priority interrupts? I have my doubts there, was just looking at test on hardware, will post it when cleaned up. For the moment i have the strong impression that inside any interrupt, a higher priority request will immediately be served.
Au royaume des aveugles, les borgnes sont rois.

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Re: Interrupt issues

#12 Post by LGR » 07 Dec 2012 16:19

Maybe my question wasn't completely clear (but JPC seems to understand the point): what I wanted to know, is does "SOFT" save context on the stack, as opposed to in a set of fixed locations? Only if context is saved on the stack can you have nested interrupts. It seems illogical to me to have a vectored prioritized multiple interrupt system, if it wasn't the intention of Microchip (or MIPS, really) to allow the possibility of nested (but not recursive) interrupts. If you disable all interrupts on entering the ISR, I see no point in using multiple prioritized interrupts.

So the question, again is: is context using "SOFT" saved on the stack, or in a set of static RAM locations? JPC's test seems to suggest that it's saved on the stack, but I'd like that confirmed.
If you know what you're doing, you're not learning anything.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#13 Post by jpc » 07 Dec 2012 16:22

ok, i have created some testenvironment that allows for systematic testing interrupt priority and related behaviour, at the moment i am not bothering with subpriority levels , this could easily be added if someone is interested.
the following code is used on LV32MX board.In order to make it all very visible i used a oscillatorsetting of 8 mhz.

Code: Select all

program interrupt_testing;

// framework to test interrupt priority and related behaviour on P32MX

procedure indirect1;
begin
  latc1_bit := 1;
  tmr2 := 0;             // make sure it will not trigger due to timeout
  t2if_bit := 1;         // force the interrupt flag for tmr2 , as this timer-ISR has higher priority it should trigger immediately
end;


procedure tmr1isr(); iv IVT_TIMER_1; ilevel 1; ics ICS_AUTO;
begin
  indirect1;
  t1if_bit := 0;
end;

procedure tmr2isr(); iv IVT_TIMER_2; ilevel 2; ics ICS_AUTO;
begin
  latc2_bit := 1;
  delay_ms(500);
  tmr1 := 0;
  latc1_bit := 0;
  delay_ms(500);
  tmr1 := 0;
  delay_ms(500);
  tmr1 := 0;
  delay_ms(500);
  tmr1 := 0;
  delay_ms(500);
  tmr1 := 0;
  latc2_bit := 0;
  t2if_bit := 0;
end;

procedure tmr3isr(); iv IVT_TIMER_3; ilevel 3; ics ICS_AUTO;
begin
  t3if_bit := 0;
end;

procedure tmr4isr(); iv IVT_TIMER_4; ilevel 4; ics ICS_AUTO;
begin
  t4if_bit := 0;
end;

procedure tmr5isr(); iv IVT_TIMER_5; ilevel 5; ics ICS_AUTO;
begin
  t5if_bit := 0;
end;

begin
  trisb := 0;
  trisc := 0;
  latc := 0;
  AD1PCFG := 0xFFFF;                  // Configure AN pins as digital I/O
 
  T1IP0_bit := 1;
  T1IP1_bit := 0;
  T1IP2_bit := 0;
  
  T2IP0_bit := 0;
  T2IP1_bit := 1;
  T2IP2_bit := 0;
  
  T3IP0_bit := 1;
  T3IP1_bit := 1;
  T3IP2_bit := 0;
  
  T4IP0_bit := 0;
  T4IP1_bit := 0;
  T4IP2_bit := 1;
  
  T5IP0_bit := 1;
  T5IP1_bit := 0;
  T5IP2_bit := 1;
  
  T1CON := %01110000;              // prescaler 1:256      // all as slow as possible for the tes, we want to see sequence on the led's
  T2CON := %01110000;
  T3CON := %01110000;
  T4CON := %01110000;
  T5CON := %01110000;

  PR1 := $ffff;
  PR2 := $ffff;
  PR3 := $ffff;
  PR4 := $ffff;
  PR5 := $ffff;
  
  ON__T1CON_bit := 1;
  ON__T2CON_bit := 0;
  ON__T3CON_bit := 0;
  ON__T4CON_bit := 0;
  ON__T5CON_bit := 0;

  T1IE_bit := 1;                      // Enable Timer1 interrupt
  T2IE_bit := 1;                      // Enable Timer2 interrupt
  T3IE_bit := 0;                      // Enable Timer3 interrupt
  T4IE_bit := 0;                      // Enable Timer4 interrupt
  T5IE_bit := 0;                      // Enable Timer5 interrupt
  EnableInterrupts();                 // Enable interrupts as previously set

  while (TRUE) do                     // Endless loop  wait for interrupt to occurs
  begin
    nop;
  end;
end.
for simplicity i assigned up to 5 timers with increasing priotity, the shown example uses only 2.
I do not reenable any interrupts inside ISR, as stated before i do not think this is required.
There is a little trick that needs explaining perhaps, i enable interrupts on TMR2 but as such this timer is NOT enabled, i simply force the flag in order to see how the interrupt-controller responds.
Au royaume des aveugles, les borgnes sont rois.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Interrupt issues

#14 Post by jpc » 07 Dec 2012 16:24

LGR, seems our post crossed each other, not that i have real answer, in fact it gave me the idea that we would want to look at the stack in a debugging session, perhaps that could be implemented
Au royaume des aveugles, les borgnes sont rois.

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

Re: Interrupt issues

#15 Post by LGR » 07 Dec 2012 17:15

FWIW, my original problem was that with one timer interrupt, and two UART interrupts, I was locking the MPU by sending overrun strings to the UART. I could send strings spaced every few seconds all day, but if I started sending one before the previous one was finished (from the mE USART terminal), it would crash the MPU.

I changed the timer interrupt (highest priority) to:

Code: Select all

procedure Timer1Int(); iv IVT_TIMER_1; ilevel 7; ics ICS_SRS;
begin
  disableinterrupts;
  if lcdtmr <> 0 then dec(lcdtmr);
  inc(ic1);
  T1IF_bit := 0; 
  if SixSecCtr = 0 then // Six second counter - update FRAM
  begin
    Timerflag := 1;
    SixSecCtr := 59;
  end
  else dec(SixSecCtr);
  if modport1.CFTMRC <> 0 then dec(modport1.CFTMRC);
  if modport2.CFTMRC <> 0 then dec(modport2.CFTMRC);
  if timer <> 0 then dec(timer);
  if t1sec <> 0 then dec(t1sec);
  enableinterrupts;
end;
Now I don't seem to have the problem any more. That does NOT mean that this was the solution; there could have been a number of other things that fixed it, without me knowing. I'll post anything more that I learn.
If you know what you're doing, you're not learning anything.

Post Reply

Return to “mikroPascal PRO for PIC32 General”