Problem with ASM IRQ using FSR0 on PIC18F252


Closed Thread
Results 1 to 11 of 11
  1. #1
    mytekcontrols's Avatar
    mytekcontrols Guest

    Question Problem with ASM IRQ using FSR0 on PIC18F252

    I have a 6 digit counter routine incorporated as an ASM IRQ on a PIC18F252 under MEL PicBasic Pro. It utilizes in-direct addressing of a 6 byte array to update and store the counter's count. The problem is that the part of the routine that is supposed to clear a digit as it rolls over from 9 doesn't always work. Here is the partial code showing only the UP counting module:

    Code:
    DEFINE INTHAND myint
    
    Ecount     var   byte[6] bankA
    fsave	    var   word  bankA  system
    loopcount var   byte
    
    Goto Start     ' jump past interrupt routine
    
    ;================================================
    asm
    myint
    ; save the FSR value because it gets changed below
        movf	Low FSR0, W
        movwf      fsave
        movf	High FSR0, W
        movwf      fsave+1
    
    ;-------------------------------------------------------
    ;polling and calling routine for counter
    ;-------------------------------------------------------
    
    ; (code not shown)
    
    ;-------------------------------------------------------
    ;6 digit count up module - each entry increments counter
    ;-------------------------------------------------------
    
    countup
        clrf   _loopcount
    
    ;set base address of array
        movlw	Low _Ecount
        movwf	FSR0L
        movlw	High _Ecount
        movwf	FSR0H
    
    inc_loop
        movlw  d'9'
        subwf  INDF0,W
        btfsc  STATUS, Z          ; Have we hit top for this digit?
        goto   nextdigit             ; Yes, go to next! 
        incf   INDF0,F               ; else keep incrementing it, and...
        goto   restore               ; leave!
    nextdigit
        clrf   POSTINC0             ; (clear INDF and increment FSR)
        incf   _loopcount,F
        movlw  d'6'
        subwf  _loopcount,W
        btfss  STATUS, Z          ; Have we checked all 6 digits?
        goto   inc_loop             ; No go to next!
    
    ;restore registers
    restore
        movf	fsave, W
        movwf	Low FSR0
        movf	fsave+1, W
        movwf	High FSR0
        retfie  FAST
    endasm
    ;================================================
    
    Start:
    ;-------------------------------------------------------
    ;PBP interrupt init and counter display
    ;-------------------------------------------------------
    
    ; (code not shown)
    
    End
    The problem when it manifests is that a given digit will continue to increment beyond the number 9. It is as if the array byte pointed to by the FSR has changed momentarily, thereby missing the check for zero after subtracting 9.

    Is code generated by PBP able to interfere with the in-direct addressing? The reason I ask this is, that I originally coded the counter routine without using FSR and instead used Ecount+1, Ecount+2, ect. to access the array. I achieved reliable counting using this method, although at the cost of considerably more code.

    The problem is very intermittent with the FSR routine. So this too tends to point to outside influences causing the glitch. Has anyone else encountered such a problem when using SR's and interrupts under PBP?
    Last edited by mytekcontrols; - 14th June 2005 at 02:56.

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hey Michael,

    This doesn't really explain your problem, but in this section...
    Code:
    ; save the FSR value because it gets changed below
        movf       Low FSR0, W
        movwf      fsave
        movf       High FSR0, W
        movwf      fsave+1
    It's really just saving address 00 instead of saving the contents of the FSR0 registers. (FE9 and FEA)

    The symbol FSR0 equates to 0x0h. It's for use with LFSR etc.

    I believe it should be like this.
    Code:
    ; save the FSR value because it gets changed below
        movf       FSR0L, W
        movwf      fsave
        movf       FSR0H, W
        movwf      fsave+1
    It's the same again when trying to restore it.

    HTH,
       Darrel
    Last edited by Darrel Taylor; - 14th June 2005 at 08:14.

  3. #3
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Speaking of LFSR ....

    This
    Code:
    ;set base address of array
        movlw	Low _Ecount
        movwf	FSR0L
        movlw	High _Ecount
        movwf	FSR0H
    Could be this
    Code:
        LFSR  FSR0, _Ecount

  4. #4
    mytekcontrols's Avatar
    mytekcontrols Guest


    Did you find this post helpful? Yes | No

    Smile It works like a charm!

    Darrel your solution worked great! Thank you for your great wisdom and speedy answers.

    The glitch problem was caused by the fact that I am also running a low priority interrupt service routine which is using the same FSR. Neither of the routines was doing a proper context save of the FSR.

    Here is the completed 6 digit up/down counter w/prescaler source code incorporating your suggestions (hopefully this is all accurate, since I cut and pasted it together out of several include files). The counter's signal source is a rotary encoder connected to 2 pins on PORTC.

    Code:
    '************************************************
    '*  Name    : mod_ENCDRdisp.BAS 
    '*  Author  : Michael St. Pierre
    '*  Notice  : Copyright (c) 2005 Mytek Controls
    '*          : Free For All To Use 
    '*  Date    : 06/14/2005
    '*  Version : 1.0
    '*  Notes   : MEL PicBasic Pro Rotary Encoder Display Routine
    '*          : Includes 8-bit Prescaler 
    '************************************************
    
    DEFINE OSC 40
    DEFINE INTHAND myint
    ' Device = PIC18Fxxx
    
    '================================================
    ' Equates
    '================================================
    
    ENCA var PORTC.x	' use any 2 schmidt trigger inputs with 10K pull-ups
    ENCB var PORTC.x
    encoder var byte
    auxenc var byte
    Ecount var byte[6] bankA
    prescale var byte
    psvalue var byte
    direnc var bit
    loopcount var byte
    periodH con $FE
    periodL con $0B
    ascii var byte
    
    'Variables for saving state in interrupt handler
    fsave	var word bankA system	      ' Saves FSR0
    
    Goto Start	' Jump past interrupt routine
    
    '================================================
    ' Interrupt Handler (High Priority)
    ' Rotary Encoder w/precaler and 6 digit up/down counter 
    '================================================
    asm
    myint
    	
    ; save the FSR value because it gets changed below
        movf    FSR0L, W
        movwf   fsave
        movf    FSR0H, W
        movwf   fsave+1
    
    ; Main Interrupt routine begins here
    
    ; Timer1 set-up as 20 Khz counter (.00005 sec period)
        bcf     _TMR1ON         ; turn OFF Timer1 for counter load
        movlw   _periodH
        movwf   TMR1H           ; load high byte of period counter
        movlw   _periodL
        movwf   TMR1L           ; load low byte of period counter
        bcf     _TMR1IF         ; clear Timer1 IRQ Flag
        bsf     _TMR1ON         ; turn Timer1 back ON
    
    ;check rotary encoder inputs (@20 Khz rate)
    chk_encoder
        clrf    _auxenc
        btfsc   _ENCA
        bsf     _auxenc,0
        btfsc   _ENCB
        bsf     _auxenc,1
    
        movf    _auxenc, W
        xorwf   _encoder, F
    
        rrf     _auxenc, F
        rlf     _encoder, F
        rrf     _auxenc, F
        rlf     _encoder, F
    
        btfsc   _encoder,2
        goto    encoder_up
    chk_down
        btfsc   _encoder,3
        goto    encoder_down
        goto    restore
                
    encoder_up
        btfss   _encoder,3
        bsf     _direnc
        btfsc   _encoder,3
        goto    chk_down
        goto    countup
    
    encoder_down
        btfss   _encoder,2
        bcf     _direnc
        btfsc   _encoder,2
        goto    restore
        goto    countdown
    
    ;Encoder 6 Digit Counter w/PreScaler - Count Up
    countup
    ;prescaler
        movf    _psvalue, W     ; retrieve prescaler value and...
        subwf   _prescale, W    ; compare to prescale count
        btfsc   STATUS, Z       ; Have we finished prescaling?
        goto    preupdone       ; Yes! Go begin actual count
        incf    _prescale, F    ; Else keep incrementing prescale count and
        goto    restore         ; Leave!
    preupdone
        clrf    _prescale       ; Set-up for next prescale event
        clrf    _loopcount
        LFSR    FSR0, _Ecount   ; set counter base address
    
    inc_loop
        movlw   d'9'
        subwf   INDF0, W
        btfsc   STATUS, Z       ; Have we hit top for this digit?
        goto    nextdigit       ; Yes, go to next! 
        incf    INDF0, F        ; else keep incrementing it, and...
        goto    enc_exit        ; Leave!
    nextdigit
        clrf    POSTINC0        ; (clear INDF and increment FSR)
        incf    _loopcount, F
        movlw   d'6'
        subwf   _loopcount,W
        btfss   STATUS, Z       ; Have we checked all 6 digits?
        goto    inc_loop        ; No go to next!
        goto    enc_exit
    
    ;Encoder 6 Digit Counter w/PreScaler - Count Down
    countdown
    ;prescaler
        movf    _prescale, W    ; retrieve prescaler value
        btfsc   STATUS, Z       ; Have we finished prescaling?
        goto    predowndone     ; Yes! Go begin actual count
        decf    _prescale, F    ; Else keep decrementing prescale count and
        goto    restore         ; Leave!
    predowndone
        movf    _psvalue, W
        movwf   _prescale       ; Set-up for next prescale event
        clrf    _loopcount
        LFSR    FSR0, _Ecount   ; set counter base address
    
    dec_loop
        movf    INDF0, W        ; retrieve digit[x]
        bnz     dec_digit       ; Are we at the bottom for this digit?    
        movlw   d'9'            ; Yes, roll it over!
        movwf   POSTINC0        ; (move w = 9 to INDF and increment FSR)
        incf    _loopcount, F
        movlw   d'6'
        subwf   _loopcount, W
        btfss   STATUS, Z       ; Have we checked all 6 digits?
        goto    dec_loop        ; No go to next!
        goto    enc_exit    
    dec_digit
        decf    INDF0, F        ; Not at bottom, keep decrementing it, and...
        goto    enc_exit        ; leave!    
    
    enc_exit
        bsf     _AUTOdispNEW    ; flag that encoder value has changed
    
    ;restore registers
    restore
        movf	fsave, W
        movwf	FSR0L
        movf	fsave+1, W
        movwf	FSR0H
        retfie  FAST
    endasm
    
    '================================================
    ' Program Start
    '================================================
    Start:
            Clear
    
    ' Set-up Interrupts and Timers
    	TMR1H = periodH         ' Pre-load Timer1 High Byte  
    	TMR1L = periodL         ' Pre-load Timer1 Low Byte 
    	T1CON = %000001         ' Set Timer1: IntCLK SRC,Pre 1:1, - Timer ON
    	TMR1IF = 0              ' Clear Timer1 IRQ Overflow Flag
    	TMR1IE = 1              ' Enable Timer1 IRQ on Overflow
    	TMR1IP = 1              ' Timer 1 set as high priority interrupt
    	IPEN = 1                ' Enable priority levels on interrupts
    	INTCON = %11000000      ' Enable all interrupts!
    
    	Pause 100
    	Gosub reset_enc         ' initialize encoder
    
    	psvalue = 0		      ' initialize prescaler
    			
    	' psvalue = 0  - no prescaling -
    	' psvalue = 1  divide by 2
    	' psvalue = 2  divide by 3
    	' psvalue = 99 divide by 100
    
    ' Main Program Loop Begins Here
    
    mainloop
    	If AUTOdispNEW = 1 Then Gosub ENCDRdisp
    
    '--------------------------------------------
    ' your mainloop code goes here
    '--------------------------------------------
    
    	Goto	mainloop
    
    ENCDRdisp:
    ' display direction indicator
    	If direnc = 1 Then
    	ascii = "+"             'direction = UP
    	Else
    	ascii = "-"             'direction = down
    	Endif
    	Gosub	printascii
    
    ' display distance
    	For x = 5 To 0 Step-1
    	ascii = (Ecount DIG x) + $30
    	Gosub	printascii
    	Next x
    	Return
    
    ' Reset "ZERO" Encoder Display
    reset_enc:
    	AUTOdispNEW = 1
    	prescale = 0
    	For x = 0 To 5
    	Ecount[x] = 0
    	Next x
    	Return
    
    ' Print ascii characters
    printascii:
    	' your ascii print/display routine goes here
    	Return
    
    End
    Please excuse the lack of comments on the chk_encoder part of the routine. It was a public domain example that I pasted into my code ( I wish I could remember the author).

    One last question:
    I implemented the following as you suggested
    Code:
        LFSR    FSR0, _Ecount   ; set counter base address
    Can you explain how it works? What is LFSR?

    Thanks,
    Last edited by mytekcontrols; - 14th June 2005 at 21:27.

  5. #5
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    SWEET, I'm glad that worked for you.

    Let's see here, LFSR. It stands for "Load File Select Register" or Load FSR.

    It takes a 12-bit constant and loads the low byte in FSRxL and the highbyte in FSRxH. It does it in 2 instruction cycles, and doesn't care what bank of memory is selected by BSR at the time.

    Using the "old way" movf / movwf you first need to select the proper bank (or use the "a" option to select the access bank) then use 4 instruction cycles to accomplish the same thing.

    While your program wasn't large enough to worry about bank switching, sometimes is has to be handled manually.

    The 18F's have several new Opcodes that can make life easier. MOVFF is one of the best. For a complete list, see the "Instruction Set Summary" towards the end of the datasheet for the device you are using. I know..., I hate being told to RTFM too, but sometimes ya gotta do it.

    regards,
       Darrel

  6. #6
    mytekcontrols's Avatar
    mytekcontrols Guest


    Did you find this post helpful? Yes | No

    Thumbs up

    The 18F's have several new Opcodes that can make life easier. MOVFF is one of the best. For a complete list, see the "Instruction Set Summary" towards the end of the datasheet for the device you are using. I know..., I hate being told to RTFM too, but sometimes ya gotta do it.
    Your right, I found the reference in the data sheet (Stupid me I guess I just got a litle lazy). Thanks again for all the help.

  7. #7
    jmen's Avatar
    jmen Guest


    Did you find this post helpful? Yes | No

    Unhappy using the code at a pic 18f452

    I have tried to use the code on a 18f452 - but it dont works... At the beginnig there were many error messages from the Compiler.
    Therefore I´ve done the following modifications:
    1.changed the rrf instructions to rrcf
    2.changed the rlf instructions to rrcf
    3.at "enc_exit" I changed
    "bsf _AUTOdispNEW ; flag that encoder value has changed"
    to
    "bsf _AUTOdispNEW,0 ; flag that encoder value has changed"
    4. I defined the following Variables:

    TMR1ON VAR BIT
    TMR1IF Var BIT
    TMR1IE VAR BIT
    TMR1IP VAR BIT
    IPEN VAR BIT

    TMR1ON = T1CON.0
    TMR1IF = PIR1.0
    TMR1IE = PIE1.0
    TMR1IP = IPR1.0
    IPEN = RCON.7
    Now it compiles well, but do not work :-(
    To tell the truth I have no expirience with assembler but I have to decode the quadencoder and with PBP I´m loosing counts.

    Thanks in advance
    Jan

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hi Jan,

    Those variables aren't working the way you think. For instance:

    TMR1ON VAR BIT
    TMR1ON = T1CON.0

    Creates a separate BIT variable, and then puts the value of T1CON.0 in it. It doesn't assign T1CON.0 the the name TMR1ON.

    Try doing it this way.

    TMR1ON VAR T1CON.0
    TMR1IF Var PIR1.0
    TMR1IE VAR PIE1.0
    TMR1IP VAR IPR1.0
    IPEN VAR RCON.7<br><br>
    DT

  9. #9
    jmen's Avatar
    jmen Guest


    Did you find this post helpful? Yes | No

    Talking working!

    I´m realy a fool! I changed the wrong variable declaration to aliases as you suggested - now it´s working!!
    thanks a lot, you´ve saved my life!!
    Another short question...
    When i have declared a variable as word - how do I assign a value like 1000 to it or better a value from anoter variable or constant?

    In PBP I would do:
    <pre>resetValue CON 1000
    counter = resetValue</pre>
    or:
    <pre>resetValue VAR WORD
    resetValue = 1000
    counter = resetValue</pre>
    In ASM: ??
    <pre>MOVFF _resetValue, _counter</pre>
    You see I´m a real beginner in ASM :-(

    regards,
    Jan

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hey, don't worry about it Jan. I think I made the same mistake in the beginning.

    To move 1 word var to another using movff might look like this ...

    MOVFF _resetValue, _counter
    MOVFF _resetValue+1, _counter+1

    but that will only work with 2 variables. movff won't work with constants.

    The easiest way to copy things from 1 place to another is using the MOVE?xx macro's. Take a look at this post for more info.

    https://www.picbasic.co.uk/forum/showthread.php?p=2009

    The MOVE?xx macro's will take care of all the bank switching (if required) the same way that PBP does it. <br><br>
    DT

  11. #11
    Join Date
    Oct 2005
    Posts
    8


    Did you find this post helpful? Yes | No

    Thumbs up Encoder

    Hello, please it sends for I the codigo that functions, I am not obtaining success. They thanked

Similar Threads

  1. Instant Interrupts - Revisited
    By Darrel Taylor in forum Code Examples
    Replies: 772
    Last Post: - 17th February 2016, 23:14
  2. PBP, ASM and LST files
    By HenrikOlsson in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th January 2010, 14:43
  3. Problem using ASM instruction
    By ewandeur in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 3rd April 2008, 16:26
  4. pic18f252 hserout problem
    By edysan in forum Serial
    Replies: 4
    Last Post: - 16th June 2006, 21:46
  5. problem with asm interrupt
    By servo260 in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 20th December 2004, 18:02

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts