PDA

View Full Version : PIC18 interrupt handler, where to save W etc?



ImAnEE
- 15th May 2010, 19:34
I'm trying to make a simple interrupt handler for the PIC18F8722 timer0. I'm using PICBASIC PRO, MPLAB, the Explorer 18 board, PICKIT 3 and MPASM.

I'm confused about the assembler interrupt handler for the PIC18F8722. Where is W saved? I see code snippets but not the whole thing and apparently W is saved in different locations for the different PIC micros? And what about the bank(ing)? I can't seem to find answers in the PIC BASIC PRO Manual or in M-chip docs or elsewhere but probably I'm not looking in the proper docs or just not understanding what I'm reading!

So the beginning of the interrupt code is (for example, from http://www.phanderson.com/PIC/16C84/interrupts/interrupt_1.html):
MOVWF W_SAVE ; save W
SWAPF STATUS, W ; save STATUS
MOVWF STATUS_SAVE

So, for the PIC18F8722, where is W_SAVE located and what to do about the bank(ing)?

Thanks in advance!

rmteo
- 15th May 2010, 20:37
Try asking here 16-Bit Core (instructions, reset, WDT, specifications...) (http://www.microchip.com/forums/tt.aspx?forumid=7)

Darrel Taylor
- 15th May 2010, 22:06
One nice thing about 18F's is that you don't have to save W, BSR and STATUS when using High Priority Interrupts.
The hardware does it for you whenever an interrupt occurs by saving the values to "Shadow" registers.

At the end of the ISR just ...
 RETFIE FAST ; return from interrupt, restore shadows
and they all get restored.
A plain RETFIE does not.

When using Low Priority interrupts you do need to save them.
But they can be anywhere in RAM, just use MOVFF to save/restore them.

Bruce
- 15th May 2010, 22:07
This is helpful as well http://ww1.microchip.com/downloads/en/DeviceDoc/39500a.pdf

You can use the fast return with auto restore for low pri ints too, but not if you have high pri & low pri interrupts enabled at the same time. The high pri interrupt can corrupt shadow values saved during the low pri interrupt.

Darrel Taylor
- 15th May 2010, 22:27
You can use the fast return with auto restore for low pri ints too, but not if you have high pri & low pri interrupts enabled at the same time. The high pri interrupt can corrupt shadow values saved during the low pri interrupt.
That is so true ...

But so far, I haven't found a possible reason for anyone to have Low Priority interrupts, without High Priority.
Consequently, DT_INTS crashes if you try to only use LP ints, mainly because I haven't seen the need.

Is there a reason anyone can think of for using only Low Priority Interrupts?
Enquiring minds want to know. :)

Bruce
- 15th May 2010, 22:40
Is there a reason anyone can come up with for using only Low Priority Interrupts?

I use low priority exclusivley unless I have more than 1 interrupt, and one 'or more' needs priority over the lower priority interrupt task.

If you only have 1 interrupt enabled, I can't see why making it high priority VS low priority would be of any benefit!


Consequently, DT_INTS crashes if you try to only use LP ints
Yikes. I haven't used DT_INTs much with 18F types, but that's good to know. What causes that to happen?

Darrel Taylor
- 16th May 2010, 18:14
I use low priority exclusivley unless I have more than 1 interrupt, and one 'or more' needs priority over the lower priority interrupt task.
Ok,
But since all the 18F's default to High Priority on power-up.
You have to first Enable Low Priorities by setting IPEN ...

RCON.7 = 1 ; enable interrupt priorities

And clear the corresponding priority bit for the interrupt you're using ...

IPR1.5 = 0 ; set RCIF to low priority

And always remember to use GIEL INTCON.6 instead of GIEH INTCON.7

Then, does that give you anything that the default High priority doesn't?
Other than more statements to write.

Well, DT_INTS doesn't really crash, it just won't compile with only LP ints because it's looking for something that isn't there. And I never saw a reason to try to change it.

Perhaps it's just a way of thinking and I could make DT_INTS allow LP_INTS only.
But if there's a valid reason, I will definitely do it.

Q: Is there a reason anyone can think of for using only Low Priority Interrupts?

ImAnEE
- 16th May 2010, 19:31
So far I had only thought of one interrupt to use for my project, and I figured I would set it at low priority since there seemed to be no reason to use high-priority when using only one interrupt. Then if later on I discovered that another interrupt was needed, I supposed it might be a higher priority and would then use high priority for it. So, yes, I may need only one interrupt and didn't know of a reason to set it at high priority.

Interestingly, I think, my PICBASIC PRO manual states in section 9.3 "In any case, you must restore these registers at the end of your assembler interrupt handler. If the 14-bit core PIC MCU has 2K or less of code space, or it is an PIC18 device, the registers are not saved. Your interrupt handler must save and restore any used registers." However, the on-line PICBASIC PRO manual doesn't have such a statement and I hadn't read that section of the on-line manual until this morning. I don't see anything about high or low priority interrupts in the manuals. I suppose MEL can't be expected to put "everything about everything" in their manual but interrupts are a particularly important topic, I think.

I wasn't planning on using the DT_INTS, figuring that my project is so simple that DT_INTS wouldn't be required. In retrospect, I probably should use DT_INTS but I need to get my code running right away (yesterday, of course) and our Procurement Department takes a couple of weeks or more to purchase anything and I don't want to spend my own $. BTW, I am a firm believer in macros but have always made my own macros.

So, in conclusion:
1. Use the high priority interrupts if possible.
2. For high priority interrupts, use RETFIE FAST ; return from interrupt, restore shadows.
3. If I have to use low-priority interrupts, I have to save the registers and they can be saved anywhere, using MOVFF to restore them. Also have to use "RCON.7 = 1 ; enable interrupt priorities. And clear the corresponding priority bit for the interrupt you're using ...IPR1.5 = 0 ; set RCIF to low priority. And always remember to use GIEL INTCON.6 instead of GIEH INTCON.7"

This all seems overly complex with all sorts of special rules, but I guess it comes with the high-capability of the beast. I come from the days of (even before) the DEC PDP8 and PDP9, and am overwhelmed with this complexity.

I just now discovered a very useful thread from 2006 with Darrel's info about interrupts. Not sure why I didn't see this earlier: http://www.picbasic.co.uk/forum/showthread.php?t=3251

Now to get back to my home "industrial controller" project with the dsPIC33F and the MPLAB GNU C compiler. That's beginning to seem simpler than using PICBASIC PRO. ;-)

Thanks again for all the very useful info!

Bruce
- 16th May 2010, 20:09
Hi Darrel,

With RCON,IPEN = 0 it's in compatibility mode. I.E. no priority levels on any interrupts, and it's just as easy as say setting up & using interrupts on a 16F part.

There's no GIEH, GIEL, or any priority high/low bit settings to worry about. So, it's actually a bit easier than setting up & using high & low priority interrupts.

Here's an example;


list p=18f452
include "p18f452.inc"

CONFIG OSC=XT,OSCS=OFF,WDT=OFF,WDTPS=128,BOR=ON,BORV=45,L VP=OFF

CBLOCK 0x08
MyVar
ENDC

ORG 0x000
BRA Init

ORG 0x008 ; all ints vector here in compatibility mode
BRA TMR_INT ; and high-pri vectors here when enabled

ORG 0x018 ; low-pri int vector, but only when priority
BRA LOW_PRI ; interrupts are enabled

Init
CLRF MyVar ; clear MyVar
CLRF PORTB ; Clear PORTB
CLRF TRISB ; PORTB all outputs
MOVLW 0x07
MOVWF ADCON1 ; disable A/D
MOVLW B'11000111' ; TMR0 on, 8-bit, prescaler, 1:256
MOVWF T0CON
BCF RCON,IPEN ; disable priority interrupts
BCF INTCON,TMR0IF

; since RCON,IPEN=0, we don't need to worry about any priority
; bit settings for any interrupt source, and we refer to GIE,PEIE
; VS GIEH,GIEL because we're in "compatibility" mode. We don't
; have to mess with anything related to high or low priority
; interrupts. Compatibility mode is just as easy as interrupts on
; 16F parts.

BSF INTCON,TMR0IE ; enable Timer0 interrupt
BSF INTCON,PEIE ; peripheral ints enabled
BSF INTCON,GIE ; global enabled

Main
MOVFF MyVar,PORTB ; show count on PORTB LEDs
BRA Main

TMR_INT ; default int vector for all interrupts
INCF MyVar ; when in compatibility mode
BCF INTCON,TMR0IF
RETFIE FAST

LOW_PRI ; never gets here because priority ints
INCF MyVar ; are not enabled when RCON,IPEN = 0
BCF INTCON,TMR0IF
RETFIE FAST
END
And you still have the benefit of fast return with auto context restore even with low pri interrupts.

Maybe I should have said - I use NO priority levels or compatibility mode VS only low priority interrupts. The only time I enable priority levels is when I have more than one interrupt, and one or more needs to interrupt the less important interrupt assigned to the low vector.

Otherwise it's easier to just use compatibility mode with no priority levels to worry about.

I know you're already aware of this, but I figured it would be good to post so folks reading this didn't get confused between using priority levels - I.E. high & low VS compatibility mode where there are no priority levels enabled.

Darrel Taylor
- 16th May 2010, 20:17
I'll take that as a NO.

No reason to have ONLY Low Priority interrupts. (suggested in post #4).

Bruce
- 16th May 2010, 20:40
I'll take that as a NO.
Yep. I don't see any reason to even have priority levels enabled unless you have one interrupt that needs to interrupt another. I should have said NO priority levels VS LOW priority...;)

My point was just to let the OP know he didn't need to enable priority interrupts, or use a high pri interrupt just to use the fast return with auto context restore because this;

One nice thing about 18F's is that you don't have to save W, BSR and STATUS when using High Priority Interrupts.

Made it sound like he did.

Darrel Taylor
- 16th May 2010, 21:16
I agree, Thanks.

I just want to make sure I'm not purposely avoiding something that should be in DT_INTS-18. (getting lazy)

If there were a reason, now would be the time to mention it.
Since I'm updating it.

Anyone?

ImAnEE
- 16th May 2010, 21:28
Your responses are very helpful and greatly appreciated. It's pretty incredible to get this quality of help.

Bruce
- 16th May 2010, 22:09
I can think of a couple scenarios where it might come in handy to use only low priority interrupts.

A. If you need the first few code locations for initialization code that would exceed location 0x08, it would be nice to recover this space by forcing all interrupts to vector to 0x18 after initialization.

B. If you need just a few more words code space, this would free up room between the high/low vectors. GOTO somewhere at 0x00 with GOTO or BRA at 0x08 leaves several words of code space unused between the reset vector & low pri vector.

For B of course you could just make everything high priority, bump it up to 0x08, but you still have a few words not used from reset to 0x08.

So I guess in some extreme cases it might be nice to have the option.

Darrel Taylor
- 16th May 2010, 22:21
Excellent!

I knew I was talking to the right guy.

Reason A. is a perfectly "Valid" need to have only Low Priority Interrupts.
Albeit, an infrequent need.

I will now attempt to add it to the update.

Way to go Bruce!

Darrel Taylor
- 16th May 2010, 22:33
All the back and forth with bruce, I forgot to say ...

ImAnEE,

I'm glad it helps, interrupts can be very confusing.
I've tried to reduce the confusion with DT_INTS, but am still working on it.
If you're short on time, it's probably the Quickest way though.

Fortunately for me, there's more and more people answering DT_INTS questions around here.
So dive in, helps not far away.

Best regards,

tiresmokindad
- 13th June 2010, 08:18
I'm trying to make a simple interrupt handler for the PIC18F8722 timer0. I'm using PICBASIC PRO, MPLAB, the Explorer 18 board, PICKIT 3 and MPASM.

I'm confused about the assembler interrupt handler for the PIC18F8722. Where is W saved? I see code snippets but not the whole thing and apparently W is saved in different locations for the different PIC micros? And what about the bank(ing)? I can't seem to find answers in the PIC BASIC PRO Manual or in M-chip docs or elsewhere but probably I'm not looking in the proper docs or just not understanding what I'm reading!

So the beginning of the interrupt code is (for example, from http://www.phanderson.com/PIC/16C84/interrupts/interrupt_1.html):
MOVWF W_SAVE ; save W
SWAPF STATUS, W ; save STATUS
MOVWF STATUS_SAVE

So, for the PIC18F8722, where is W_SAVE located and what to do about the bank(ing)?

Thanks in advance!

I think you should have the swift code so that the banking will surely not interrupt. :)