Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Solved-New set of eyes - please

Status
Not open for further replies.

augustinetez

Active Member
This is probably going to be another one of those "it's staring me in the face" :banghead: moments and will serve me right for doing three things at once, but could somebody run through this and see if anything twigs.

What I'm doing - converting code from one of my older projects that runs fine on a 12F629 to a 16F1827. Note - done in assembly!

The problem is
- sometimes the rotary encoder works straight up and other times it takes quite few seconds to become active - almost like an interrupt is running and timing out.
This happens immediately on power up, once the encoder starts working it is fine from then on. I have changed the encoder, done meter and scope tests and it is all doing the right thing electrically.

The encoder code is something Mike (Pommie) wrote a little while ago, I have an LED on one of the Port pins that I'm using to try and work out where things are going astray and it appears to be in the Poll_encoder routine starting at line 542. When the encoder is not working, the code runs from the beginning of the routine on through a table call, back to the encoder routine but fails to exit in either up or down mode <- reading the code below should explain that better.

The commented out code is either yet to be modified or removed.

C-like:
;
;********************************************************************************
;                                        *
;                COPYRIGHT NOTICE                *
;                                        *
;        Copyright T Mowles VK5TM September 2021                *
;                                        *
;                                        *
;    This software and any derivatives of it are free for personal use only.    *
;    Commercial use in any form is expressly forbidden including, but not    *
;    limited to, kits based on this and any derivatives of this software     *
;    without specific written consent.                    *
;                                        *
;     This software is, in part, based on and modified from, the works of:    *
;                                        *
;             Curtis W. Preuss - WB2V                    *
;            Bob Okas (SK) - W3CD                    *
;             Bruce Stough - AA0ED                    *
;             Craig Johnson - AA0ZZ                    *
;                                        *
; *******************************************************************************
;
; ----- SELECT ONE OF THESE DDS TYPES AND TURN THE OTHER OFF !! ---------
#define AD9850       ; Using the AD9850
;#define AD9851        ; Using the AD9851
;
;********************************************************************************
;

;
;********************************************************************************

;********************************************************************************
;                                                                             
; Target Controller        PIC16F1827
;                __________                                         
;        DDS_LOAD---RA2 |1       18| RA1---DDS_CLK
;        DDS_DATA---RA3 |2       17| RA0---SPARE
;        CAL SW-----RA4 |3       16| RA7---SPARE
;        SPARE------RA5 |4       15| RA6---SPARE
;        Ground-----Vss |5       14| VDD---+5 V
;        ENCODER----RB0 |6       13| RB7---SPARE
;        ENCODER----RB1 |7       12| RB6---LED STEP 10kHz
;        STEP SW----RB2 |8       11| RB5---LED STEP 1kHz
;        SPARE------RB3 |9       10| RB4---LED STEP 10Hz
;                ----------                                         
;                                                                             
; *******************************************************************************
; * Device type and options                            *
; *******************************************************************************
;
        processor 16F1827
        radix     dec
    errorlevel -207    ; Skip found label after column 1
    errorlevel -302    ; Skip out of bank nuisance messages
    errorlevel -303    ; Skip program word too large. Truncated to core size
;
; *******************************************************************************
; * Configuration fuse information for 16F1827                    *
; *******************************************************************************
;
        include   <P16F1827.INC>

; __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
 __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;
; *******************************************************************************

;                                                                             
; *******************************************************************************
; * General equates.  These may be changed to accommodate the reference clock    *
; * frequency, the desired upper frequency limit, and the default startup    *
; * frequency.                                    *
; *******************************************************************************
;
#ifdef AD9850
;    For 125 MHz Oscillator =======
ref_osc_3   equ 0x22        ; Most significant osc byte
ref_osc_2   equ 0x5C        ; Next byte
ref_osc_1   equ 0x17        ; Next byte
ref_osc_0   equ 0xD0        ; Least significant byte
#endif

#ifdef AD9851
;    For 180 MHz (30 MHz clock and 6x multiplier)                               
ref_osc_3   equ 0x17        ; Most significant osc byte               
ref_osc_2   equ 0xDC        ; Next byte                               
ref_osc_1   equ 0x65        ; Next byte                               
ref_osc_0   equ 0xDE        ; Least significant byte                   
#endif

;    Change limits to suit
;
; Limit_0...3 contains the upper limit frequency as a 32 bit integer.
;
limit_hi_3   equ 0x00        ; Most significant byte for 5.5 MHz   
limit_hi_2   equ 0x53        ; Next byte
limit_hi_1   equ 0xEC        ; Next byte
limit_hi_0   equ 0x60        ; Least significant byte
;limit_3   equ 0x00        ; Most significant byte for 5.5 MHz   
;limit_2   equ 0x53        ; Next byte
;limit_1   equ 0xEC        ; Next byte
;limit_0   equ 0x60        ; Least significant byte
;
; Low_limit_3..0 contains the lower frequency limit as a 32 bit integer
;
limit_low_3 equ 0x00        ; Most significant byte for 5.0 MHz
limit_low_2 equ 0x4C        ; Next byte
limit_low_1 equ 0x4B        ; Next byte
limit_low_0 equ 0x40        ; Least significant byte
;
; Default contains the default startup frequency as a 32 bit integer.
; This will be overwritten by the frequency save routine in normal use.
;
default_3 equ 0x00        ; Most significant byte for 5.0 MHz
default_2 equ 0x4C        ; Next byte
default_1 equ 0x4B        ; Next byte
default_0 equ 0x40        ; Least significant byte
;
; Frequency at which Calibration will take place
;
cal_freq_3 equ 0x00        ; Most significant byte for 5.250 MHz
cal_freq_2 equ 0x50        ; Next byte
cal_freq_1 equ 0x1B        ; Next byte
cal_freq_0 equ 0xD0        ; Least significant byte
;
EEstartup_adr equ 4        ; Location of startup frequency in EEPROM   
;
; *******************************************************************************
; * Setup the initial constant, based on the frequency of the reference        *
; * oscillator.  This can be tweaked with the calibrate function.        *
; *******************************************************************************
;
    ORG    0xF000        ; For 16F1827

; ref_osc bytes must be first 4 bytes of EEPROM                               
    DATA    ref_osc_0
    DATA    ref_osc_1
    DATA    ref_osc_2
    DATA    ref_osc_3
; startup frequency bytes must be next 4 bytes of EEPROM                     
    DATA    default_0    ; startup -> freq_0                               
    DATA    default_1    ; startup -> freq_1                               
    DATA    default_2    ; startup -> freq_2                               
    DATA    default_3    ; startup -> freq_3
    DATA    0
;
; *******************************************************************************
; * Assign names to IO pins.                            *
; *******************************************************************************
#DEFINE DDS_clk        PORTA,1    ; AD9850/AD9851 write clock
#DEFINE DDS_dat        PORTA,3    ; AD9850/AD9851 serial data input
#DEFINE DDS_load    PORTA,2    ; Update pin on AD9850/AD9851
;
;    16F1827 Oscillator setup
    ; OSCCON - Oscillator control reg.
    ; ---------------------------------
    ; SPLLEN b7 enable PLL x4
    ; 1 = enabled 0 = disabled
    ; IRCF | b6-3 frequency selection
    ; 1111 = 16MHz HF
    ; 1110 = 8 or 32MHz HF
    ; 1101 = 4MHz HF
    ; 1100 = 2MHz HF
    ; 1011 = 1MHz HF
    ; 1010 = 500kHz HF
    ; 1001 = 250kHz HF
    ; 1000 = 125kHz HF
    ; 0111 = 500kHz MF (default)
    ; 0110 = 250kHz MF
    ; 0101 = 125kHz MF
    ; 0100 = 62.5kHz MF
    ; 0011 = 31.25kHz HF
    ; 0010 = 31.25kHz MF
    ; 000x = 31.25kHz LF
    ; Reserved B2 reserved, 0
    ; SCS      B1 0-: 1x = int. OSC.
    ; 01 = Timer1 oscillator
    ; 00 = determined by FOSC <2:0> in Configuration
    ; POR default 00111-00 500 kHz (POR = Power On Reset)

OSCCONVAL    EQU    b'01101000'    ; 4MhZ CLOCK
;
; *******************************************************************************
; *           Allocate variables in general purpose register space        *
; *******************************************************************************
;
    CBLOCK    0x20        ; Start Data Block

    AD9851_0        ; AD9850/AD9851 control word               
    AD9851_1        ;  (5 bytes)                               
    AD9851_2                                                           
    AD9851_3                                                           
    AD9851_4                                                           
    fstep_0            ; Frequency inc/dec
    fstep_1            ;  (4 bytes)
    fstep_2
    fstep_3
    low_limit_3        ; Low frequency limit
    low_limit_2        ; (4 bytes)
    low_limit_1
    low_limit_0
    mult_count        ; Used in calc_dds_word
    bit_count        ;   "
    byte2send        ;
    osc_temp_0        ; Oscillator frequency
    osc_temp_1        ;  (4 bytes)
    osc_temp_2       
    osc_temp_3
    timer1            ; Used in delay routines
    timer2            ;   "
    dir            ; for encoder routine
    previous
    clicks
    temp            ; for encoder routine

    saved            ; Flags for frequency save routine
                ; saved,0 used in read encoder routine to jump flag for frequency save
                ; =1 calibrate mode active
                ; =0 calibrate mode not active
                ; saved,2 used in interupt routine

    CNT1            ; Counter for interrupt routine
    CNT2            ;    "     "      "        "                         
    cal_flag        ; Flag to test if CAL done. Bit 0 = 1 if done
                ; 0=10Hz 1=1kHz 2=10kHz step size
    count
    byte_count
    regb_0
    regb_1
    regb_2
    regb_3
    ENDC            ; End of Data Block

    CBLOCK    0x70        ; Use bank common locations - saves bank switching
    freq_0            ; Frequency (hex)
    freq_1            ; (4 bytes)           
    freq_2            ; 
    freq_3            ;   
    osc_0            ; Current oscillator
    osc_1            ; (4 bytes)
    osc_2
    osc_3
    step_size        ; 0=10Hz 1=1kHz 2=10kHz step size
    ENDC            ; End of Data Block

; *******************************************************************************
; * Purpose:  This is the start of the program.                    *
; *******************************************************************************
;
    ORG     0x0000               
    goto    start        ; Jump to main program

    ORG     0x0004        ; interrupt routine for approx 2 second counter
;    movwf   w_temp        ; save off current W register contents
;    movf    STATUS,w    ; move status register into W register
;    movwf    status_temp    ; save off contents of STATUS register
;    bcf    INTCON,T0IF    ; Clear Timer0 interrupt flag
;    decfsz     CNT1,F         ; Decrease CNT1. If zero, skip next instruction
;    goto    not_yet     ; Not zero goto not yet
;    decfsz    CNT2,f
;    goto    not_yet2     ; Not zero goto not yet
;    bsf    saved,2        ; set interrupt timed out flag
;    movlw    delay        ; Delay x number of seconds
;    movwf    CNT2
;
;not_yet2
;    movlw    18
;    movwf    CNT1
;not_yet
;    movlw    39
;    movwf    TMR0         ; Reload Timer0
;;
;exit_interrupt
;;
;    movf    status_temp,w    ; retrieve copy of STATUS register
;    movwf    STATUS        ; restore pre-isr STATUS register contents
;    swapf   w_temp,f
;    swapf   w_temp,w    ; restore pre-isr W register contents
;    retfie             ; Enable general interrupts and return
;
LED_on    macro
    bsf    PORTB,7
    endm

LED_off macro
    bcf    PORTB,7
    endm

enc_table
    addwf    PCL,f        ;index into table
    dt    0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0

;--------------------------------------------------------------------------------

start
    clrf    INTCON        ; clear INTCON
    clrf    PORTA
    clrf    PORTB
    clrf    step_size
    clrf    cal_flag    ;

; Set PIC oscillator frequency
    banksel    OSCCON        ; Select OSCCON
    movlw    OSCCONVAL    ;
    movwf    OSCCON        ; Loads the wanted value

; Configures all I / O as digital
    Banksel    ANSELA
    clrf    ANSELA
    clrf    ANSELB

; Disable all wakeup pull-ups
    Banksel    WPUA
    clrf    WPUA
    clrf    WPUB

    banksel    OPTION_REG
    movlw    b'10000111'    ; Pull-ups disabled, TMR0 clock source internal
                ; clock, prescaler to TMR0, set TMR0 prescaler
    movwf    OPTION_REG    ; 1:256
;
    movlw    b'10110000'    ; PORTA (RA0:3 & 6 outputs RA4,5,7 input)     
    movwf    TRISA        ;
    movlw    b'00001111'    ; PORTB 0:3 & 7 inputs 4:6 outputs
    movwf    TRISB        ; Set port B to all outputs
    movlb    0        ; NOTE: Pull-up via 10k resistor all unused pins
