PDA

View Full Version : ASM Interrupt



mikep
- 22nd October 2003, 13:10
I know this is a big request, but it doesn't hurt to ask.

I'm looking for an example of a hardware interrupt for a 16F876.

Basically I have some PBP code that jumps around several loops depending on certain conditions.

Only while it's in one of those loops I need an interrupt to be triggerred if a pin changes state from low to high. I would use software interrupots, however the problem is that I'm using "sound" and that ties up the program while the sound is being played, so the event could happend while the sound is being played and I would never know it.

Can I send a hardware interrupt back to a piece of PBP code?

Can that code then disable the hardware interrupt until the next time the loop is entered?

Any examples of this or something similar to get me going would be really appreciated.

Also if you know of any nice and easy primers (links) to PIC ASM
that would also be nice.

Thanks,
Mike

Melanie
- 23rd October 2003, 10:32
I don’t think you’ve grasped what interrupts are Mike.

Firstly, in a PIC they’re all generated by Hardware. Be it interrupt on change on a PIC pin, a Timer Overflow, a byte arriving at the USART, whatever. That Hardware Interrupt has THEN got to be serviced by your Software Program.

Secondly, the program in the PIC can only do one thing at a time. Whilst Hardware events are happening all around, the software can only attend to one thing. If your going to service an interrupt event, then, because individual PIC’s don’t parallel process yet, you must by the very nature “interrupt” what you’re doing a go do something else. That’s why some no-brainer named this an “Interrupt”.

If your software is say in the middle of your Sound command, and a Hardware event occurs which would trigger an interrupt, then this can be handled in one of only THREE ways.

1. No Interrupt. Interrupts are NOT enabled, however the Hardware event still sets the event Flag. Once you complete what you’re doing (say your Sound command), you go check what Flag has been set (if any) and do your thing appropriately. In this option, the Sound command completes happily before you check you Flags status.

2. PBP Interrupt. The Hardware event happens, but PBP ignores it until it completes the current command (eg PBP will wait until your Sound command finishes what it’s doing), only then it will jump into your Interrupt Service Routine. You’ll note that here as in option 1 above, the Sound command will be unaffected and will complete without interruption.

3. Assembler Interrupt. This now replaces the way that PBP would handle an Interrupt event. As soon as the interrupt occurs, it will be serviced, therefore execution of what you’re currently doing (eg the Sound command) will be broken whilst the Interrupt Service Routine (ISR) executes. In this instance the Sound command will be broken for the duration of the ISR.

I can see what you want. You want instant access to a Hardware event, without affecting what you’re currently doing. You can only do that by compromising you’re requirement against one of the three options I’ve outlined. If you’re application absolutely depends, life or death, on being able to complete the Sound command for example, but you MUST attend to the Hardware event, then Option 3, but (and it’s a big BUT), your ISR must not be longer than a few instructions (which might be very hard to achieve), otherwise you’ll notice ‘clicks’ and breaks in the Sound output as the ISR executes. The only other way is to synchronise your ISR execution to the output of the Sound command, ensuring your ISR completes before the next High/Low sound transition. For that you will need to write your own Sound command.

It might be simpler here to have a dedicated baby PIC for your uninterrupted sounds, and a second one attending to your Hardware events. There you go - parallel processing…

mikep
- 23rd October 2003, 13:45
Thanks for the reply Mel. (Read next message before replying)

First by Hardware interrupt I meant ASM interrupt. And software interrupt should have been PBP interrupt. Sorry for the mixup in words.

So here is my confusion. With PBP interrupts, I thought that if the interrupt event happend during the processing of another command it would simply not be flagged and never be triggered.

The pin that I have changing states, only does so for a few milliseconds.

This is why when doing a 1 second pauses for example, I do a loop 1000 times of a 1ms pause.

I did not realize that it will still handle the event after whatever command executes.

I did notice in the asm files that basically PBP simply adds a line after every statement to look for the interrupt (as read in the manual) which explains the huge increase in code size.

So basically what happends here is if the interrupt is received (pin changing states etc.) a flag is set by the PIC no matter what is being executing when the interrupt is received. Once the current instruction is processed PBP will look to see if the flag is set and go to the interrupt routine. Once that routine is completed the interrupt flag is reset. Am I correct?

Just making sure here! :-)

I have used PBP interrupts before waiting for serial input and it worked great for those projects.

Actually in this project, I do want the sound to be interrupted. So basically I would need to use the ASM interrupt. And that I have not done yet besides using one that Darrel Taylor graciously supplied to me.

So to continue a question from my earlier post. Can I have the ASM code simply "GOTO" a routine in PBP. My biggest hurddle here is ASM. I understand it, but am not really at a functional level to use it.

Also if not, once the interrupt routine is completed, I imagine it will then return to the same place in my PBP code as where it left off. Is that right? If so I guess I will still have to look for a flag in my PBP routine to know to stop executing that specific set of instructions. So lets say for the sound... If it's playing a 1 second sound and it receives the interrupt after .5 seconds, after the ASM interrupt routine is executed, will it jump back and finish the other .5 seconds of the sound command, or will it simply goto the next line.

Does this make sense?

In simpler terms. I have a bunch of code executing that will take about 10 seconds. If at anytime the interrupt is received while processing that code, I want that series of code to stop executing and jump to another PBP routine immediately.

I don't suppose you have some simple example somewhere of a ASM interrupt? Anything I can play with on the dev board just to get the hang of it.

In the meantime, I think I will go and re-read the chapters on ASM interrupts I have. Although in the books I own, they are all quite slim sections.


Thanks again,
Mike

P.S. Is the mail list totally defunct. Although this is great for searching and all, there seemed to be alot more involment when we were using the e-mail list. Just want to make sure I didn't miss something about have to re-signup or something.

mikep
- 23rd October 2003, 16:24
Nothing like a bit of trial and error to figure things out.

So I've been playing on the dev board and here is what I figured out so far.

After the ASM interrupt routine is handled the rest of the line that was executing while the interrupt is received will execute. So in my case if I have a 5 second sound, and the PIC receives the interrupt after 1 second, when it comes out of the interrupt the other 4 seconds will play. There is a significant amount of delay mind you during the interrupt even though all I am doing in my test is lighting up an LED.

So no matter what, so far the way I see it, once I start a sound I have no way of terminating it.

And I will still have to check to see if I had an interrupt during the sound afterwards.

So basically my main problem now is back to, is there anyway I can have my ASM interrupt routine jump to a different part of my PBP code when it is done executing instead of continuing where it left off.

The other thing that troubles me is that even though I turn on the LED in the interrupt, it will go back off once it returns to executing the PBP code where it left off.

So how then would I set a flag to know that the interrupt happend if everything is restored back to it's state before the interrupt. Or is that only the hardware state of things that are reset. I guessed if I move a value in to a var in the ASM code that woulkd remain the same. Right? I will try that next.

Just for archival sake and if anyone else ever needs this, here is the code I am using to test. It basically comes out of the PBP manual. I don't think it handles the possibility of being in several RAM banks so that could cause some problems on longer code etc.

Off to read more on ASM instructions..... I wish I took a speed reading course!



DEFINE __16F876 1


' Define Oscillator Speed
DEFINE OSC 10

ADCON1 = 7

' Shutdown comparators
CCP1CON = 0
CCP2CON = 0

' Set the port directions
' 0=output 1=input
TRISA=%00000000 ' Set PORTA
TRISB=%00000000 ' Set PortB
TRISC=%00000000 ' Set PortC

led var PORTB.2

wsave var byte $20 system
ssave var byte bank0 system
psave var byte bank0 system

GOTO Start

' Define interrupt handler
define INTHAND myint

' Assembly language interrupt handler
asm

; Save W, STATUS and PCLATH registers
myint movwf wsave
swapf STATUS, W
clrf STATUS
movwf ssave
movf PCLATH, W
movwf psave

; Insert interrupt code here
; Save and restore FSR if used

bsf _led ; Turn on LED

; Restore PCLATH, STATUS and W registers
movf psave, W
movwf PCLATH
swapf ssave, W
movwf STATUS
swapf wsave, F
swapf wsave, W
retfie
endasm
' Added to see if it would use some PBP code as well
' But it will not.
' Would have to perhaps move retfie to after this code?
SOUND PortB.1,[120,160]
PAUSE 3000

Start:
LOW led ' Turn LED off

' Enable interrupt on PORTB.0
INTCON = %10010000

Main:
SOUND PortB.1,[100,160]
PAUSE 3000
SOUND PortB.1,[110,160]
PAUSE 3000
GOTO Main

mikep
- 23rd October 2003, 19:33
The test continue......

Basically I tried something as simple as not adding the return in my ASM interrupt routine.

Change to this:

--------------------------------------------------------------------------

; Save W, STATUS and PCLATH registers
myint movwf wsave
swapf STATUS, W
clrf STATUS
movwf ssave
movf PCLATH, W
movwf psave

; Insert interrupt code here
; Save and restore FSR if used

bsf _led ; Turn on LED

endasm

SOUND PortB.1,[120,160]
PAUSE 3000
GOTO Main

-------------------------------------------------------------------------


I'm guessing I don't need to save the registers up there, but for now I guess it doesn't hurt.

So now it simply continues executing the code below it which is what I'm looking to do.

The thing that I do question at this point is, are there any register I should be saving and restoring?

Any comments on this approach?

mikep
- 23rd October 2003, 21:22
Well I read that you HAVE to return from an interrupt.

So I tried something else... playing the sound in small increments and looping that. Like:

For w = 1 to 160
SOUND PortB.1,[110,1]

in here look to see if the flag is set that
we went through an interrupt.

Next w

But that sounds terrible!


Waiting for the next idea....
I'm starting to think about advancing the PICs counter, but not sure how to do that yet.


Sorry if I'm making this thread so long.... but I'm figuring why not document the process... could make for good archiving! :-)

languer
- 23rd October 2003, 21:29
This is from the interrupt section on the datasheet:

{
The “return from interrupt” instruction, RETFIE, exits interrupt routine as well as sets the GIE bit.

During an interrupt, only the return PC value is saved on the stack. Typically, users may wish to save key registers during an interrupt e.g. W register and STATUS register. This will have to be implemented in software.

• Stores the W register
• Stores the STATUS register in Bank 0
• Executes the ISR code
• Restores the STATUS (and bank select bit
register)
• Restores the W register
}

You do not need RETFIE instruction, as you already discovered. It will get you back to where you were (the sound function in your case). If you do not call the instruction you can jump to some other code (CALL) routine, or the next instruction.

As for what to store, it really is up to you. The datasheet for each device shows what registers are kept and under what interrupt conditions. In general, if is not in a variable it is not guaranteed. The quote above shows you a guideline of usually the minimum that you store before you process the interrupt.

mikep
- 24th October 2003, 00:22
Thanks languer....

I'm going to decide you are right..... It does not have to return.

I re-read the datasheet a few times, brought this up with some people on the pic list and although some people did say I had to, I don't see why. (Others said they have done this before also)

The PBP Manual says:

"The routine should end with an Retfie instruction to return from the interrupt and allow the processor to pick up where it left off in your PicBasic Pro program."

However I've spoken with a few people that have done it (in ASM only though) with no problems.

My test program runs fine without it.


Basically from this (datasheet):
----------------------------------------------------------------------
When an interrupt is responded to, the GIE bit is
cleared to disable any further interrupt, the return
address is pushed onto the stack and the PC is loaded
with 0004h. Once in the Interrupt Service Routine, the
source(s) of the interrupt can be determined by polling
the interrupt flag bits. The interrupt flag bit(s) must be
cleared in software before re-enabling interrupts to
avoid recursive interrupts.
----------------------------------------------------------------------

As far as I can tell the only thing that happends is the return address gets pushed onto the stack. This shouldn't bother me as no longer need whatever was on the stack anyways. However if I could figure out how to POP it that would be cool.

The PC is loaded with 0004h which is fine because that's where it is!

If I want to re-enable interrupts I needs to reset the interrupt flag bits and GIE.

As for W again I'm asusming don't need this since I'm not returning anyways.

I still need to figure out what STATUS and PCLATH are exactly.

I would like to ask a ME techie about this... and if so, they should change the text from "should end" to "usually will end" or something similar.

The other thing that is making me ask a few questions is this line out of the manual:

"The interrupt routine should be as short and fast as you can possibly make it. If it takes too long to execute, the Watchdog Timer could timeout and really make a mess of things."

By the ISR in this case do they mean whatever is in between the ASM and ENDASM?

I'm leaving the watchdog timer on in my tests and it does not seem to be behaving badly in anyway.



Cheers,
Mike

bearpawz
- 22nd November 2004, 20:50
If Im reading what you want correctly, the answer is oh so incredibly simple:

Try this:

MyISR: 'Interupt Service routine starts here
.
.
.
Resume <i><b>label</b></i>


execution will resume at label....


That will send your program back to where ever you want to go...

mister_e
- 22nd November 2004, 21:06
For w = 1 to 160
SOUND PortB.1,[110,1]

in here look to see if the flag is set that
we went through an interrupt.

Next w

But that sounds terrible!


simple thought here... if your PIC have an internal PWM module... why not using it as output? or an loop to trigger an external 555 reset pin with a specific PIC pin??? 555 as pulse generator...