5 Multiple Source Files, Paging and Linear Memory Example

In this PIC16F18446 example, the code reads a number of values from PORTC and stores these into the elements of an array accessed using linear memory addressing. Linear memory access is only implemented on Enhanced Mid-range devices, but other aspects of this code are relevant for all devices The example source code has been intentionally split into two files to illustrate how code can use routines and objects defined in other modules, and the consequences this has on how program memory pages must be handled.

Note: This code example performs manual masking of instruction operand addresses to avoid fixup overflow errors. You can alternatively have the linker automatically truncate operand values when building, as discussed in Working with Data Banks, so that the BANKMASK() and PAGEMASK() macros used in this example are not required.

PIC16 Example - file_1.S

/*
 * Take NUM_TO_READ samples of PORTC, storing this into an array accessed
 * using linear memory. NUM_TO_READ must be defined as a macro on the command-line.
 */

PROCESSOR 16F18446

#include <xc.inc>

CONFIG "FEXTOSC = OFF"     // External Oscillator not enabled
CONFIG "RSTOSC = HFINT1"   // Power-up default value for COSC bits->HFINTOSC (1MHz)
CONFIG "CLKOUTEN = OFF"    // CLKOUT disabled; i/o or oscillator on OSC2
CONFIG "CSWEN = ON"        // Clock Switch Enable->Writing to NOSC and NDIV allowed
CONFIG "FCMEN = ON"        // Fail-Safe Clock Monitor Enable->FSCM timer enabled

CONFIG "MCLRE = ON"        // Master Clear Enable->MCLR pin is Master Clear function
CONFIG "PWRTS = OFF"       // Power-up Timer Enable bit->PWRT disabled
CONFIG "LPBOREN = OFF"     // Low-Power BOR enable bit->ULPBOR disabled
CONFIG "BOREN = ON"        // Brown-out reset enable->Enabled, SBOREN bit is ignored
CONFIG "BORV = LO"         // Brown-out Reset Voltage Selection->VBOR set to 2.45V
CONFIG "ZCDDIS = OFF"      // Zero-cross circuit disabled at POR
CONFIG "PPS1WAY = ON"      // PPSLOCK set/cleared only once
CONFIG "STVREN = ON"       // Stack Over/Underflow causes reset

CONFIG "WDTCPS = WDTCPS_31"    // WDT Period Divider 1:65536; software control
CONFIG "WDTE = OFF"        // WDT operating mode->WDT Disabled, SWDTEN is ignored
CONFIG "WDTCWS = WDTCWS_7" // WDT Window always open; software control
CONFIG "WDTCCS = SC"       // WDT input clock selector->Software Control

CONFIG "BBSIZE = BB512"    // Boot Block Size Selection->512 words boot block size
CONFIG "BBEN = OFF"        // Boot Block Enable bit->Boot Block disabled
CONFIG "SAFEN = OFF"       // SAF Enable bit->SAF disabled
CONFIG "WRTAPP = OFF"      // Application Block not write protected
CONFIG "WRTB = OFF"        // Boot Block not write protected
CONFIG "WRTC = OFF"        // Configuration Register not write protected
CONFIG "WRTD = OFF"        // Data EEPROM write protection->Not write protected
CONFIG "WRTSAF = OFF"      // Storage Area Flash not write protected
CONFIG "LVP = ON"          // Low Voltage Programming Enabled, MCLR/Vpp pin is MCLR

CONFIG "CP = OFF"          // UserNVM Program memory code protection disabled

PSECT code
;read PORTC, storing the result into WREG
readPort:
    BANKSEL   PORTC
    movf      BANKMASK(PORTC),w
    return

GLOBAL count                       ;make this globally accessible

PSECT udata_shr
count:
    DS        1                    ;1 byte in common memory

PSECT resetVec,class=CODE,delta=2
resetVec:
    PAGESEL   main
    goto      main

GLOBAL storeLevel                  ;link in with global symbol defined elsewhere

PSECT code
main:
    BANKSEL   ANSELC
    clrf      BANKMASK(ANSELC)
    clrf      count
loop:
    ;a call to a routine in the same psect
    call      readPort             ;value returned in WREG
    ;a call to a routine in a different module
    PAGESEL   storeLevel
    call      storeLevel           ;expects argument in WREG
    PAGESEL   $
    ;wait for a few cycles
    movlw     0xFF
delay:
    decfsz    WREG,f
    goto      delay
    ;increment the array index, count, and stop iterating
    ;when the final element is reached 
    movlw     NUM_TO_READ
    incf      count,f
    xorwf     count,w
    btfss     ZERO
    goto      loop
    
    goto      $                    ;loop forever

    END       resetVec

PIC16 Example - file_2.S

PROCESSOR 16F18446

#include <xc.inc>

GLOBAL storeLevel                  ;make this globally accessible
GLOBAL count                       ;link in with global symbol defined elsewhere

PSECT udata_shr
tmp:
    DS     1

;define NUM_TO_READ bytes of linear memory, at banked address 0x120
DLABS  1,0x120,NUM_TO_READ,levels

PSECT code
;store byte passed via WREG into the count-th element of the
;linear memory array, levels
storeLevel:
    movwf     tmp                  ;store the parameter
    movf      count,w              ;add the count index to...
    addlw     low(levels)          ;the base address of the aray...
    movwf     FSR1L                ;storing the result in FSR1
    movlw     high(levels)
    clrf      FSR1H
    addwfc    FSR1H
    movf      tmp,w                ;retrieve the parameter
    movwf     INDF1                ;access levels in linear memory
    return

    END