;
;
;    Initialize DDS Module with zero freq
;
    clrf    AD9851_0    ; AD9850/51 control word
    clrf    AD9851_1    ; (5 bytes)
    clrf    AD9851_2
    clrf    AD9851_3
    clrf    AD9851_4
    call    send_dds_word    ; Send it to the DDS
    call    send_dds_word    ; twice to be sure
;
    movlw    limit_low_3    ; Most significant byte for lower limit
    movwf    low_limit_3
    movlw    limit_low_2    ; Next byte
    movwf    low_limit_2
    movlw    limit_low_1    ; Next byte
    movwf    low_limit_1
    movlw    limit_low_0    ; Least significant byte
    movwf    low_limit_0
;
;       Enter Calibrate Mode if GPIO,5 is low when turning the power on and CAL not already done.
;    Test flag to see if CAL already done. Jump over this section if done.
;    movlw    9
;    bsf    STATUS,RP0    ; Switch to bank 1
;    movwf    EEADR        ; Point to flag location in EEprom
;    call    read_EEPROM    ; Read EEprom at address 4
;    bcf    STATUS,RP0    ; Switch to bank 0
;    movwf    cal_flag    ; Move data to register
;    btfsc    cal_flag,0    ; Test set_flag,0 - will be 0 if CAL not done
;    goto    read_EEocs    ; or 1 if CAL already done
;    btfss    PORTA,4        ; Cal pushbutton pressed
;    call    calibrate    ; Yes,call calibration routine
;
;       Get the reference oscillator constant from the EEPROM.
;
read_EEocs
;
    BANKSEL    EEADRL        ;
    clrf    EEADRL        ; Data Memory Address to read
    call    read_EEPROM    ; Read EEPROM
    movf    EEDATL,W    ; Get the first osc byte
        movwf   osc_0        ; Save osc frequency
        call    read_EEPROM    ; Read EEPROM
        movf    EEDATL,W    ;
        movwf   osc_1        ; Save it
        call    read_EEPROM    ; Read EEPROM
        movf    EEDATL,W    ;
        movwf   osc_2        ; Save it
        call    read_EEPROM    ; Read EEPROM
        movf    EEDATL,W    ;
        movwf   osc_3        ; Save it
;
;       Set the power on frequency to the defined value.
;       (They always follow the osc bytes)                                     
;
    call    read_EEPROM    ; Read EEPROM                               
    movf    EEDATL,w    ; Get the first default freq byte           
    movwf    freq_0        ; Save it
    call    read_EEPROM    ; Read EEPROM                               
    movf    EEDATL,w    ; Get the next freq byte                     
    movwf    freq_1        ; Save it
    call    read_EEPROM    ; Read EEPROM                               
    movf    EEDATL,w    ; Get the next freq byte                     
    movwf    freq_2        ; Save it                                   
    call    read_EEPROM    ; Read EEPROM                                 
    movf    EEDATL,w    ; Get the last freq byte                     
    movwf    freq_3        ; Save it
    call    read_EEPROM    ; Read EEPROM                                 
    movf    EEDATL,w    ; Get step size                     
    movwf    step_size    ; Save it

    movlb    0        ; Back to bank 0

    call    step_led
;
;    Send power on frequency to the DDS chip.
;
    call    calc_dds_word    ; Convert to delta value
    call    send_dds_word    ; Send the power-on frequency to the
                ; AD9850/AD9851 in serial mode
;
;    Get the power on encoder value.
    movf    PORTB,w
    movwf   previous    ; Save it in ren_old
    movlw    b'00011000'    ; Get encoder mask (GPIO,4 and GPIO,3)
    andwf   previous,f    ; Get encoder bits and zero all other bits
    clrf    dir        ; Clear the knob direction indicator
    clrf    saved        ;
;
;;    Setup interupt on change pins
;    bsf    STATUS,RP0    ; Switch to bank 1
;    movlw    b'00111000'    ; Set GPIO,3,4 & 5 to interupt on change
;    movwf    IOC        ;
;    bcf    STATUS,RP0    ; Back to bank 0
;
; Fall into the Main Program Loop
;
; *******************************************************************************
; *                                        *
; * Purpose:    This is the Main Program Loop. The program's main loop        *
; *        calls poll_encoder, which continuously polls the rotary shaft    *
; *        encoder.  When the shaft encoder has changed, the direction    *
; *        it moved is determined and stored in last_dir.  The subroutine    *
; *        then returns to main.                        *                       
; *                                        *
; *        The variable fstep is added or subtracted from the current    *
; *        VFO frequency and stored in freq.                *
; *        Next, the subroutine calc_dds_word is used to calculate the DDS    *
; *        frequency control word from the values in freq and osc.        *
; *        The result is stored in AD9850/AD9851. This data is transferred    *
; *        to the AD9851 DDS chip by calling the subroutine send_dds_word.    *
; *                                        *
; *        The frequency is saved to EPROM X seconds (as set by 'delay')    *
; *        after the encoder stops turning and the PIC goes to sleep until    *
; *        the encoder is turned again                    *
; *                                        *
; *   Input:    None.                                *
; *                                        *
; *  Output:    None.                                *
; *                                        *
; *******************************************************************************
;
;    bsf    INTCON,T0IE    ; Enable Timer0 interrupt
;    bsf    INTCON,GIE    ; Enable general interrupts

main

    call    poll_encoder    ; Check for knob movement (wait there!)     
                ; Return here when encoder change detected
;    bsf    STATUS,RP0    ; Switch BANK1
;    bcf    OPTION_REG,T0CS    ; Start Timer0
;    bcf    STATUS,RP0    ; Switch to BANK0
;    movlw    18        ; Interrupt counter for ~1 second
;    movwf    CNT1
;    movlw    delay        ; Delay x number of seconds
;    movwf    CNT2
;    movlw    39
;    movwf    TMR0        ; Writing this will restart Timer0 after two ins. cyc.
;
; *******************************************************************************
;    Code for pushbutton selection of step size                *
;    Step size 10Hz/1kHz/10kHz                        *
; *******************************************************************************
step                ;
    clrf    fstep_3        ;
    clrf    fstep_2        ;
    clrf    fstep_1        ;

step1
    movfw    step_size    ; If step_size = 0
    xorlw    0
    btfsc    STATUS,Z
    goto    step_10hz    ; Set step to 10Hz

    movfw   step_size    ; If step_size = 1
    xorlw   1
    btfsc   STATUS,Z
    goto    step_1khz    ; Set step to 1kHz

                ; Else step_size = 10kHz

    movlw    0x10        ; 10kHz steps
    movwf    fstep_0        ;
    movlw    0x27        ;
    movwf    fstep_1        ;
    goto    stepdir

step_10hz            ;
    movlw    0x0A        ; 10Hz steps
    movwf    fstep_0        ;
    goto    stepdir

step_1khz
    movlw    0xE8        ; 1kHz steps
    movwf    fstep_0        ;
    movlw    0x03        ;
    movwf    fstep_1        ;
;
;    Based on the knob direction, either add or subtract the increment,
;    then update DDS.
;
stepdir
    btfsc    dir,0        ; Is the knob going up?
    goto    up        ; Yes, then add the increment
down
    call    sub_step    ; Subtract fstep from freq
    goto    update        ; Update DDS                         
up
    call    add_step    ; Add fstep to freq
    call    check_add    ; Make sure we did not exceed the maximum
update
    call    calc_dds_word    ; Calculate the control word for the DDS chip
    call    send_dds_word    ; Send the control word to the DDS chip
;
    goto    main        ; Continue main loop
;
; *******************************************************************************
; *                                        *
; * Purpose:    This routine does the following:                *
; *                                        *
; *        Reads the encoder bits until a change is detected, then        *
; *        determines the direction the knob was moved.            *
; *                                        *
; *   Input:    Knob input read from GPIO                    *
; *        ren_old -> the last encoder bits read                           *
; *        last_dir -> the last direction moved                            *
; *                                        *
; *  Output:    ren_new -> the current encoder bits                *
; *        last_dir -> the last direction (0 = down, 1 = up)        *
; *                                        *
; *******************************************************************************
;
poll_encoder
;
;    btfsc    saved,0        ; Test if in calibrate mode - ignore interrupt flags
;    goto    read_encoder
;    btfsc    saved,2        ; Test interrupt flag, jump over if not set
;    call    update_EEPROM    ; Call to save freq when changed and timer timed out
;
; *******************************************************************************
; *    Code for pushbutton selection of step size                *
; *******************************************************************************
    btfsc    PORTB,2        ; Is Step switch pushed?
    goto    read_encoder    ; No

    incf    step_size,f

    movfw   step_size    ; Keep step_size in range of 0 - 2
    xorlw   3
    btfsc   STATUS,Z
    clrf    step_size

step_exit
    btfss    PORTB,2
    goto    step_exit    ; Wait for Step switch to be released
    call    step_led

read_encoder
    rlf    previous,f
    rlf    previous,w
    andlw    0x0c        ; Keep only bits 2 & 3
    btfss    PORTB,0        ; Move encoder bits
    iorlw    1        ; to bits 1 & 2
    btfss    PORTB,1
    iorlw    2
    movwf    previous    ; Keep for next time

    call    enc_table

    addwf    clicks,f
    movlw    3
    xorwf    clicks,w
    btfsc    STATUS,Z
    goto    exit_up
    movlw    0xfc        ;-4
    xorwf    clicks,w
    btfsc    STATUS,Z
    goto    exit_down
    goto    poll_encoder

exit_down
    clrf    clicks
    bcf    dir,0        ; Set "DOWN"
    return

exit_up
    LED_on
    clrf    clicks
    bsf    dir,0        ; Set "UP"
    return
;
; *******************************************************************************
; *                                        *
; *    Set step size and output pulses to indicate step size            *
; *                                        *
; *******************************************************************************
step_led
    movfw    step_size    ; If step_size = 0
    xorlw    0
    btfsc    STATUS,Z
    goto    step_led10hz    ; Set 10Hz LED

    movfw   step_size    ; If step_size = 1
    xorlw   1
    btfsc   STATUS,Z
    goto    step_led1khz    ; Set 1kHz LED
;
;                ; Else set 10kHz LED
;
    BANKSEL LATB
    bsf    LATB,6        ; 10kHz LED
    nop
    bcf    LATB,5        ; 1kHz LED
    nop
    bcf    LATB,4        ; 10Hz LED
    movlb    0
    return
;
step_led10hz
    BANKSEL LATB            ;
    bsf    LATB,4
    nop
    bcf    LATB,5
    nop
    bcf    LATB,6
    movlb    0
    return
;
step_led1khz
    BANKSEL LATB
    bsf    LATB,5
    nop
    bcf    LATB,6
    nop
    bcf    LATB,4
    movlb    0
    return
;
; *******************************************************************************
; *                                        *
; * Purpose:    This routine adds the 32 bit value of fstep to the 32 bit    *
; *        value in freq.  When incrementing, the fstep value is a        *
; *        positive integer.  When decrementing, fstep is the complement    *
; *        of the value being subtracted.                    *
; *                                        *
; *   Input:    The 32 bit values in fstep and freq                *
; *                                        *
; *  Output:    The sum of fstep and freq is stored in freq.  When incrementing    *
; *        this value may exceed the maximum.  When decrementing, it may   *
; *        go negative.                                                    *
; *                                         *
; *******************************************************************************
;
add_step
    movf    fstep_0,w    ; Get low byte of the increment
    addwf    freq_0,f    ; Add it to the low byte of freq
    btfss    STATUS,C    ; Any carry?
    goto    add1        ; No, add next byte
    incfsz    freq_1,f    ; Ripple carry up to the next byte
    goto    add1        ; No new carry, add next byte
    incfsz    freq_2,f    ; Ripple carry up to the next byte
    goto    add1        ; No new carry, add next byte
    incf    freq_3,f    ; Ripple carry up to the highest byte
add1
    movf    fstep_1,w    ; Get the next increment byte
    addwf    freq_1,f    ; Add it to the next higher byte
    btfss    STATUS,C    ; Any carry?
    goto    add2        ; No, add next byte
    incfsz    freq_2,f    ; Ripple carry up to the next byte
    goto    add2        ; No new carry, add next byte
    incf    freq_3,f    ; Ripple carry up to the highest byte
add2
    movf    fstep_2,w    ; Get the next to most significant increment
    addwf    freq_2,f    ; Add it to the freq byte
    btfss    STATUS,C    ; Any carry?
    goto    add3        ; No, add last byte
    incf    freq_3,f    ; Ripple carry up to the highest byte
add3
    movf    fstep_3,w    ; Get the most significant increment byte
    addwf    freq_3,f    ; Add it to the most significant freq
    return            ; Return to the caller
