PIC Interrupts

5/6/08

What seems important at this point is to see if I can get handling of a user hardware interrupt. For example, I want to see if I can use a timer interrupt. First, I want to see if the PICDEM firmware already makes use of a timer interrupt.

Searching for the word "interrupt" in the PICDEM firmware C code, I can only see reference to the UIE, UIR, and UEIE interrupts-- i.e., the USB interrupts on the microcontroller. I'm now going to look into using interrupts on the microcontroller. I want my first example to not make use of USB at all, seeing as I've never used interrupts on these PIC microcontrollers before.

p. 478 to 480 of Predko (Programming and Customizing the PIC Microcontroller, 3rd Edition) considers the TMR0 interrupt.

I'm going to work from an example on p. 125-6 in Wilmshurst (2007, Designing Embedded Systems with PIC Microcontrollers ), which is for a pic16f84a chip. I'll use the MPLAB IDE simulator to run this code. To run the code with the MPLAB simulator, I'm selecting Debugger -> Select Tool -> MPLAB SIM in the MPLAB IDE. When I run this code in the simulator it tells me the watchdog timer (WDT) has expired. I've now added __CONFIG _WDT_OFF into the assembly code.

I'll now open a Watch window to diplay PORTA, PORTB, INTCON and PCL using the simulator, by View -> Watch, and then clicking "Add SFR" for the PORTA, PORTB, INTCON. and PCL. How do I get the Watch window to display the values in real-time as the data is changing? Under Debugger -> Settings, and the Animation/Realtime Updates tab, check the the "Enable Realtime watch updates" checkbox.

Now, I want to cause the interrupt to happen. To do this, I am using Debugger -> Stimulus -> New Workbook. I've saved the stimulus workbook as Stim1. I've used the Asynch tab of this Stimulus workbook to define Pin / SFR RB0 as Toggle. A symbol ">" appears to the left of this row, and causes the pin to toggle, apparently. Yes, I see now in the Watch window that this does indeed toggle pin RB0. I find the example from Wilmshurst a wee bit confusing. The interrupt handler changes the same port as the mainline code. I'm going to change this so that the mainline code just loops, and the interrupt handler just toggles a bit on port A. Yeah! I now have my first successful interrupt code working on a PIC microcontroller. You have to toggle RB0 twice to invoke the interrupt handler, which then activates the ISR (interrupt handler), and toggles the current output value of the low order bit of PORTA. This example MPLAB project is here:

interrupt1.zip

TODO:

  1. This example is not yet doing any kind of context save. I want to put a context save in it.
  2. I want to convert this over to a PIC 18f4550 example, and then use a timer interrupt.

5/8/08

So, now I'm going to change the pic16f84a example to save context in the Interrupt Service Handler. I appear to have broken something now. I have put in code that saves context and code that restores context, and a variable area that is used to save the context (status and w registers). And now, my interrupt routine is not toggling the port A bit. Is this because of the context save & restore? Or because of the variables I've declared? It seems that it's the context save & restore. When I comment out (only) the context save & restore, I am again getting my port A bit toggled by the interrupt service routine. In what way is the context save & restore causing a problem with the port A bit toggle?

One issue here is the location at which I'm declaring the variables. I'm using the CBLOCK directive presently to locate the variables at address 0x20. Is this an in appropriate place to locate these variables? Is it interfering with the port A value or some other cricial value? Ok, so the reason I'm having problems is that my ISR assumes that the value of the W register doesn't change, but my context save & restore uses W. So, what I need to do is reload W from its saved state immediate after the context save. Hmmm. This is not quite what I want. Since I was relying on the change of the value of W across calls to the ISR, this won't work. What I need is another variable, one that I can toggle and push out to PORTA instead of W. Ok! So, that works! Here is an archive of the MPLAB project with the context save and the toggle variable:

interrupt1v2.zip

One thing that my context save doesn't do is save the PCL variable. Hmmm. That wouldn't seem necessary. The PCL is the program counter. What about PCLATH? It is used to set the current code execution page (see p. 328 of Predko; see also my notes in the next interrupt.zip file archive; I don't to save this for the PIC16f84a simulation).

p. 812-814 of Predko has a timer interrupt example that I'm going to try next. The circuit on p. 812 of Predko has an oscillator. Does TMR0 need an external oscillator? (I'm wondering if the USB circuits with the external oscillator us TMR0). The code corresponding to that circuit specifies _XT_OSC, which seems to indicate an external oscillator. My question is now, does TMR0 require use of an external oscillator? See p. 478 of Predko for TMR0. Good. TMR0 can be clocked by an external source or the instruction clock (p. 479, Predko).