16F628 Interrupt problem - help!

Loading thread data ...

encoder

counter

when the

fine,

count

think

intermittently

the PIC.

am

The biggest problem I see is that you clobber W when restoring the FSR value before returning from the interrupt. You absolutely have to save/restore context carefully or strange things happen. W must be the last thing restored.

To save context, I use this: movwf W_TEMP ;Save everything swapf STATUS, W movwf STATUS_TEMP movfw FSR movwf FSR_TEMP movfw PCLATH movwf PCLATH_TEMP

These variables must be located in ram that is mirrored accross the banks, this can be accomplished like this:

; ; ISR Register Save Areas ; cblock 0x70 W_TEMP STATUS_TEMP FSR_TEMP PCLATH_TEMP endc

Then, to restore context, use this code in exactly this order: ;------------------------------------------------------ IntExit movfw PCLATH_TEMP movwf PCLATH movfw FSR_TEMP movwf FSR swapf STATUS_TEMP, W movwf STATUS swapf W_TEMP, F swapf W_TEMP, W retfie

Reply to
Anthony Fremont

is

formatting link

an

runs

to

He was referring to keeping a "shadow" ram location that represents the value of an ouput port. You then set and reset individual bits within the shadow register and move the whole shadow register to the output port, instead of flipping bits directly on the output port. This avoids potential Read/Modify/Write issues having to do with the way the PIC ports are designed. These issues are generally associated with highly loaded output pins and/or fast clock speeds.

When you flip an output bit on a PIC, the whole port is read, a single bit is modified, and the whole port is re-written. With heavily loaded pins, or in the case of not allowing enough settling time after changing a pins state, the pin state can be misread. It will consequently be re-written with the incorrect value resulting in the appearance of output pins mysteriously changing themselves when other pins on the same port are changed.

bit

problem

be an

Your interpretation is correct, Mark appears to be somewhat unfamiliar with PICs. In fact your clearing and setting of INTE in the ISR is not really necessary, since no other interrupts will be serviced until GIE is set again (by retfie).

Be aware that the PIC's stack is quite small. Your ISR is using two of the eight locations available.

Reply to
Anthony Fremont

On restore, you restore STATUS selecting the pre-interrupt bank then restore W and FSR which you saved to bank zero. If you take an interrupt while other than bank 0 is selected the interrupt will corrupt W and FSR.

Reply to
nospam

errupts", " reenable interrupt after servicing", the counter direction routine. Your 24 counter appears to be 16 bits. Your problem is most likely to be in the convertion routines which you havent shown, I suspect that they are table read routines. These allways need some care.

Reply to
CBarn24050

My mistake, think W is OK, FSR is still a problem.

Reply to
nospam

No, it's just that I avoid ISR's because of all the inherent trouble with them. It's been so long, I'd forgotten GIE was automatically cleared. It's just as easy most of the time to check for things in the main program loop anyways.

Also check out JAL, it's a friendly pascal-like language for PICs (which will do assembler also if you like.)

formatting link
- binary from sourceforge.net/projects/jal/

Also sorry about the strange message formatting... was tinkering with PGP stuff.

-- "The one truth of the universe is: infinite recursion. That is all."

Reply to
Mark Jones

I've got what I think is an interrupt problem with a simple optical encoder / PIC 16F628 circuit.

The PIC loops around and sends the encoder count values out when a counter in the main loop expires. The encoder is read and the count updated when the encoder input generates a falling edge interrupt on RBO. It all works fine, however every now and again it will crash and cease sending out the count data. This only seems to happen if the encoder is changing position. I think the problem may be do do with my context saving.

The encoder is a quadrature optical unit, which is powered up intermittently at around 2kHz. Some glue logic grabs the status and presents it to the PIC. A falling edge on RBO means a step has occurred, with the direction indicated by the second input on RB3. All of this works fine.

Clock | Power switch | Encoder --> Glue Logic --> PIC - RB0 (Step) / RB3 (Dir)

I've pasted the relevant code sections below - can anyone see where I am going wrong?

Many thanks. rob

;########################################################################## ORG 04H ;INTERRUPT VECTOR ;SAVE CONTEXT BEFORE SERVICING INTERRUPT MOVWF W_TEMP ;COPY W TO W_TEMP REGISTER SWAPF STATUS,W ;COPY STATUS REG INTO W CLRF STATUS ;BANK ZERO MOVWF STATUS_TEMP ;SAVE STATUS IN STATUS_TEMP

MOVF PCLATH,W ;COPY PCLATH INTO W MOVWF PCLATH_TEMP ;SAVE PCLATH IN PCLATH_TEMP CLRF PCLATH ;CLR PCLATH - GOTO PAGE 0, ONLY REQ IF USING PAGES 1,2 AND /OR 3 MOVF FSR,W ;COPY FSR TO W MOVWF FSR_TEMP ;COPY FSR FROM W TO FSR_TEMP ;CONTEXT SAVED