;
; *******************************************************************************
; *                                        *
; * Purpose:    Check if freq exceeds the upper limit.                *
; *                                        *
; *   Input:    The 32 bit values in freq                    *
; *                                        *
; *  Output:    If freq is below the limit, it is unchanged.  Otherwise, it is    *
; *        set to equal the upper limit.                    *
; *                                        *
; *******************************************************************************
;
check_add
;
;    Check the most significant byte.
;
    movlw    0xFF-limit_hi_3    ; Get (FF - limit of high byte)
    addwf    freq_3,w    ; Add it to the current high byte
    btfsc    STATUS,C    ; Was high byte too large?
    goto    set_max        ; Yes, apply limit
    movlw    limit_hi_3        ; Get high limit value
    subwf    freq_3,w    ; Subtract the limit value
    btfss    STATUS,C    ; Are we at the limit for the byte?
    goto    exit1        ; No, below.  Checks are done.
;
;    Check the second most significant byte.
;
    movlw    0xFF-limit_hi_2    ; Get (FF - limit of next byte)
    addwf    freq_2,w    ; Add it to the current byte
    btfsc    STATUS,C    ; Is the current value too high?
    goto    set_max        ; Yes, apply the limit
    movlw    limit_hi_2        ; Second limit byte
    subwf    freq_2,w    ; Subtract limit value
    btfss    STATUS,C    ; Are we at the limit for the byte?
    goto    exit1        ; No, below.  Checks are done.
;
;    Check the third most significant byte.
;
    movlw    0xFF-limit_hi_1    ; Get (FF - limit of next byte)
    addwf    freq_1,w    ; Add it to the current byte
    btfsc    STATUS,C    ; Is the current value too high?
    goto    set_max        ; Yes, apply the limit
    movlw    limit_hi_1        ; Third limit byte
    subwf    freq_1,w    ; Subtract limit value
    btfss    STATUS,C    ; Are we at the limit for the byte?
    goto    exit1        ; No, below.  Checks are done.
;
;    Check the least significant byte.
;
    movlw    limit_hi_0        ; Fourth limit byte
    subwf    freq_0,w    ; Subtract limit value
    btfss    STATUS,C    ; Are we at the limit for the byte?
    goto    exit1        ; No, below.  Checks are done.
set_max
    movlw    limit_hi_0        ; Get least significant limit
    movwf    freq_0        ; Set it in freq
    movlw    limit_hi_1        ; Get the next byte limit
    movwf    freq_1        ; Set it in freq_1
    movlw    limit_hi_2        ; Get the next byte limit
    movwf    freq_2        ; Set it in freq_2
    movlw    limit_hi_3        ; Get the most significant limit
    movwf    freq_3        ; Set it in freq_3
exit1
    return            ; Return to the caller
;
; *******************************************************************************
; *                                        *
; * Function:    sub_step                            *
; *                                        *
; * Purpose:    Subtract the increment step from freq.                *
; *                                        *
; *   Input:    The values in fstep and freq_3..0.                *
; *                                        *
; *  Output:    None                                *
; *                                        *
; * Revisions:    Modified for limited range VFO. 29-9-13 VK5TM            *
; *                                        *
; *******************************************************************************
;
sub_step
;
    call    invert_fstep    ; Invert fstep_3..0 to perform the subtraction
    call    add_step    ; Add the complement to do the subtraction
;
; *******************************************************************************
; *                                        *
; * Function:    low_limit_chk                            *
; *                                        *
; * Purpose:    Test the new frequency to see if it is above the lower band    *
; *        limit. If not, the frequency is set to the band lower limit.    *
; *                                        *
; * Input:    Freq_0...3 and Low_limit_0...3                    *
; *                                        *
; * Output:    Original frequency if above low limit or low_limit_0..3 in    *
; *        Freq_0...3                            *
; *                                        *
; *******************************************************************************
;
low_limit_chk
;       Check the most significant byte.
;
    btfsc    freq_3,7
    goto    set_low        ; Yes, set to lower frequency limit
    movf    freq_3,w
    subwf    low_limit_3,w
    btfss     STATUS,C    ; Are we at the limit for the byte?
    return            ; No, above.
    btfss    STATUS,Z    ; Are the bytes equal?
    goto    set_low        ; No, so vfo_X_3 > limit_3.
;
;       Check the second most significant byte when MSB equals limit_3
;
    movf    freq_2,w
    subwf    low_limit_2,w
    btfss    STATUS,C    ; Are we at the limit for the byte?
    return            ; No, above.
    btfss    STATUS,Z    ; Might they be equal?
    goto    set_low        ; Nope, so vfo_X_2 > limit_2
;
;       Check the third most significant byte.
;
    movf    freq_1,w
    subwf    low_limit_1,w
    btfss    STATUS,C    ; Are we at the limit for the byte?
    return            ; No, above.
    btfss    STATUS,Z    ; Check if the bytes are equal
    goto    set_low        ; No, so vfo_X_1 > limit_1
;
;       Check the least significant byte.
;
    movf    freq_0,w
    subwf    low_limit_0,w
    btfss    STATUS,C     ; Are we at the limit for the byte?
    return            ; No, above.     
;
;    The frequency is below the band lower limit. Set frequency to the
;    band starting frequency.       
set_low
    movf    low_limit_0,w
    movwf    freq_0
    movf    low_limit_1,w
    movwf    freq_1
    movf    low_limit_2,w
    movwf    freq_2
    movf    low_limit_3,w
    movwf    freq_3
;
    return            ; Return to caller
;
; *******************************************************************************
; *                                        *
; * Function:    invert_fstep                            *
; *                                        *
; *  Purpose:    Support function for sub_step and calibrate. This function    *
; *        negates the value of fstep_3..0 to assist in the frequency    *
; *        decrement. This operation is performed twice by sub_step, and    *
; *        is also used by calibrate.                    *
; *                                        *
; *    Input:    fstep_3, fstep_2, fstep_1, fstep_0                *
; *                                        *
; *   Output:    fstep_3..0 contain the 2's complement of their original value    *
; *                                        *
; *******************************************************************************
;
invert_fstep
                ; Invert the bits in
    comf    fstep_0,f    ; fstep_0
    comf    fstep_1,f    ; fstep_1
    comf    fstep_2,f    ; fstep_2
    comf    fstep_3,f    ; fstep_3
    incfsz    fstep_0,f    ; Now incremnt fstep_0 to get 2's complement
    goto    invert_done    ; If fstep_0 > 0, then done
                ; Else, there was a carry out of fstep_0
    incfsz    fstep_1,f    ; Add 1 to fstep_1
    goto    invert_done    ; If fstep_1 > 0, then done
                ; Else, there was a carry out of fstep_1
    incfsz    fstep_2,f    ; Add 1 to fstep_2
    goto    invert_done    ; if fstep_2 > 0, then done
                ; Else, there was a carry out of fstep_2
    incf    fstep_3,f    ; Increment the high byte
