please dont rip this site

PIC Micro Controller Interrupt Introduction

Via the 16F877 by William Chops Westfield

On a PIC, and especially a PIC16, I think the basic principles of interrupts are obscured by the complexities of how they work on PIC16s; details about saving state, handling paging, Read-only vectors, and so on. On some other CPUs, things are much simpler.

So, stepping backwards...

"Hardware Interrupts" are a mechanism for providing faster (more immediate) software servicing of particular hardware events. Typically the CPU hardware will check some hardware status after each CPU instruction (for CISC machines for potentially long-running single instructions, sometimes even with a single instruction.) If the hardware needs attention, the CPU will transfer execution to a special piece of software called "the Interrupt Service Routine" (ISR). The ISR can do whatever is necessary to service the hardware, and then it returns to the point where the main software was interrupted, and continues whatever it was doing before.

So what has to happen in order for that to work?

Well, at the hardware level, we want to be able to turn this sort of thing on and off at a global level. Some things should just not be interrupted! Other things shouldn't cause interrupts before all the pieces associated with them are set up properly. On the PIC (16F877), this global enable/disable of the interrupt function is controlled by the GIE bit of the INTCON register.

But before that can work, we have to route the signals that we want to cause interrupts to the appropriate gates, and others that we don't want to cause interrupts need to be set up NOT to. In this case, this is also done via setting or clearing other bits in the INTCON register. See figure 12-9 of the 877 manual for the cascade of gates involved.

And we have to set up the destination address(es) of the ISR code functions. On PICxx877 this is easy; it goes to location 4. Other processors may have multiple locations for multiple interrupt sources, or have external interrupt controllers than you need to poke at...

So if we want RB0 and TM0 to cause interrupt, somewhere in our code initialization we will have code that looks something like:

   bsf INTCON,T0IE  ;enable TMR0 interrupt
   bsf INTCON,INTE  ;enable B0 interrupt
   bsf INTCON,GIE   ; enable interrupt globally.

Now we're ready to do anything we want, and hope we get interrupted by important events!

But wait; how is this going to work from a SW point of view, if the ISR has to continue what we were doing when the ISR is done? The interrupt as a whole will have to preserve everything about the state of the CPU that was relevant to what the main code was doing at the time the interrupt occurred. PC address. Register contents. Status flags for the multi-precision math or conditional jump/skip I was about to take, and so on. All of that will need to be saved when an interrupt occurs, and restore to the previous state when the ISR finishes. This is not TOO much different than a subroutine call, but it is less voluntary than a subroutine, and so must preserve things more exactly (your subroutine can say "I trash the flags values", and you're supposed to deal with that.)

The Saving of State is divided up between what the hardware does, and what the ISR software you write has to do. On many CPUs, the interrupt hardware will push both the return address and the status flags onto the stack, for example. On some CPUs, it'll do that AND switch you to another set of registers reserved just for used by ISRs. However, on the PIC16, the stack is only for return addresses, so that's all that gets saved for you automatically. You suddenly arrive at location 4, and you're NOT ALLOWED TO MAKE ANY CHANGES THAT YOU CAN'T REVERT on exit. And you don't have a general purpose stack. The other thing that has been done for you is that interrupts are now globally OFF, which prevents things like new interrupts showing up and wanting to save (now different) state in the same variables. Here is where this bit of code comes in:

 org 0x4
   movwf          temp_w       ;save w in temp.  movwf does not
change STATUS
                               ;; NOTE However, that temp_w must
exist in all RAM banks.
   swapf          STATUS,w    ;put unchanged STATUS in w with nibbles
   clrf           STATUS      ;now use RAM page 0
   movwf          temp_s       ;save STATUS in temp_s
   movf           PCLATH,W     ; save PCLATH as well
   movwf          temp_pclath
   clrf           PCLATH       ; now on code page 0 for sure too.
   ;;; Now the important and hard-to-do-without registers have been
   ;;; saved and reset as appropriate for continuing to run the ISR 
   ;;; code here in low memory.

Now, since all interrupts came to location 4, we have to check which one it might have been and jump to appropriate smaller bits of code. this is usually done by examining the INTCON register(s) some more:

   btfsc INTCON, RBIE  ;; check for RB0 interrupt
    goto  RB0INTCODE
   btfsc INTCON, T0IF  ;; check for timer interrupt
    goto  TIMERINT
;;; Shouldn't be here; just get out by falling through

  MOVF     temp_pclath, W ;Restore PCLATH
  MOVWF    PCLATH         ;Move W into PCLATH
  SWAPF    temp_s,W       ;Swap STATUS_TEMP register into W
                            ;(sets bank to original state)
  MOVWF    STATUS        ;Move W into STATUS register
  SWAPF    temp_w,F      ;Swap temp_w
  SWAPF    temp_w,W      ;Swap temp_w into W

RB0INTCODE   ;; we got a signal on RB0.  Do the right things!
    ;  :  Blah
    ;  :  Blah
    goto INTEXIT  ;get out

       incfz TIMERTICS_LOW
        goto INTEXIT
        goto INTEXIT

The ISR code has to have SOME state (memory variable) it can manipulate somewhere in the processor. That's fine as long as it's not state that the main program also manipulates. If there is data that has to be shared between ISR code and main Code, you have to be VERY CAREFUL about how and when it is manipulated. The easiest thing to do is surround the main code that touches this data with instructions that turn off interrupts (globally) while the main code is working with them (and then turns them on again when its done.)

Since our ISR code is done, we now know where the startup code can go:

     ;; blah

And hopefully we can set up the reset vector to go there:

   org 0x0
   movlw  HIGH(StartupCode)  ; 0
   movwf  PCLATH             ; 1
   goto   StartupCode        ; plenty of room; won't run into our ISR code.

(mind you this probably has errors; I haven't actually tried this, and it's been a while since I coded a PIC in assembler. But I hope the explanation helps some...)


See also:

file: /Techref/microchip/ints16Fintro-wcw.htm, 7KB, , updated: 2010/4/8 08:43, local time: 2017/10/16 18:22,

 ©2017 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE! / 

<A HREF=""> PIC Micro Controller Interrupt Introduction Via the 16F877 by William Chops Westfield</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

  PICList 2017 contributors:
o List host: MIT, Site host, Top posters @20171016 RussellMc, James Cameron, Van Horn, David, Sean Breheny, IVP, alan.b.pearce, Neil, Bob Blick, David C Brown, Denny Esterline,
* Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.

Welcome to!