;IDENTIFY INTERRUPT SOURCE ;BTFSC INTCON,INTF ;IS INT DUE TO A RB0 TRANSITION? BCF INTCON,INTE ;DISABLE RBO INTERRUPT CALL ISR_ENC ;YES - SO SERVICE ENCODER STEP INTERRUPT

;RE-ENABLE PORTB INTERRUPT AFTER SERVICING........... BCF INTCON,INTF BSF INTCON,INTE ;NO MORE INTERRUPTS

ISR_DONE ;RESTORE CONTEXT PREVIOUSLY SAVED MOVF PCLATH_TEMP,W ;RESTORE PCLATH MOVWF PCLATH SWAPF STATUS_TEMP,W ;RESTORE STATUS MOVWF STATUS ;RESTORES TO ORIGINAL BANK SWAPF W_TEMP,F ;SWAP W_TEMP SWAPF W_TEMP,W ;W_TEMP INTO W MOVF FSR_TEMP,W ;RESTORE FSR MOVWF FSR RETFIE ;RETURN FROM INTERRUPT - ALSO RESETS GIE BIT CLEARED BY INTERRUPT ;##########################################################################

;MAIN LOOP

CALL INIT_INTERRUPTS HERE INCFSZ TX_CNT1,1 ;loop until ctr overflows and then send out count data GOTO HERE INCFSZ TX_CNT2,1 GOTO HERE CALL CNT2SER ;CONVERTS HEX COUNT TO ASCII & SENDS OUT SERIAL GOTO HERE

;########################################################################## ISR_ENC ;SERVICE ENCODER STEP INTERRUPT - ENCODER CHECK ROUTINE ;########################################################################## BTFSS DIR ;IS DIR HIGH? GOTO CCW ;DIR=0 SO STEP IS CCW GOTO CW ;DIR=1 SO STEP IS CW

CW ;INCREMENT 24 BIT COUNTER ;/TEST LED2_PULSE ;PULSES LED2 LED1_ON ;/END TEST INCFSZ CTR0,1 RETURN INCF CTR1,1 RETURN

CCW ;DECREMENT 24 BIT COUNTER ;/TEST LED2_PULSE ;PULSES LED2 LED1_OFF ;/END TEST

DECF CTR0,1 INCFSZ CTR0,0 ;TEST FOR FF 'UNDERFLOW' RETURN ;NO UNDERFLOW DECF CTR1,1 RETURN ;NO UNDERFLOW

;########################################################################## INIT_INTERRUPTS ;########################################################################## GOBANK1 ;CONFIG RB0 EDGE ETC BCF OPTION_REG,INTEDG ;CLEARED FOR FALLING EDGE INTERRUPT GOBANK0 BCF INTCON,INTF ;ENSURE EXT INT FLAG IS CLEAR BSF INTCON,INTE ;ENABLE RB0 INT CLRF PIR1 ;CLEAR INT FLAGS BSF INTCON,GIE ;ENABLE GIE , RETURN ;##########################################################################

Reply to
Rob

Snipped original post content

Thanks for the reply Mark.

The LEDs are just being turned on/off for test purposes. The encoder runs very slowly - it is to be used to measure a slowly changing mechanical position,

Reply to
Rob

What inherent trouble with PIC ISR's are you referring to, or are you talking about ISR's in general? I happen to love using interrupt handlers, they are quite beneficial to have IMO. ;-) I like to use them for serial i/o, button press sensing, or virtually anything that involves some kind of unpredictable input. They are also good for performing repetitive tasks on a precise interval (like switch debouncing, or even polling ;-) The whole key is in saving and restoring context properly for the main level and setting up the correct context for the ISR. Also, it's good to keep in mind when writing your code that an interrupt can (and eventually will ;-) occur between any two instructions of your program.

You should try to stop avoiding them. Once you get the hang of it, you will begin to see more and more applications for them vs. polling at mainlevel. I tend to use allot of circular queues for my projects, usually stuffing data in them in an ISR and then pulling it out at liesure during main level processing.

Polling is ok I suppose, unless you need absolute precision. And polling introduces it's own set of problems anyway, which is best all depends upon the specific application. Interrupts are also nice in that they let you seperate your program flow into asynchronous pieces (in a sorta threadish way). The 18F pics have two priority levels, letting you receive a high priority interrupt while a lower one is already running. :-)))

Thanks anyway, but I'm already aware of JAL. It's pretty neat, but it's just not my thing. I've used high level languages on micros before, but I tend to stick with assembler for my PIC projects. Although I am thinking about trying one of the free BASIC compilers to see how I like it. I will say though that the most trouble I've had out of using interrupts is when using them from a high level language. But even then, I only really needed to figure out the rules for the particular compiler and then things worked as expected.

Reply to
Anthony Fremont

snipped all.........

Thanks for your advice Mark, Anthony & others. Anthony's context save/restore method seems to have fixed the problem. I added the changes and have beat up on it for a day without seeing any misbehavior.

regards rob

Reply to
Rob

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.