;
invert_done
    return            ; Back to caller
;

;     
; *******************************************************************************
; *                                        *
; * Purpose:    This routine is entered at start up if the calibrate pads are    *
; *        shorted at power-on time.                    *
; *                                        *
; *         The DDS chip is programmed to produce a frequency, based on the    *
; *        osc value stored in the EEPROM and the calibration frequency as    *
; *        at the head of the code. As long as the pads are shorted, the    *
; *        osc value is slowly altered to allow the output    to be trimmed.     *
; *        Once the encoder is turned after the short is removed from the     *
; *        Cal pads, the new osc value is stored in the EEPROM and normal    *
; *        operation begins.                        *
; *                                        *
; *   Input:    The original osc constant in EEPROM                *
; *                                          *
; *  Output:    The corrected osc constant in EEPROM                *
; *                                        *
; *******************************************************************************
;
;calibrate
;    bsf    saved,0        ; set flag for poll encoder routine
;    bcf    INTCON,GIE    ; Turn off interupts to be sure
;;
;    movlw    cal_freq_0    ; Move Calibration frequency constants
;    movwf    freq_0        ; to freq_0...3 for Calibration routine.
;    movlw    cal_freq_1    ;
;    movwf    freq_1        ;   
;     movlw    cal_freq_2    ;
;    movwf    freq_2        ;   
;    movlw    cal_freq_3    ;
;    movwf    freq_3        ;   
;;
;;    Read the starting reference oscillator value from EEPROM.
;;
;    bsf    STATUS,RP0    ; Switch to bank 1
;    clrf    EEADR        ; Reset the EEPROM read address
;    call    read_EEPROM    ; Read first byte from EEPROM (all in bank 1)
;    movf    EEDATA,w    ; Get the first osc byte
;    movwf    osc_0        ; Save osc frequency
;    call    read_EEPROM    ; Read second byte from EEPROM
;    movf    EEDATA,w    ;
;    movwf    osc_1        ; Save it
;    call    read_EEPROM    ; Read third byte from EEPROM
;    movf    EEDATA,w    ;
;    movwf    osc_2        ; Save it
;    call    read_EEPROM    ; Read fourth byte from EEPROM
;    movf    EEDATA,w    ;
;    movwf    osc_3        ; Save it
;    bcf    STATUS,RP0    ; Back to bank 0 for store
;;
;cal_loop
;    call    calc_dds_word    ; Calculate DDS value based on current osc
;    call    send_dds_word    ; Update the DDS chip
;    call    poll_encoder    ; Wait until the encoder has moved.
;    btfsc    GPIO,5        ; Calibrate switch/jumper still set?
;    goto    cal_out        ; No, go to exit and save values to EEPROM
;    clrf    fstep_3        ; Clear the three most significant
;    clrf    fstep_2        ; bytes of fstep
;    clrf    fstep_1        ;
;    movlw    0x10        ;
;    movwf    fstep_0        ; Use small increment
;    nop            ; Wait a cycle
;    btfsc    dir,0        ; Are we moving down?
;    goto    faster        ; No, increase the osc value
;;
;;    slower
;;
;    comf    fstep_0,f    ; Subtraction of fstep is done by
;    comf    fstep_1,f    ; adding the twos compliment of fsetp
;    comf    fstep_2,f    ; to osc
;    comf    fstep_3,f    ;
;    incfsz    fstep_0,f    ; Increment last byte
;    goto    faster        ; Non-zero, continue
;    incfsz    fstep_1,f    ; Increment next byte
;    goto    faster        ; Non-zero, continue
;    incfsz    fstep_2,f    ; Increment next byte
;    goto    faster        ; Non-zero, continue
;    incf    fstep_3,f    ; Increment the high byte
;faster
;    movf    fstep_0,w    ; Get the low byte increment
;    addwf    osc_0,f        ; Add it to the low osc byte
;    btfss    STATUS,C    ; Was there a carry?
;    goto    add4        ; No, add the next bytes
;    incfsz    osc_1,f        ; Ripple carry up to the next byte
;    goto    add4        ; No new carry, add the next bytes
;    incfsz    osc_2,f        ; Ripple carry up to the next byte
;    goto    add4        ; No new carry, add the next bytes
;    incf    osc_3,f        ; Ripple carry up to the highest byte
;add4
;    movf    fstep_1,w    ; Get the second byte increment
;    addwf    osc_1,f        ; Add it to the second osc byte
;    btfss    STATUS,C    ; Was there a carry?
;    goto    add5        ; No, add the third bytes
;    incfsz    osc_2,f        ; Ripple carry up to the next byte
;    goto    add5        ; No new carry, add the third bytes
;    incf    osc_3,f        ; Ripple carry up to the highest byte
;add5
;    movf    fstep_2,w    ; Get the third byte increment
;    addwf    osc_2,f        ; Add it to the third osc byte
;    btfss    STATUS,C    ; Was there a carry?
;    goto    add6        ; No, add the fourth bytes
;    incf    osc_3,f        ; Ripple carry up to the highest byte
;add6
;    movf    fstep_3,w    ; Get the fourth byte increment
;    addwf    osc_3,f        ; Add it to the fourth byte
;    goto    cal_loop    ; Yes, stay in calibrate mode
;;
;;    Write final value to EPROM
;;
;cal_out
;    bsf    STATUS,RP0    ; Switch to bank 1
;    movf    osc_0,w        ; Get the first osc byte to record
;    clrf    EEADR        ; osc bytes start at EEPROM address 0
;    movwf    EEDATA        ; Put byte in EEPROM write location
;    call    write_EEPROM    ;
;    movf    osc_1,w        ; Get the second byte to record
;    movwf    EEDATA        ; Put byte in EEPROM write location
;    call    write_EEPROM    ;
;    movf    osc_2,w        ; Get the third byte to record
;    movwf    EEDATA        ; Put byte in EEPROM write location
;    call    write_EEPROM    ;
;    movf    osc_3,w        ; Get the fourth byte to record
;    movwf    EEDATA        ; Put byte in EEPROM write location
;    call    write_EEPROM    ;
;    movlw    9
;    movwf    EEADR        ; Move to EEPROM write location
;    movlw    1         ; Set cal_flag   
;    movwf    EEDATA        ; Put byte in EEprom write location
;    call    write_EEPROM    ;
;    bcf    STATUS,RP0    ; Back to bank 0
;    bcf    saved,0        ; clear flag used poll encoder routine
;    return            ; Return to the caller
;                     
; *******************************************************************************
; *                                        *
; * Purpose:    This routine will save the current frequency in EEPROM. This    *
; *        frequency will then be used as the initial frequency upon start    *
; *        up. Frequency is automatically saved 2 seconds after encoder    *
; *        stops moving                            *
; *                                        *
; *   Input:    The constants in freq_0...3                    *
; *                                        *
; *  Output:    None                                *
; *                                        *
; *******************************************************************************
;
update_EEPROM ;
    bcf    INTCON,GIE    ; turn interrupts off
    btfsc     INTCON,GIE     ; See AN576 - make sure interrupts are off
    goto     $-2
    bcf    saved,2        ; clear interrupt timed out flag
    banksel    OPTION_REG
    bsf    OPTION_REG,T0CS    ; Turn off Timer0

    BANKSEL    EEADRL        ;
        movlw   EEstartup_adr    ; Get startup address location
    movwf    EEADRL        ; and set up for start of EEPROM writes   
        movf    freq_0,w    ; Get the first freq byte to write
        movwf   EEDATL        ; First freq byte to EEPROM Write register
        call    write_EEPROM    ; Write it
        movf    freq_1,w    ; Get the second freq byte to write
        movwf   EEDATL        ; Second freq byte to EEPROM Write register
        call    write_EEPROM    ; Write it
        movf    freq_2,w    ; Get the third freq byte to write
        movwf   EEDATL        ; Third freq byte to EEPROM Write register
        call    write_EEPROM    ; Write it
        movf    freq_3,w    ; Get the fourth freq byte to write
        movwf   EEDATL        ; Fourth freq byte to EEPROM Write register
        call    write_EEPROM    ; Write it
    movf    step_size,w    ; Move step size value to w to save in to EEprom
        movwf   EEDATL        ;
        call    write_EEPROM    ; Write it
    movlb    0        ; Back to bank 0                                   
    bsf    INTCON,GIE    ; turn interrupts on

    return            ;
