How do you clear the RAM and initialize the FSR0 register correctly when using indirect addressing with PIC16F1829?
The code works. My problem is that when debugging, the variables (i.e., Delay1 & Delay2 in this case) whose values should be stored at address 0x70 and 0x71 are being stored at 0x120 and 0x121 respectively, despite the FSR0 register holding the 0x70 address.
I do not know what I have missed, as there are not many examples of using a 16-bit FSR register around. Therefore, any assistance that anyone can provide will be very much appreciated.
LIST p=16f1829 ;list directive to define processor
#INCLUDE <p16f1829.inc> ;processor specific variable definitions
__CONFIG _CONFIG1, (_FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF);
__CONFIG _CONFIG2, (_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _LVP_OFF);
;-------------------------------------------------------------------------
; UDATA declares a section of uninitialised data
VARIABLES UDATA ; VARIABLES is the name of the section of memory
Delay1 RES 1 ; uninitialised data, placed by linker in GPR's.
Delay2 RES 1 ; uninitialised data, placed by linker in GPR's.
;-------------------------------------------------------------------------
; RESET VECTOR
;-------------------------------------------------------------------------
RESET_VECTOR CODE 0x0000
GOTO START
;-------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;-------------------------------------------------------------------------
INT_VECTOR CODE 0x0004 ; Interrupt vector location
GOTO START
;-------------------------------------------------------------------------
; MAIN PROGRAM
;-------------------------------------------------------------------------
MAIN_PROG CODE
START
;-------------------------------------------------------------------------
; SET OSCILLATOR TO FACTORY FREQUENCY AND CLEAR GPR's
;-------------------------------------------------------------------------
ERRORLEVEL -302 ; Disable warning accessing register not in bank 0
BANKSEL OSCTUNE ; Configure OPTION_REG and TMR0
MOVLW 0x00 ; Set oscillator to factory calibrated frequency
MOVWF OSCTUNE ;
BANKSEL STATUS
ERRORLEVEL +302 ; Enable warning accessing register not in bank 0
CLEAR_RAM ; code sequence initialises all GPR's to 0x00
MOVLW 0x70 ; initialise pointer to RAM
MOVWF FSR0L
CLRF FSR0H
NEXT
CLRF INDF0 ; clear INDF0 register
INCF FSR0L, F ; inc pointer
BTFSS FSR0L, 7 ; all done?
GOTO NEXT ; no clear NEXT
CONTINUE ; yes CONTINUE
NOP
;-------------------------------------------------------------------------
; REMAINDER OF PROGRAM
;-------------------------------------------------------------------------
; Setup main init
BANKSEL OSCCON ; Selects memory bank containing OSCCON register
MOVLW b'00111000' ; Set CPU clock speed of 500KHz -> correlates to (1/(500K/4)) for each instruction
MOVWF OSCCON ; OSCCON <- 0x38
; Configure the LEDs
BCF TRISC,0 ; Make I/O Pin C0 an output for DS1
BANKSEL LATC ; Selects memory bank containing LATC
CLRF LATC ; Start by turning off all of the LEDs
MAINLOOP:
BSF LATC, 0 ; Turn LED on
ONDELAYLOOP:
DECFSZ Delay1,f ; Waste time.
BRA ONDELAYLOOP ; The Inner loop takes 3 instructions per loop * 256 loops = 768 instructions
DECFSZ Delay2,f ; The outer loop takes an additional 3 instructions per lap * 256 loops
BRA ONDELAYLOOP ; (768+3) * 256 = 197376 instructions / 125K instructions per second = 1.579 sec.
BCF LATC,0 ; Turn off LED C0 - NOTE: do not need to switch banks with 'banksel' since bank2 is still selected
OFFDELAYLOOP:
DECFSZ Delay1,f ; same delay as above
BRA OFFDELAYLOOP
DECFSZ Delay2,f
BRA OFFDELAYLOOP
BRA MAINLOOP ; Do it again...
;-------------------------------------------------------------------------
; END OF PROGRAM
;-------------------------------------------------------------------------
END ; End of program
The answer is that your code:
; UDATA declares a section of uninitialised data
VARIABLES UDATA ; VARIABLES is the name of the section of memory
Delay1 RES 1 ; uninitialised data, placed by linker in GPR's.
Delay2 RES 1 ; uninitialised data, placed by linker in GPR's.
Tells the assembler to place these in banked memory.
To place data in common (non-banked) memory use this syntax with MPASM:
; UDATA_SHR declares a section of uninitialised data common to all banks
VARIABLES UDATA_SHR ; VARIABLES is the name of the section of memory
Delay1 RES 1 ; uninitialised data, placed by linker in GPR's.
Delay2 RES 1 ; uninitialised data, placed by linker in GPR's.