;
; *******************************************************************************
; *                                        *
; *    Sleep routine.                                 *
; *    Puts PIC to sleep and waits for encoder to move.             *
; *                                        *
; *                                        *
; *******************************************************************************
;
;nod_off
;;    Setup interupt on change pins
;    bsf    INTCON,GPIE    ; Enable Port Change Interupt
;    movf    GPIO,w        ; clear the change condition (see 12F629 data sheet)
;    bcf    INTCON,GPIF    ; clear the interrupt flag
;    sleep            ; Night,night. Sweet dreams.
;    nop            ; Wake from sleep (may still be a bit drowsy)
;    bcf    INTCON,GPIE    ; Disable Port Change Interupt
;    return            ; Back to work
;
; *******************************************************************************
; *                                        *
; *        Required sequence to write to EEPROM                *
; *        Used by update_EEPROM and calibrate routines            *
; *                                        *
; *******************************************************************************
;
write_EEPROM
    bsf    EECON1,WREN    ; Set the EEPROM write enable bit
        ; Start of required sequence
    movlw    0x55        ; Write 0x55 and 0xAA to EECON2
    movwf    EECON2        ; control register, as required
    movlw    0xAA        ;   
    movwf    EECON2        ;
    bsf    EECON1,WR    ; Set WR bit to begin write
        ; End of required sequence
bit_check
    btfsc    EECON1,WR    ; Has the write completed?
    goto    bit_check    ; No, keep checking
    bcf    EECON1,WREN    ; Clear the EEPROM write enable bit
    incf    EEADR,f        ; Increment the EE write address
    return            ; Return to the caller
;
; *******************************************************************************
; *                                        *
; * Purpose:    Read a byte of EEPROM data at address EEADR into EEDATA.    *
; *                                        *
; *   Input:    The address EEADR.                        *
; *                                        *
; *  Output:    The value in EEDATA.                        *
; *                                        *
; *    NOTE:    All in BANK 1                            *
; *                                        *
; *******************************************************************************
;
read_EEPROM
    bcf    EECON1,CFGS    ; Deselect Config space
    bcf    EECON1,EEPGD    ; Point to DATA memory
    bsf    EECON1,RD    ; EE Read
    incf    EEADRL,f    ; Increment the read address
    return
;                                                                             
; *******************************************************************************
; *                                        *
; * Purpose:    Multiply the 32 bit number for oscillator frequency times the    *
; *        32 bit number for the displayed frequency.            *
; *                                        *
; *   Input:    The reference oscillator value in osc_3 ... osc_0 and the    *
; *        current frequency stored in freq_3 ... freq_0.  The reference    *
; *        oscillator value is treated as a fixed point real, with a 24    *
; *        bit mantissa.                            *
; *                                        *
; *  Output:    The result is stored in AD9851_3 ... AD9851_0.            *
; *                                        *
; *******************************************************************************
;
calc_dds_word
;
    clrf    AD9851_0    ; Clear the AD9850/AD9851 control word bytes
    clrf    AD9851_1    ;
    clrf    AD9851_2    ;
    clrf    AD9851_3    ;
    clrf    AD9851_4    ;
    movlw    0x20        ; Set count to 32 (4 osc bytes of 8 bits)
    movwf    mult_count    ; Keep running count
    movf    osc_0,w        ; Move the four osc bytes
    movwf    osc_temp_0    ; to temporary storage for this multiply
    movf    osc_1,w        ; (Don't disturb original osc bytes)
    movwf    osc_temp_1    ;
    movf    osc_2,w        ;
    movwf    osc_temp_2    ;
    movf    osc_3,w        ;
    movwf    osc_temp_3    ;
mult_loop
    bcf    STATUS,C    ; Start with Carry clear
    btfss    osc_temp_0,0    ; Is bit 0 (Least Significant bit) set?
    goto    noAdd        ; No, don't need to add freq term to total
    movf    freq_0,w    ; Get the "normal" freq_0 term
    addwf    AD9851_1,f    ; Add it in to total
    btfss    STATUS,C    ; Does this addition result in a carry?
    goto    add7        ; No, continue with next freq term
    incfsz    AD9851_2,f    ; Yes, add one and check for another carry
    goto    add7        ; No, continue with next freq term
    incfsz    AD9851_3,f    ; Yes, add one and check for another carry
    goto    add7        ; No, continue with next freq term
    incf    AD9851_4,f    ; Yes, add one and continue
add7
    movf    freq_1,w    ; Get the "normal" freq_0 term
    addwf    AD9851_2,f    ; Add freq term to total in correct position
    btfss    STATUS,C    ; Does this addition result in a carry?
    goto    add8        ; No, continue with next freq term
    incfsz    AD9851_3,f    ; Yes, add one and check for another carry
    goto    add8        ; No, continue with next freq term
    incf    AD9851_4,f    ; Yes, add one and continue
add8
    movf    freq_2,w    ; Get the "normal" freq_2 term
    addwf    AD9851_3,f    ; Add freq term to total in correct position
    btfss    STATUS,C    ; Does this addition result in a carry?
    goto    add9        ; No, continue with next freq term
    incf    AD9851_4,f    ; Yes, add one and continue
add9
    movf    freq_3,w    ; Get the "normal" freq_3 term
    addwf    AD9851_4,f    ; Add freq term to total in correct position
noAdd
    rrf    AD9851_4,f    ; Shift next multiplier bit into position
    rrf    AD9851_3,f    ; Rotate bits to right from byte to byte
    rrf    AD9851_2,f    ;
    rrf    AD9851_1,f    ;
    rrf    AD9851_0,f    ;
    rrf    osc_temp_3,f    ; Shift next multiplicand bit into position
    rrf    osc_temp_2,f    ; Rotate bits to right from byte to byte
    rrf    osc_temp_1,f    ;
    rrf    osc_temp_0,f    ;
    decfsz    mult_count,f    ; One more bit has been done.  Are we done?
    goto    mult_loop    ; No, go back to use this bit

#ifdef     AD9850
    movlw    0x00        ; No clock multiplier (AD9850)             
#endif

#ifdef     AD9851
    movlw    0x01        ; Turn on 6x clock multiplier (AD9851)     
#endif

    movwf    AD9851_4    ; Last byte to be sent                     
                ; Mult answer is in bytes _3 .. _0         
    return            ; Done.
;
; *******************************************************************************
; *                                        *
; * Purpose:    This routine sends the AD9850/AD9851 control word to the DDS    *
; *        using a serial data transfer.                    *
; *                                        *
; *   Input:    AD9851_4 ... AD9851_0                        *
; *                                        *
; *  Output:    The DDS chip register is updated.                *
; *                                        *
; *******************************************************************************
;
send_dds_word
    movlw    5        ; Set number of control bytes to send
    movwf    byte_count    ;
    movlw    LOW AD9851_0
    movwf    FSR0L
    movlw    HIGH AD9851_0
    movwf    FSR0H

next_byte
        movf    INDF0,w        ;
        movwf   byte2send    ;
        movlw   0x08        ; Set counter to 8
        movwf   bit_count    ;
next_bit
        rrf     byte2send,f    ; Test if next bit is 1 or 0
        btfss   STATUS,C    ; Was it zero?
        goto    send0        ; Yes, send zero

;    BANKSEL LATA
    bsf    DDS_dat        ; No, send one                               
    bsf    DDS_clk        ; Toggle write clock                         
    bcf    DDS_clk        ;
;    movlb    0        ; Bank 0
                    
        goto    break        ;

send0
;    BANKSEL LATA
    bcf    DDS_dat        ; Send zero                                 
    bsf    DDS_clk        ; Toggle write clock                         
    bcf    DDS_clk        ;
;    movlb    0        ; Bank 0
                
break
        decfsz  bit_count,f    ; Has the whole byte been sent?
        goto    next_bit    ; No, keep going.
        incf    FSR0L,f
    decfsz    byte_count,f    ;
        goto    next_byte    ;

;    BANKSEL LATA
        bsf     DDS_load    ; Send load signal to the AD9850/AD9851             
        bcf     DDS_load    ;
;    movlb    0        ; Bank 0

        return            ;
;
; *******************************************************************************
; *                                        *
; * Purpose:    Wait delays.                            *
; *                                        *
; *                                        *
; *   Input:    None                                *
; *                                        *
; *  Output:    None                                 *
; *                                        *
; *******************************************************************************
;
wait_100us
    movlw    D'1'
    movwf    timer2
    movlw    D'31'
    movwf    timer1
    goto    loop

wait_1ms
    movlw    D'2'
    movwf    timer2
    movlw    D'73'
    movwf    timer1
    goto    loop

wait_10ms
    movlw    D'13'
    movwf    timer2
    movlw    D'251'
    movwf    timer1

loop   
    decfsz    timer1,f
    goto    loop
    decfsz    timer2,f
    goto    loop
    return
;
        END
 
Before you go crazy, try putting a meter on each encoder input pin and make sure they are changing cleanly??

If the encoder contacts are tarnished, it may not be giving reliable signals until it's been turned a bit.
 
It's a long time since I have used much serious PIC assembly, but I remember having to be very careful with look-up tables, ensuring they did not cross register bank boundaries and that the bank register was correctly set, at the start of the lookup.

Is there a different in register bank sizes or the table location between the different MCUs?

I'd try tracing the program through that point if you can.
 
Is there a different in register bank sizes or the table location between the different MCUs?
Code is only 500 odd bytes so all in one page and the table is in the first few bytes of the start, so not crossing any boundary that I can see. I did keep all that stuff inside the 256 byte boundary (start up code, encoder routine, table look up etc).

The 16F1827 has 31 banks (15 used), hence all the BANKSEL stuff and the 12F629 2 banks.

Id there enough decouplig caps..
Plenty, one right on the PIC plus extra on the reg and a short run to the reg.

I thought of osc start up before and put the scope on the osc out pin - all starting up quickly and at the right speed.

The start process involves generating the default start up frequency from EEprom and setting the an initial LED indicator before running in to the main loop, all that works every time.

Putting the LED indicator where the code returns from the table read shows that it is doing that everytime from start up but when it plays up, it is not getting to the exit up or exit down part.
 
Found it.

The initial read of the encoder in the set-up section was masking off the wrong bits (a carry over from the 12F629 version), causing the encoder routine to flip it's lid occasionally.

Knew it would be sitting there laughing at me :mad:
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top