From Swordfish Wiki

SwordfishUser: PeripheralPinSelect

NOTE: the PPS.bas module is now included as part of the standard libraries as of V2.2.3.0

This module allows you to assign the remappable input and output pins for devices that have a Peripheral Pin Select (PPS) module.

Currently, the PPS module is only present in certain "J" and "K" series devices, and the number of pins/function varies depending on the device, so consult the datasheet.

Rev History

V1.5 adds support for xxQ10 family and corrects some K40 assignments

V1.41 errata for 24K40/25K40

V1.4 adds support for the xxK40 family

V1.3 added support for the J94/J99 family

Sample Code

device = 18F47J53

include "pps.bas"

//
//------------------------------------------------------------------------------
// example usage - 47J53
//------------------------------------------------------------------------------
//
sub init_pps()
    // unlock pps registers for change (disables interrupts)
    pps.unlock()

    // assign intr pins
    pps.assign_input(PPS_INT1, PPS_IN_RP3)      // INT1 -> RB0
    pps.assign_input(PPS_INT3, PPS_IN_RP6)      // INT3 -> RB3

    // assign uart2 pins
    pps.assign_input(PPS_RX2, PPS_IN_RP24)      // RX2 -> RD7
    pps.assign_output(PPS_TX2, PPS_OUT_RP23)    // TX2 <- RD6

    // assign spi2 (master)
    pps.assign_output(PPS_SCK2, PPS_OUT_RP20)   // SCK2 <- RD3
    pps.assign_input(PPS_SDI2, PPS_IN_RP21)     // SDI2 -> RD4
    pps.assign_output(PPS_SDO2, PPS_OUT_RP22)   // SDO2 <- RD5

    // relock pps config (restores interrupt enable)
    pps.lock()
end sub 

// start of main code
main:
    // reset all the pps assignments to default
    pps.assign_defaults()

    init_pps()

PPS Module

//
//------------------------------------------------------------------------------
// Name    : pps.bas
// Author  : Jerry Messina
// Date    : 7/22/2018
// Version : 1.50
// Notes   : Peripheral Pin Select (PPS) module
//         : This peripheral is available in select J, K, and Q series devices
//         : (see PPS module type definitions below for a list of supported devices)
//
// ver 1.50: change 24K40,25K40 output mapping to match datasheet 40001843D (PPS_V5_1)
//         : add support for 24Q10,25Q10 (PPS_V6_1)
//         : add prelim support for 26Q10,27Q10,45Q10,46Q10,47Q10 (PPS_V6_2)
// ver 1.41: incorporate output register mapping errata for 24K40/25K40 (PPS_V5_1)
// ver 1.4 : add support for xxK40 family
//         : this family is slightly different so check assign_input/assign_output
//         : examples
//         : fix errors from xc8 pps.h for 4xJ50
// ver 1.3 : add support for J94/J99 (PPS_V4) PPS Lite module
//         : split PPS_V3 into two groups (J13 and J53 devices are different)
//         : change pin definitions from previous version to support V4
//         : add #option PPS_IOL1WAY to enable changes to the config w/out editing
//         : fix errors from XC8 pps.h
// ver 1.2 : add definitions for PPS_V3 RP17/RP18 pins
//------------------------------------------------------------------------------
//
module pps

//
//------------------------------------------------------------------------------
// PPS module type definitions
// list of devices is current as of MPLABX v4.10 (MPASMX 5.77)
// V1.4 adds the K40 family (PPS_V5 devices), which are not supported by XC8 plibs
// V1.5 adds the Q10 family (PPS_V6 devices)
// notes:
// taken from XC8 v1.33 pconfig.h/pps.h (and C18 v3.47)
// note: pconfig.h lumps the J13 and J53 devices together into PPS_V3, but they
// have to be split into two groups (V3 and V3B) because of RPOR14/15/16
// also, some of the mappings in pps.h aren't correct, esp for the V4 devices
// (V4 devices don't work at all in XC8)
//------------------------------------------------------------------------------
//
#if _device in (18F24J50, 18F25J50, 18F26J50)
  #define PPS_V1
#elseif _device in (18F24J11, 18F25J11, 18F26J11)
  #define PPS_V1_1
#elseif _device in (18F44J50, 18F45J50, 18F46J50)
  #define PPS_V2
#elseif _device in (18F44J11, 18F45J11, 18F46J11)
  #define PPS_V2_1
#elseif _device in (18F26J13, 18F27J13)
  #define PPS_V3
#elseif _device in (18F26J53, 18F27J53)
  #define PPS_V3B
#elseif _device in (18F46J13, 18F47J13)
  #define PPS_V3_1
#elseif _device in (18F46J53, 18F47J53)
  #define PPS_V3B_1
#elseif _device in (18F65J94, 18F66J94, 18F67J94) or _
        _device in (18F85J94, 18F86J94, 18F87J94, 18F95J94, 18F96J94, 18F97J94) or _
        _device in (18F66J99, 18F86J99, 18F96J99)
  #define PPS_V4
#elseif _device in (18F24K40, 18F25K40, 18LF24K40, 18LF25K40)
  #define PPS_V5_1
#elseif _device in (18F26K40, 18F27K40, 18LF26K40, 18LF27K40)
  #define PPS_V5_1B
#elseif _device in (18F45K40, 18F46K40, 18F47K40, 18LF45K40, 18LF46K40, 18LF47K40)
  #define PPS_V5_2
#elseif _device in (18F65K40, 18F66K40, 18F67K40, 18LF65K40, 18LF66K40, 18LF67K40)
  #define PPS_V5_3
#elseif _device in (18F24Q10, 18F25Q10)
  #define PPS_V6_1
#elseif _device in (18F26Q10, 18F45Q10, 18F46Q10, 18F27Q10, 18F47Q10)
  #define PPS_V6_2
#else
  #error _device + " unknown PPS module type"
#endif

//
//------------------------------------------------------------------------------
// PPS CONFIG settings
//------------------------------------------------------------------------------
//
// There is a CONFIG bit (IOL1WAY/PPS1WAY) that will prevent you from changing 
// the pps mapping more than once, and it defaults to ON. You must set the config
// setting off if you want to be able to remap them more than once
#option PPS_IOL1WAY = OFF
// K40 device
#if defined(PPS_V5_1) or defined(PPS_V5_1B) or defined(PPS_V5_2) or defined(PPS_V5_3)
  config PPS1WAY = PPS_IOL1WAY
// Q10 device
#elseif defined(PPS_V6_1) or defined(PPS_V6_2)
  config PPS1WAY = PPS_IOL1WAY
// all others
#else
  config IOL1WAY = PPS_IOL1WAY
#endif

// the lock() and unlock() sequences are timing sensitive. by default, the routines
// will manage the state of the global IE bit... lock() will disable interrupts and
// unlock() will restore the setting that was in effect when lock() was initially 
// called. setting 'PPS_DISABLE_INT = false' will bypass this 
#option PPS_DISABLE_INT = true

//
//------------------------------------------------------------------------------
// PPS input
//------------------------------------------------------------------------------
//

// pps input pin definitions
#if defined (PPS_V1) or defined (PPS_V1_1) or defined (PPS_V2) or defined (PPS_V2_1) or _
    defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public const PPS_IN_VSS  = 31  // RPxx Input tied to Vss (unused)
public const PPS_IN_RP0  = 0   // assign RP0 as Input Pin
public const PPS_IN_RP1  = 1   // assign RP1 as Input Pin
public const PPS_IN_RP2  = 2   // assign RP2 as Input Pin
public const PPS_IN_RP3  = 3   // assign RP3 as Input Pin
public const PPS_IN_RP4  = 4   // assign RP4 as Input Pin
public const PPS_IN_RP5  = 5   // assign RP5 as Input Pin
public const PPS_IN_RP6  = 6   // assign RP6 as Input Pin
public const PPS_IN_RP7  = 7   // assign RP7 as Input Pin
public const PPS_IN_RP8  = 8   // assign RP8 as Input Pin
public const PPS_IN_RP9  = 9   // assign RP9 as Input Pin
public const PPS_IN_RP10 = 10  // assign RP10 as Input Pin
public const PPS_IN_RP11 = 11  // assign RP11 as Input Pin
public const PPS_IN_RP12 = 12  // assign RP12 as Input Pin
public const PPS_IN_RP13 = 13  // assign RP13 as Input Pin
// alias name for unmapping an input pin
public const PPS_IN_UNUSED = PPS_IN_VSS
#endif      // (PPS_V1) or (PPS_V1_1) or (PPS_V2) or (PPS_V2_1) or (PPS_V3) or (PPS_V3_1) or (PPS_V3B) or (PPS_V3B_1)

#if defined (PPS_V1_1) or defined (PPS_V2_1)
public const PPS_IN_RP14 = 14  // assign RP14 as Input Pin
public const PPS_IN_RP15 = 15  // assign RP15 as Input Pin
public const PPS_IN_RP16 = 16  // assign RP16 as Input Pin
#endif      // (PPS_V1_1) or (PPS_V2_1)

#if defined (PPS_V1) or defined (PPS_V2) or defined (PPS_V2_1) or defined (PPS_V3_1) or defined (PPS_V3B_1)
public const PPS_IN_RP17 = 17  // assign RP17 as Input Pin
public const PPS_IN_RP18 = 18  // assign RP18 as Input Pin
#endif      // (PPS_V1) or (PPS_V2) or (PPS_V2_1) or (PPS_V3_1) or (PPS_V3B_1)

#if defined (PPS_V2) or defined (PPS_V2_1) or defined (PPS_V3_1) or defined (PPS_V3B_1)
public const PPS_IN_RP19 = 19  // assign RP19 as Input Pin
public const PPS_IN_RP20 = 20  // assign RP20 as Input Pin
public const PPS_IN_RP21 = 21  // assign RP21 as Input Pin
public const PPS_IN_RP22 = 22  // assign RP22 as Input Pin
public const PPS_IN_RP23 = 23  // assign RP23 as Input Pin
public const PPS_IN_RP24 = 24  // assign RP24 as Input Pin
#endif      // (PPS_V2) or (PPS_V2_1) or (PPS_V3_1) or (PPS_V3B_1)

#if defined (PPS_V4)
public const PPS_IN_VSS  = $0F  // RPxx Input tied to Vss (unused)
// GROUP 4n
public const PPS_IN_RP0  = 0   // assign RP0 as Input Pin
public const PPS_IN_RP4  = 1   // assign RP1 as Input Pin
public const PPS_IN_RP8  = 2   // assign RP2 as Input Pin
public const PPS_IN_RP12 = 3   // assign RP3 as Input Pin
public const PPS_IN_RP16 = 4   // assign RP4 as Input Pin
public const PPS_IN_RP20 = 5   // assign RP5 as Input Pin
public const PPS_IN_RP24 = 6   // assign RP6 as Input Pin
public const PPS_IN_RP28 = 7   // assign RP7 as Input Pin
public const PPS_IN_RP32 = 8   // assign RP8 as Input Pin
public const PPS_IN_RP36 = 9   // assign RP9 as Input Pin
public const PPS_IN_RP40 = $0A  // assign RP10 as Input Pin
public const PPS_IN_RP44 = $0B  // assign RP11 as Input Pin

// GROUP (4n+1)
public const PPS_IN_RP1  = 0   // assign RP0 as Input Pin
public const PPS_IN_RP5  = 1   // assign RP1 as Input Pin
public const PPS_IN_RP9  = 2   // assign RP2 as Input Pin
public const PPS_IN_RP13 = 3   // assign RP3 as Input Pin
public const PPS_IN_RP17 = 4   // assign RP4 as Input Pin
public const PPS_IN_RP21 = 5   // assign RP5 as Input Pin
public const PPS_IN_RP25 = 6   // assign RP6 as Input Pin
public const PPS_IN_RP29 = 7   // assign RP7 as Input Pin
public const PPS_IN_RP33 = 8   // assign RP8 as Input Pin
public const PPS_IN_RP37 = 9   // assign RP9 as Input Pin
public const PPS_IN_RP41 = $0A  // assign RP10 as Input Pin
public const PPS_IN_RP45 = $0B  // assign RP11 as Input Pin

// GROUP (4n+2)
public const PPS_IN_RP2  = 0   // assign RP0 as Input Pin
public const PPS_IN_RP6  = 1   // assign RP1 as Input Pin
public const PPS_IN_RP10 = 2   // assign RP2 as Input Pin
public const PPS_IN_RP14 = 3   // assign RP3 as Input Pin
public const PPS_IN_RP18 = 4   // assign RP4 as Input Pin
public const PPS_IN_RP22 = 5   // assign RP5 as Input Pin
public const PPS_IN_RP26 = 6   // assign RP6 as Input Pin
public const PPS_IN_RP30 = 7   // assign RP7 as Input Pin
public const PPS_IN_RP34 = 8   // assign RP8 as Input Pin
public const PPS_IN_RP38 = 9   // assign RP9 as Input Pin
public const PPS_IN_RP42 = $0A  // assign RP10 as Input Pin
public const PPS_IN_RP46 = $0B  // assign RP11 as Input Pin

// GROUP (4n+3)
public const PPS_IN_RP3  = 0   // assign RP0 as Input Pin
public const PPS_IN_RP7  = 1   // assign RP1 as Input Pin
public const PPS_IN_RP11 = 2   // assign RP2 as Input Pin
public const PPS_IN_RP15 = 3   // assign RP3 as Input Pin
public const PPS_IN_RP19 = 4   // assign RP4 as Input Pin
public const PPS_IN_RP23 = 5   // assign RP5 as Input Pin
public const PPS_IN_RP27 = 6   // assign RP6 as Input Pin
public const PPS_IN_RP31 = 7   // assign RP7 as Input Pin
public const PPS_IN_RP35 = 8   // assign RP8 as Input Pin
public const PPS_IN_RP39 = 9   // assign RP9 as Input Pin
public const PPS_IN_RP43 = $0A  // assign RP10 as Input Pin
public const PPS_IN_RP47 = $0B  // assign RP11 as Input Pin
// alias name for unmapping an input pin
public const PPS_IN_UNUSED = PPS_IN_VSS
#endif      // (PPS_V4)

// pps input functions
#if defined (PPS_V1) or defined (PPS_V1_1) or defined (PPS_V2) or defined (PPS_V2_1) or _
    defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public dim PPS_INT1      as RPINR1  // assign External Interrupt 1 (INTR1) to the RPn pin
public dim PPS_INT2      as RPINR2  // assign External Interrupt 2 (INTR2) to the RPn pin
public dim PPS_INT3      as RPINR3  // assign External Interrupt 3 (INTR3) to the RPn pin
public dim PPS_T0CK      as RPINR4  // assign Timer0 External Clock (T0CK) to the RPn pin
public dim PPS_T3CK      as RPINR6  // assign Timer3 External Clock (T3CK) to the RPn pin
public dim PPS_IC1       as RPINR7  // assign Input Capture 1 (IC1) to the RPn pin
public dim PPS_IC2       as RPINR8  // assign Input Capture 2 (IC2) to the RPn pin
public dim PPS_T1G       as RPINR12 // assign Timer1 External Gate Input (TG1) to the RPn pin
public dim PPS_T3G       as RPINR13 // assign Timer3 External Gate Input (TG3) to the RPn pin
public dim PPS_RX2       as RPINR16 // assign EUSART2 Async/Sync Receive (RX2/DT2) to the RPn pin
public dim PPS_CK2       as RPINR17 // assign EUSART2 Sync Slave Clock Input (CK2) to the RPn pin
public dim PPS_SDI2      as RPINR21 // assign SDI2 Data Input (SDI2) to the RPn pin
public dim PPS_SCK2IN    as RPINR22 // assign SCK2 Clock Input (SCK2IN) to the RPn pin
public dim PPS_SS2IN     as RPINR23 // assign SS2 Slave Select Input (SS2IN) to the RPn pin
public dim PPS_FLT0      as RPINR24 // assign PWM Fault Input (FLT0)  to the RPn pin
#endif      // (PPS_V1) or (PPS_V1_1) or (PPS_V2) or (PPS_V2_1) od (PPS_V3) or (PPS_V3_1) or (PPS_V3B) or (PPS_V3B_1)

#if defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public dim PPS_T5CK      as RPINR15 // assign Timer5 External Clock (T5CK) to the RPn pin
public dim PPS_IC3       as RPINR9  // assign Input Capture 3 (IC3) to the RPn pin
public dim PPS_T5G       as RPINR14 // assign Timer5 External Gate Input (TG5) to the RPn pin
#endif      // (PPS_V3) or (PPS_V3_1) or (PPS_V3B_1)


// the PPS Lite module splits the RPINR registers into two nibbles with certain functions
// assigned to each of the upper and lower nibbles. in order to use a macro for this we need
// a unique value for each input function so that we can place the setting in the proper spot.
// we just assign numbers to the functions in increasing order... the number itself isn't 
// important as the macro will translate PPS_xxx input functions to RPINRxx registers
// some input function names had to be changed so that there is a unique input/output function
// (ie PPS_CCPx, PPS_PBIOx, etc)
// 
#if defined (PPS_V4)
// GROUP 4n
public const PPS_SDI1     = 0    // assign SDI1 Data input (SDI1) to the RPn pin
public const PPS_FLT0     = 1    // assign PWM Fault Input (FLT0) to the RPn pin
public const PPS_IOC0     = 2    // assign InterruptOnChange0 (IOC0) to the RPn pin
public const PPS_IOC4     = 3    // assign InterruptOnChange4 (IOC4) to the RPn pin
public const PPS_MDCIN1   = 4    // assign MDCIN1 to the RPn pin
public const PPS_T0CKI    = 5    // assign Timer0 External Clock (T0CKI) to the RPn pin
public const PPS_T5G      = 6    // assign Timer5 External Gate Input (T5G) to the RPn pin
public const PPS_U3RX     = 7    // assign EUSART3 Async/Sync Receive (RX3/DT3) to the RPn pin
public const PPS_U4RX     = 8    // assign EUSART4 Async/Sync Receive (RX4/DT4) to the RPn pin
public const PPS_IC5      = 9    // assign Input Capture 5 (CCP5)  to the RPn pin
public const PPS_IC8      = 10   // assign Input Capture 8 (CCP8) to the RPn pin
public const PPS_PBI0     = 11   // assign PBIO0 to the RPn pin (Virtual port?)
public const PPS_PBI4     = 12   // assign PBIO4 to the RPn pin

// GROUP (4n+1)
public const PPS_SDI2     = 13   // assign SDI1 Data input (SDI2) to the RPn pin
public const PPS_INT1     = 14   // assign External Interrupt 1 (INTR1) to the RPn pin
public const PPS_IOC1     = 15   // assign InterruptOnChange1 (IOC1) to the RPn pin
public const PPS_IOC5     = 16   // assign InterruptOnChange5 (IOC5) to the RPn pin
public const PPS_MDCIN2   = 17   // assign MDCIN2 to the RPn pin
public const PPS_T1CKI    = 18   // assign Timer1 External Clock (T1CKI) to the RPn pin
public const PPS_T1G      = 19   // assign Timer1 External Gate Input (T1G) to the RPn pin
public const PPS_T3CKI    = 20   // assign Timer3 External Clock (T3CKI) to the RPn pin
public const PPS_T3G      = 21   // assign Timer3 External Gate Input (T3G) to the RPn pin
public const PPS_T5CKI    = 22   // assign Timer5 External Clock (T5CKI) to the RPn pin
public const PPS_U3TX_CKI = 23   // assign EUSART3 Sync Clock In (TX3/CK3) to the RPn pin
public const PPS_U4TX_CKI = 24   // assign EUSART4 Sync Clock In (TX4/CK4) to the RPn pin
public const PPS_IC7      = 25   // assign Input Capture 7 (CCP7) to the RPn pin
public const PPS_IC9      = 26   // assign Input Capture 9 (CCP9) to the RPn pin
public const PPS_PBI1     = 27   // assign PBIO1 to the RPn pin
public const PPS_PBI5     = 28   // assign PBIO5 to the RPn pin

// GROUP (4n+2)
public const PPS_SS1      = 29   // assign SS1 (SS1) to the RPn pin
public const PPS_INT2     = 30   // assign External Interrupt 2 (INTR2) to the RPn pin
public const PPS_IOC2     = 31   // assign InterruptOnChange2 (IOC2) to the RPn pin
public const PPS_IOC6     = 32   // assign InterruptOnChange6 (IOC6) to the RPn pin
public const PPS_MDMIN    = 33   // assign MDMIN to the RPn pin
public const PPS_U1TX_CKI = 34   // assign EUSART1 Sync Clock In (TX1/CK1) to the RPn pin
public const PPS_U2RX     = 35   // assign EUSART2 Async/Sync Receive (RX2/DT2) to the RPn pin
public const PPS_SCK2IN   = 36   // assign SCK2 to the RPn pin
public const PPS_ECCP3    = 37   // assign ECCP3 to the RPn pin
public const PPS_IC6      = 38   // assign Input Capture 6 (CCP6) to the RPn pin
public const PPS_IC10     = 39   // assign Input Capture 10 (CCP10) to the RPn pin
public const PPS_PBI2     = 40   // assign PBIO2 to the RPn pin
public const PPS_PBI6     = 41   // assign PBIO6 to the RPn pin

// GROUP (4n+3)
public const PPS_SS2      = 42   // assign SS2 (SS2) to the RPn pin
public const PPS_INT3     = 43   // assign External Interrupt 3 (INTR3) to the RPn pin
public const PPS_IOC3     = 44   // assign InterruptOnChange3 (IOC3) to the RPn pin
public const PPS_IOC7     = 45   // assign InterruptOnChange7 (IOC7) to the RPn pin
public const PPS_U1RX     = 46   // assign EUSART1 Async/Sync Receive (RX1/DT1) to the RPn pin
public const PPS_U2TX_CKI = 47   // assign EUSART2 Sync Clock In (TX2/CK2) to the RPn pin
public const PPS_SCK1IN   = 48   // assign SCK1 to the RPn pin
public const PPS_ECCP1    = 49   // assign ECCP1 to the RPn pin
public const PPS_ECCP2    = 50   // assign ECCP2  to the RPn pin
public const PPS_IC4      = 51   // assign Input Capture 4 (CCP4) to the RPn pin
public const PPS_PBI3     = 52   // assign PBIO2 to the RPn pin
public const PPS_PBI7     = 53   // assign PBIO6 to the RPn pin
#endif      // (PPS_V4)


// K40 family device
#if defined(PPS_V5_1) or defined(PPS_V5_1B) or defined(PPS_V5_2) or defined(PPS_V5_3)
// Register Definitions: PPS Input Selection
// xxxPPS<4:3> Peripheral xxx Input PORTx Selection bits
public const
    PPS_PORTA as byte = %0000,
    PPS_PORTB as byte = %0001,
    PPS_PORTC as byte = %0010

// 18(L)F4xK40, 18(L)F6xK40
#if defined(PPS_V5_2) or defined(PPS_V5_3)
public const    
    PPS_PORTD as byte = %0011
#endif      // 4xK40, 6xK40

// 18(L)F6xK40
#if defined(PPS_V5_3) 
public const
    PPS_PORTE as byte = %0100,
    PPS_PORTF as byte = %0101,
    PPS_PORTG as byte = %0110,
    PPS_PORTH as byte = %0111
#endif      // 6xK40

// xxxPPS<2:0>: Peripheral xxx Input PINx Pin Selection bits
//   pin selection bits are three bits 0-7, ie port pin 0(Rx0) = 0, port pin 7(Rx7) = 7
// xxxPPS<4:3>: Peripheral xxx Input PORTx Pin Selection bits
//   port selection bits are four bits 0-3: 0000=PORTA, 0001=PORTB, 0010=PORTC, 0011=PORTD, etc

// K40 family
// assign_input(input_function_reg, pps_port, pin_no)
//
// assigns pps input function to a pin
//  input_function_reg  pps input register/function (ie INT0PPS) from datasheet TABLE 17-1
//  pps_port            one of PPS_PORTA to PPS_PORTH definitions above
//  pin_no              port pin number 0-7
//
// to assign an input function to a pin set xxxPPS reg input PORT bits[4:3] and PIN bits[2:0]:
//  xxxPPS = (PPS_PORTx << 3) + (port_pin_no and %111)
// macro example:
//  pps.assign_input(INT0PPS, PPS_PORTA, 4)     // assigns INT0 input to RA4
//  pps.assign_input(RX1PPS, PPS_PORTB, 2)      // assigns usart RX1 input to RB2
// note: pps input functions are limited to specific ports
//  currently the macro does not check to see if the assignment is valid (nothing does)
//  refer to TABLE 17-1: PPS INPUT REGISTER DETAILS in the device datasheet for specifics
//
public macro assign_input(pps_function_reg, pps_port, pin_no)
    pps_function_reg = ((pps_port and %0111) << 3) + (pin_no and %111)
end macro

// Q10 family device
#elseif defined(PPS_V6_1) or defined(PPS_V6_2)
// Register Definitions: PPS Input Selection
// xxxPPS<4:3> Peripheral xxx Input PORTx Selection bits
public const
    PPS_PORTA as byte = %0000,
    PPS_PORTB as byte = %0001,
    PPS_PORTC as byte = %0010

// 18F4xQ10
#if _device in(18F45Q10, 18F46Q10, 18F47Q10)
public const    
    PPS_PORTD as byte = %0011
#endif      // 4xQ10

// xxxPPS<2:0>: Peripheral xxx Input PINx Pin Selection bits
//   pin selection bits are three bits 0-7, ie port pin 0(Rx0) = 0, port pin 7(Rx7) = 7
// xxxPPS<4:3>: Peripheral xxx Input PORTx Pin Selection bits
//   port selection bits are two bits 0-1: 00=PORTA, 01=PORTB, 10=PORTC, 11=PORTD

// Q10 family (similar to K40)
// assign_input(input_function_reg, pps_port, pin_no)
//
// assigns pps input function to a pin
//  input_function_reg  pps input register/function (ie INT0PPS) from datasheet TABLE 17-1
//  pps_port            one of PPS_PORTA to PPS_PORTD definitions above
//  pin_no              port pin number 0-7
//
// to assign an input function to a pin set xxxPPS reg input PORT bits[4:3] and PIN bits[2:0]:
//  xxxPPS = (PPS_PORTx << 3) + (port_pin_no and %111)
// macro example:
//  pps.assign_input(INT0PPS, PPS_PORTA, 4)     // assigns INT0 input to RA4
//  pps.assign_input(RX1PPS, PPS_PORTB, 2)      // assigns usart RX1 input to RB2
// note: pps input functions are limited to specific ports
//  currently the macro does not check to see if the assignment is valid (nothing does)
//  refer to TABLE 17-1: PPS INPUT REGISTER DETAILS in the device datasheet for specifics
//
public macro assign_input(pps_function_reg, pps_port, pin_no)
    pps_function_reg = ((pps_port and %0111) << 3) + (pin_no and %111)
end macro

// J94/J99 family 
#elseif defined(PPS_V4)
//------------------------------------------------------------------------------
// assign_input(input_fn, rp_pin)
//
// assigns pps input function to a pin
//  input_fn            input function/register (ie PPS_RX2)
//  rp_pin              PPS_IN_RPx pin (ie PPS_IN_RP0)
// example usage:
//  assign_input(PPS_INT1, PPS_IN_UNUSED)     'unmaps INT1 function
//  assign_input(PPS_RX2, PPS_IN_RP0)         'sets RPINR16 to RP0 pin
//
//------------------------------------------------------------------------------
public macro assign_input(input_fn, rp_pin)
    // for the PPS Lite module we need to translate input "function numbers"
    // to register and upper/lower nibble selection. just do it brute force
    // since the macro will remove all the unused code
    // taken from J94/J99 family datasheet Table 11-12

    // functions that use the lower nibble of the RPINRxx reg
    if (input_fn = PPS_PBI6) then
        RPINR52_53 = (RPINR52_53 and $F0) or rp_pin
    elseif (input_fn = PPS_PBI4) then
        RPINR50_51 = (RPINR50_51 and $F0) or rp_pin
    elseif (input_fn = PPS_PBI2) then
        RPINR48_49 = (RPINR48_49 and $F0) or rp_pin
    elseif (input_fn = PPS_PBI0) then
        RPINR46_47 = (RPINR46_47 and $F0) or rp_pin
    elseif (input_fn = PPS_T5G) then
        RPINR44_45 = (RPINR44_45 and $F0) or rp_pin
    elseif (input_fn = PPS_T3G) then
        RPINR42_43 = (RPINR42_43 and $F0) or rp_pin
    elseif (input_fn = PPS_T1G) then
        RPINR40_41 = (RPINR40_41 and $F0) or rp_pin
    elseif (input_fn = PPS_IC10) then
        RPINR38_39 = (RPINR38_39 and $F0) or rp_pin
    elseif (input_fn = PPS_IC8) then
        RPINR36_37 = (RPINR36_37 and $F0) or rp_pin
    elseif (input_fn = PPS_IC6) then
        RPINR34_35 = (RPINR34_35 and $F0) or rp_pin
    elseif (input_fn = PPS_IC4) then
        RPINR32_33 = (RPINR32_33 and $F0) or rp_pin
    elseif (input_fn = PPS_MDCIN1) then
        RPINR30_31 = (RPINR30_31 and $F0) or rp_pin
    elseif (input_fn = PPS_INT3) then
        RPINR28_29 = (RPINR28_29 and $F0) or rp_pin
    elseif (input_fn = PPS_INT1) then
        RPINR26_27 = (RPINR26_27 and $F0) or rp_pin
    elseif (input_fn = PPS_IOC6) then
        RPINR24_25 = (RPINR24_25 and $F0) or rp_pin
    elseif (input_fn = PPS_IOC4) then
        RPINR22_23 = (RPINR22_23 and $F0) or rp_pin
    elseif (input_fn = PPS_IOC2) then
        RPINR20_21 = (RPINR20_21 and $F0) or rp_pin
    elseif (input_fn = PPS_IOC0) then
        RPINR18_19 = (RPINR18_19 and $F0) or rp_pin
    elseif (input_fn = PPS_ECCP2) then
        RPINR16_17 = (RPINR16_17 and $F0) or rp_pin
    elseif (input_fn = PPS_FLT0) then
        RPINR14_15 = (RPINR14_15 and $F0) or rp_pin
    elseif (input_fn = PPS_SDI2) then
        RPINR12_13 = (RPINR12_13 and $F0) or rp_pin
    elseif (input_fn = PPS_SS1) then
        RPINR10_11 = (RPINR10_11 and $F0) or rp_pin
    elseif (input_fn = PPS_SCK1IN) then
        RPINR8_9 = (RPINR8_9 and $F0) or rp_pin
    elseif (input_fn = PPS_U4RX) then
        RPINR6_7 = (RPINR6_7 and $F0) or rp_pin
    elseif (input_fn = PPS_U3RX) then
        RPINR4_5 = (RPINR4_5 and $F0) or rp_pin
    elseif (input_fn = PPS_U2RX) then
        RPINR2_3 = (RPINR2_3 and $F0) or rp_pin
    elseif (input_fn = PPS_U1RX) then
        RPINR0_1 = (RPINR0_1 and $F0) or rp_pin
    endif

    // functions that use the upper nibble of the RPINRxx reg
    if (input_fn = PPS_U1TX_CKI) then
        RPINR0_1 = (RPINR0_1 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_U2TX_CKI) then
        RPINR2_3 = (RPINR2_3 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_U3TX_CKI) then
        RPINR4_5 = (RPINR4_5 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_U4TX_CKI) then
        RPINR6_7 = (RPINR6_7 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_SDI1) then
        RPINR8_9 = (RPINR8_9 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_SCK2IN) then
        RPINR10_11 = (RPINR10_11 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_SS2) then
        RPINR12_13 = (RPINR12_13 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_ECCP1) then
        RPINR14_15 = (RPINR14_15 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_ECCP3) then
        RPINR16_17 = (RPINR16_17 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IOC1) then
        RPINR18_19 = (RPINR18_19 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IOC3) then
        RPINR20_21 = (RPINR20_21 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IOC5) then
        RPINR22_23 = (RPINR22_23 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IOC7) then
        RPINR24_25 = (RPINR24_25 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_INT2) then
        RPINR26_27 = (RPINR26_27 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_MDMIN) then
        RPINR28_29 = (RPINR28_29 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_MDCIN2) then
        RPINR30_31 = (RPINR30_31 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IC5) then
        RPINR32_33 = (RPINR32_33 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IC7) then
        RPINR34_35 = (RPINR34_35 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_IC9) then
        RPINR36_37 = (RPINR36_37 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_T0CKI) then
        RPINR38_39 = (RPINR38_39 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_T1CKI) then
        RPINR40_41 = (RPINR40_41 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_T3CKI) then
        RPINR42_43 = (RPINR42_43 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_T5CKI) then
        RPINR44_45 = (RPINR44_45 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_PBI1) then
        RPINR46_47 = (RPINR46_47 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_PBI3) then
        RPINR48_49 = (RPINR48_49 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_PBI5) then
        RPINR50_51 = (RPINR50_51 and $0F) or (rp_pin << 4)
    elseif (input_fn = PPS_PBI7) then
        RPINR52_53 = (RPINR52_53 and $0F) or (rp_pin << 4)
    endif
end macro

// regular V1-V3 PPS module
#else
public macro assign_input(input_rp_reg, rp_pin)
    input_rp_reg = rp_pin
end macro
#endif      // PPS_V5/PPS_V4/PPS_V1-PPS_V3


//
//------------------------------------------------------------------------------
// PPS output
//------------------------------------------------------------------------------
//

// pps output functions
#if defined (PPS_V1) or defined (PPS_V2) or defined (PPS_V1_1) or defined (PPS_V2_1) or _
    defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public const PPS_NULL       =  0  // RPn tied to default port pin
public const PPS_C1OUT      =  1  // RPn tied to comparator 1 output
public const PPS_C2OUT      =  2  // RPn tied to comparator 2 output
public const PPS_ULPWU      = 13  // RPn tied to Ultra Low Power Wake Up Event
public const PPS_CCP1P1A    = 14  // RPn tied to ECCP1/CCP1 compare or PWM output channel A
public const PPS_P1B        = 15  // RPn tied to ECCP1 Enhanced PWM output, channel B
public const PPS_P1C        = 16  // RPn tied to ECCP1 Enhanced PWM output, channel C
public const PPS_P1D        = 17  // RPn tied to ECCP1 Enhanced PWM output, channel D
public const PPS_CCP2P2A    = 18  // RPn tied to ECCP2/CCP2 compare or PWM output
public const PPS_P2B        = 19  // RPn tied to ECCP2 Enhanced PWM output, channel B
public const PPS_P2C        = 20  // RPn tied to ECCP2 Enhanced PWM output, channel C
public const PPS_P2D        = 21  // RPn tied to ECCP2 Enhanced PWM output, channel D
// alias name for unmapping an output pin
public const PPS_OUT_UNUSED = PPS_NULL
#endif      // (PPS_V1) or (PPS_V2) or (PPS_V1_1) or (PPS_V2_1) or (PPS_V3) or (PPS_V3_1) or (PPS_V3B) or (PPS_V3B_1)

#if defined (PPS_V1) or defined (PPS_V2) or defined (PPS_V1_1) or defined (PPS_V2_1)
public const PPS_TX2CK2     =  5  // RPn tied to EUSART 2 Async Transmit / Sync Clock Output
public const PPS_TX2        =  5  // alias for PPS_TX2CK2
public const PPS_DT2        =  6  // RPn tied to EUSART 2 Sync Transmit
public const PPS_SDO2       =  9  // RPn tied to SPI2 Data Output
public const PPS_SCK2       = 10  // RPn tied to SPI2 Clock Output
public const PPS_SSDMA      = 12  // RPn tied to SPI DMA Slave Select
#endif      // (PPS_V1) or (PPS_V2) or (PPS_V1_1) or (PPS_V2_1)

#if defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public const PPS_C3OUT      =  3  // RPn tied to comparator 3 output
public const PPS_TX2CK2     =  6  // RPn tied to EUSART 2 Async Transmit / Sync Clock Output
public const PPS_TX2        =  6  // alias for PPS_TX2CK2
public const PPS_DT2        =  7  // RPn tied to EUSART 2 Sync Transmit
public const PPS_SDO2       = 10  // RPn tied to SPI2 Data Output
public const PPS_SCK2       = 11  // RPn tied to SPI2 Clock Output
public const PPS_SSDMA      = 12  // RPn tied to SPI DMA Slave Select
public const PPS_CCP3P3A    = 22  // RPn tied to ECCP3/CCP3 compare or PWM output
public const PPS_P3B        = 23  // RPn tied to ECCP3 Enhanced PWM output, channel B
public const PPS_P3C        = 24  // RPn tied to ECCP3 Enhanced PWM output, channel C
public const PPS_P3D        = 25  // RPn tied to ECCP3 Enhanced PWM output, channel D
#endif      // (PPS_V3) or (PPS_V3_1) or (PPS_V3B) or (PPS_V3B_1)

#if defined (PPS_V4)
// some output function names had to be changed so that there is a unique input/output function
// (ie PPS_CCPx, PPS_PBIOx, etc)
public const PPS_NULL       = 0  // RPn tied to default port pin
// alias name for unmapping an output pin
public const PPS_OUT_UNUSED = PPS_NULL
// GROUP 4n
public const PPS_U2BCLK     = 1  // RPn tied to U2BCLK port pin
public const PPS_U3RX_DT    = 2  // RPn tied to EUSART3 Sync transmit (RX3/DT3) output
public const PPS_U4RX_DT    = 3  // RPn tied to EUSART4 Sync transmit (TRX4/DT4) output
public const PPS_SDO2       = 4  // RPn tied to SPI2 Data Output
public const PPS_P1D        = 5  // RPn tied to ECCP1 Enhanced PWM output, channel D
public const PPS_P2D        = 6  // RPn tied to ECCP2 Enhanced PWM output, channel D
public const PPS_P3B        = 7  // RPn tied to ECCP3 Enhanced PWM output, channel B
public const PPS_CTPLS      = 8  // RPn tied to CTPLS
public const PPS_CCP5       = 9  // RPn tied to CCP5 compare or PWM output
public const PPS_CCP8       = $0A  // RPn tied to CCP8 compare or PWM output
public const PPS_C1OUT      = $0B  // RPn tied to comparator 1
public const PPS_PBO0       = $0D  // RPn tied to PBIO0
public const PPS_PBO4       = $0E  // RPn tied to PBIO4

// GROUP (4n+1)
public const PPS_U1BCLK     = 1  // RPn tied to U1BCLK port pin
public const PPS_U3TX_CK    = 2  // RPn tied to EUSART3 Async Transmit / sync Clock Output
public const PPS_U3TX       = PPS_U3TX_CK
public const PPS_U4TX_CK    = 3  // RPn tied to EUSART4 Async Transmit / sync Clock Output
public const PPS_U4TX       = PPS_U4TX_CK
public const PPS_SDO1       = 4  // RPn tied to SPI1 Data Output
public const PPS_P1C        = 5  // RPn tied to ECCP1 Enhanced PWM output, channel C
public const PPS_P2C        = 6  // RPn tied to ECCP2 Enhanced PWM output, channel C
public const PPS_P3C        = 7  // RPn tied to ECCP3 Enhanced PWM output, channel C
public const PPS_CCP7       = 8  // RPn tied to CCP7 compare or PWM output
public const PPS_CCP9       = 9  // RPn tied to CCP9 compare or PWM output
public const PPS_C2OUT      = $0A  // RPn tied to comparator 2
public const PPS_PBO1       = $0D  // RPn tied to PBIO1
public const PPS_PBO5       = $0E  // RPn tied to PBIO5

// GROUP (4n+2)
public const PPS_U1TX_CK    = 1  // RPn tied to EUSART1 Async Transmit / sync Clock Output
public const PPS_U1TX       = PPS_U1TX_CK
public const PPS_U2RX_DT    = 2  // RPn tied to EUSART2 Async/Sync Receive (RX2/DT2)
public const PPS_U3BCLK     = 3  // RPn tied to U3BCLK port pin
public const PPS_U4BCLK     = 4  // RPn tied to U4BCLK port pin
public const PPS_SCK2       = 5  // RPn tied to SPI2 Clock Output
public const PPS_P1B        = 6  // RPn tied to ECCP1 Enhanced PWM output, channel B
public const PPS_P2B        = 7  // RPn tied to ECCP2 Enhanced PWM output, channel B
public const PPS_ECCP3P3A   = 8  // RPn tied to ECCP3/CCP3 compare or PWM output
public const PPS_CCP6       = 9  // RPn tied to CCP6 compare or PWM output
public const PPS_CCP10      = $0A  // RPn tied to CCP10 compare or PWM output
public const PPS_PBO2       = $0D  // RPn tied to PBIO2
public const PPS_PBO6       = $0E  // RPn tied to PBIO6

// GROUP (4n+3)
public const PPS_U1RX_DT    = 1     // RPn tied to EUSART1 Async/sync Receive (RX1/DT1)
public const PPS_U2TX_CK    = 2     // RPn tied to EUSART2 Async Transmit / sync Clock Output
public const PPS_U2TX       = PPS_U2TX_CK
public const PPS_SCK1       = 3     // RPn tied to SPI1 Clock Output
public const PPS_ECCP1P1A   = 4     // RPn tied to ECCP1/CCP1 compare or PWM output
public const PPS_ECCP2P2A   = 5     // RPn tied to ECCP2/CCP2 compare or PWM output
public const PPS_P3D        = 6     // RPn tied to ECCP3 Enhanced PWM output, channel D
public const PPS_MDOUT      = 7     // RPn tied to MDOUT port pin
public const PPS_CCP4       = 8     // RPn tied to CCP4 compare or PWM output
public const PPS_C3OUT      = 9     // RPn tied to comparator 3
public const PPS_PBO3       = $0D   // RPn tied to PBIO3
public const PPS_PBO7       = $0E   // RPn tied to PBIO7
#endif      // (PPS_V4)


// pps output pin definitions
#if defined (PPS_V1) or defined (PPS_V2) or defined (PPS_V1_1) or defined (PPS_V2_1) or _
    defined (PPS_V3) or defined (PPS_V3_1) or defined (PPS_V3B) or defined (PPS_V3B_1)
public dim PPS_OUT_RP0      as RPOR0   // assign RP0 as Output Pin
public dim PPS_OUT_RP1      as RPOR1   // assign RP1 as Output Pin
public dim PPS_OUT_RP2      as RPOR2   // assign RP2 as Output Pin
public dim PPS_OUT_RP3      as RPOR3   // assign RP3 as Output Pin
public dim PPS_OUT_RP4      as RPOR4   // assign RP4 as Output Pin
public dim PPS_OUT_RP5      as RPOR5   // assign RP5 as Output Pin
public dim PPS_OUT_RP6      as RPOR6   // assign RP6 as Output Pin
public dim PPS_OUT_RP7      as RPOR7   // assign RP7 as Output Pin
public dim PPS_OUT_RP8      as RPOR8   // assign RP8 as Output Pin
public dim PPS_OUT_RP9      as RPOR9   // assign RP9 as Output Pin
public dim PPS_OUT_RP10     as RPOR10  // assign RP10 as Output Pin
public dim PPS_OUT_RP11     as RPOR11  // assign RP11 as Output Pin
public dim PPS_OUT_RP12     as RPOR12  // assign RP12 as Output Pin
public dim PPS_OUT_RP13     as RPOR13  // assign RP13 as Output Pin
public dim PPS_OUT_RP17     as RPOR17  // assign RP17 as Output Pin
public dim PPS_OUT_RP18     as RPOR18  // assign RP18 as Output Pin
#endif      // (PPS_V1) or (PPS_V2) or (PPS_V1_1) or (PPS_V2_1) or (PPS_V3) or (PPS_V3_1) or (PPS_V3B) or (PPS_V3B_1)

#if defined (PPS_V1_1) or defined (PPS_V2_1) or defined (PPS_V3) or defined (PPS_V3_1)
public dim PPS_OUT_RP14     as RPOR14  // assign RP14 as Output Pin
public dim PPS_OUT_RP15     as RPOR15  // assign RP15 as Output Pin
public dim PPS_OUT_RP16     as RPOR16  // assign RP16 as Output Pin
#endif      // (PPS_V1_1) or (PPS_V2_1) or (PPS_V3) or (PPS_V3_1)

#if defined (PPS_V2) or defined (PPS_V2_1) or defined (PPS_V3_1)  or defined (PPS_V3B_1)
public dim PPS_OUT_RP19     as RPOR19  // assign RP19 as Output Pin
public dim PPS_OUT_RP20     as RPOR20  // assign RP20 as Output Pin
public dim PPS_OUT_RP21     as RPOR21  // assign RP21 as Output Pin
public dim PPS_OUT_RP22     as RPOR22  // assign RP22 as Output Pin
public dim PPS_OUT_RP23     as RPOR23  // assign RP23 as Output Pin
public dim PPS_OUT_RP24     as RPOR24  // assign RP24 as Output Pin
#endif      // (PPS_V2) or (PPS_V2_1) or (PPS_V3_1) or (PPS_V3B_1)

// the PPS Lite module splits the RPOR registers into two nibbles with certain pins
// assigned to each of the upper and lower nibbles. in order to use a macro for this we need
// a unique value for each output pin so that we can place the setting in the proper spot. 
// we just assign numbers to the output pins to match the RPx number... the number itself 
// isn't important as the macro will translate PPS_OUT_RPxx pins to RPORx registers
#if defined (PPS_V4)
// GROUP 4n
public const PPS_OUT_RP0    = 0      // assign RP0 as Output Pin
public const PPS_OUT_RP4    = 4      // assign RP4 as Output Pin
public const PPS_OUT_RP8    = 8      // assign RP8 as Output Pin
public const PPS_OUT_RP12   = 12     // assign RP12 as Output Pin
public const PPS_OUT_RP16   = 16     // assign RP16 as Output Pin
public const PPS_OUT_RP20   = 20     // assign RP20 as Output Pin
public const PPS_OUT_RP24   = 24     // assign RP24 as Output Pin
public const PPS_OUT_RP28   = 28     // assign RP28 as Output Pin
public const PPS_OUT_RP32   = 32     // assign RP32 as Output Pin
public const PPS_OUT_RP36   = 36     // assign RP36 as Output Pin
public const PPS_OUT_RP40   = 40     // assign RP40 as Output Pin
public const PPS_OUT_RP44   = 44     // assign RP44 as Output Pin

// GROUP (4n+1)
public const PPS_OUT_RP1    = 1      // assign RP1 as Output Pin
public const PPS_OUT_RP5    = 5      // assign RP5 as Output Pin
public const PPS_OUT_RP9    = 9      // assign RP9 as Output Pin
public const PPS_OUT_RP13   = 13     // assign RP13 as Output Pin
public const PPS_OUT_RP17   = 17     // assign RP17 as Output Pin
public const PPS_OUT_RP21   = 21     // assign RP21 as Output Pin
public const PPS_OUT_RP25   = 25     // assign RP25 as Output Pin
public const PPS_OUT_RP29   = 29     // assign RP29 as Output Pin
public const PPS_OUT_RP33   = 33     // assign RP33 as Output Pin
public const PPS_OUT_RP37   = 37     // assign RP37 as Output Pin
public const PPS_OUT_RP41   = 41     // assign RP41 as Output Pin
public const PPS_OUT_RP45   = 45     // assign RP45 as Output Pin

// GROUP (4n+2)
public const PPS_OUT_RP2    = 2      // assign RP2 as Output Pin
public const PPS_OUT_RP6    = 6      // assign RP6 as Output Pin
public const PPS_OUT_RP10   = 10     // assign RP10 as Output Pin
public const PPS_OUT_RP14   = 14     // assign RP14 as Output Pin
public const PPS_OUT_RP18   = 18     // assign RP18 as Output Pin
public const PPS_OUT_RP22   = 22     // assign RP22 as Output Pin
public const PPS_OUT_RP26   = 26     // assign RP26 as Output Pin
public const PPS_OUT_RP30   = 30     // assign RP30 as Output Pin
public const PPS_OUT_RP34   = 34     // assign RP34 as Output Pin
public const PPS_OUT_RP38   = 38     // assign RP38 as Output Pin
public const PPS_OUT_RP42   = 42     // assign RP42 as Output Pin
public const PPS_OUT_RP46   = 46     // assign RP46 as Output Pin

// GROUP (4n+3)
public const PPS_OUT_RP3    = 3      // assign RP3 as Output Pin
public const PPS_OUT_RP7    = 7      // assign RP7 as Output Pin
public const PPS_OUT_RP11   = 11     // assign RP11 as Output Pin
public const PPS_OUT_RP15   = 15     // assign RP15 as Output Pin
public const PPS_OUT_RP19   = 19     // assign RP19 as Output Pin
public const PPS_OUT_RP23   = 23     // assign RP23 as Output Pin
public const PPS_OUT_RP27   = 27     // assign RP27 as Output Pin
public const PPS_OUT_RP31   = 31     // assign RP31 as Output Pin
public const PPS_OUT_RP35   = 35     // assign RP35 as Output Pin
public const PPS_OUT_RP39   = 39     // assign RP39 as Output Pin
public const PPS_OUT_RP43   = 43     // assign RP43 as Output Pin

#endif      // (PPS_V4)


//
//----------------------------------------------------------
// PPS output pin assignments
//----------------------------------------------------------
//
// K40 family
#if defined(PPS_V5_1) or defined(PPS_V5_1B) or defined(PPS_V5_2) or defined(PPS_V5_3) 
// 24K40, 25K40 (see errata DS80000711B pg 6)
// v1.50 note: these were changed in datasheet 40001843D
#if defined(PPS_V5_1)
public const
    PPS_ADGRDB        as byte = $13,   
    PPS_ADGRDA        as byte = $14,        // was $12                                   w
    PPS_DSM           as byte = $11,   
    PPS_CLKR          as byte = $10,    
    PPS_TMR0          as byte = $0F,   
    PPS_MSSP1_SDO_SDA as byte = $0E,    
    PPS_MSSP1_SCK_SCL as byte = $0D,   
    PPS_CMP2          as byte = $0C,    
    PPS_CMP1          as byte = $0B,   
    PPS_EUSART1_RX    as byte = $0A,   
    PPS_EUSART1_TX    as byte = $09,   
    PPS_PWM4          as byte = $08,   
    PPS_PWM3          as byte = $07,   
    PPS_CCP2          as byte = $06,   
    PPS_CCP1          as byte = $05,   
    PPS_CWG1D         as byte = $04,   
    PPS_CWG1C         as byte = $03,   
    PPS_CWG1B         as byte = $02,   
    PPS_CWG1A         as byte = $01,   
    PPS_LAT           as byte = $00,    
    PPS_NULL          as byte = PPS_LAT
#endif      // PPS_5_1

// 26K40, 27K40, 4xK40
#if defined(PPS_V5_1B) or defined(PPS_V5_2) 
public const
    PPS_ADGRDB        as byte = $17,   
    PPS_ADGRDA        as byte = $16,   
    PPS_DSM           as byte = $15,    
    PPS_CLKR          as byte = $14,    
    PPS_TMR0          as byte = $13,    
    PPS_MSSP2_SDO_SDA as byte = $12,     
    PPS_MSSP2_SCK_SCL as byte = $11,   
    PPS_MSSP1_SDO_SDA as byte = $10,   
    PPS_MSSP1_SCK_SCL as byte = $0F,   
    PPS_CMP2          as byte = $0E,    
    PPS_CMP1          as byte = $0D,   
    PPS_EUSART2_RX    as byte = $0C,    
    PPS_EUSART2_TX    as byte = $0B,    
    PPS_EUSART1_RX    as byte = $0A,   
    PPS_EUSART1_TX    as byte = $09,    
    PPS_PWM4          as byte = $08,    
    PPS_PWM3          as byte = $07,    
    PPS_CCP2          as byte = $06,   
    PPS_CCP1          as byte = $05,   
    PPS_CWG1D         as byte = $04,   
    PPS_CWG1C         as byte = $03,   
    PPS_CWG1B         as byte = $02,   
    PPS_CWG1A         as byte = $01,   
    PPS_LAT           as byte = $00,    
    PPS_NULL          as byte = PPS_LAT
#endif      // PPS_5_1B/5_2

// 6xK40
#if defined(PPS_V5_3)
public const
    PPS_ADGRDB        as byte = $21,
    PPS_ADGRDA        as byte = $20,
    PPS_DSM           as byte = $1f,
    PPS_CLKR          as byte = $1e,
    PPS_TMR0          as byte = $1d,
    PPS_MSSP2_SDO_SDA as byte = $1c,
    PPS_MSSP2_SCK_SCL as byte = $1b,
    PPS_MSSP1_SDO_SDA as byte = $1a,
    PPS_MSSP1_SCK_SCL as byte = $19,
    PPS_CMP3          as byte = $18,
    PPS_CMP2          as byte = $17,
    PPS_CMP1          as byte = $16,
    PPS_EUSART5_DT    as byte = $15,
    PPS_EUSART5_RX    as byte = $15,
    PPS_EUSART5_TX_CK as byte = $14,
    PPS_EUSART5_TX    as byte = $14,
    PPS_EUSART4_DT    as byte = $13,
    PPS_EUSART4_RX    as byte = $13,
    PPS_EUSART4_TX_CK as byte = $12,
    PPS_EUSART4_TX    as byte = $12,
    PPS_EUSART3_DT    as byte = $11,
    PPS_EUSART3_RX    as byte = $11,
    PPS_EUSART3_TX_CK as byte = $10,
    PPS_EUSART3_TX    as byte = $10,
    PPS_EUSART2_DT    as byte = $0f,
    PPS_EUSART2_RX    as byte = $0f,
    PPS_EUSART2_TX_CK as byte = $0e,
    PPS_EUSART2_TX    as byte = $0e,
    PPS_EUSART1_DT    as byte = $0d,
    PPS_EUSART1_RX    as byte = $0d,
    PPS_EUSART1_TX_CK as byte = $0c,
    PPS_EUSART1_TX    as byte = $0c,
    PPS_PWM7          as byte = $0b,
    PPS_PWM6          as byte = $0a,
    PPS_CCP5          as byte = $09,
    PPS_CCP4          as byte = $08,
    PPS_CCP3          as byte = $07,
    PPS_CCP2          as byte = $06,
    PPS_CCP1          as byte = $05,
    PPS_CWG1D         as byte = $04,
    PPS_CWG1C         as byte = $03,
    PPS_CWG1B         as byte = $02,
    PPS_CWG1A         as byte = $01,
    PPS_LAT           as byte = $00,
    PPS_NULL          as byte = PPS_LAT
#endif      // PPS_5_3

//
// to assign an output function to a pin:
//  RxxPPS = pps_output_function
// macro example:
//  pps.assign_output(RA0PPS, PPS_TMR0)         // assigns TMR0 output to RA0
//  pps.assign_output(RB1PPS, PPS_EUSART1_TX)   // assigns usart TX1 output to RB1
// note: pps output functions are limited to specific ports
//  currently the macro does not check to see if the assignment is valid (nothing does)
//  refer to REGISTER 17-2 PIN Rxy OUTPUT SOURCE SELECTION REGISTER
// note: for the K40 family this macro doesn't really do much at all
//
public macro assign_output(pps_port_sel_reg, pps_out_function)
    pps_port_sel_reg = pps_out_function
end macro

// Q10 family
#elseif defined(PPS_V6_1) or defined(PPS_V6_2)
#if defined(PPS_V6_1) 
// 24Q10, 25Q10 datasheet DS40001945B
public const
    PPS_ADGRDB        as byte = $13,   
    PPS_ADGRDA        as byte = $12,        // likely a mistake... K40 has this as $14 now
    PPS_DSM           as byte = $11,   
    PPS_CLKR          as byte = $10,    
    PPS_TMR0          as byte = $0F,   
    PPS_MSSP1_SDO_SDA as byte = $0E,    
    PPS_MSSP1_SCK_SCL as byte = $0D,   
    PPS_CMP2          as byte = $0C,    
    PPS_CMP1          as byte = $0B,   
    PPS_EUSART1_RX    as byte = $0A,   
    PPS_EUSART1_TX    as byte = $09,   
    PPS_PWM4          as byte = $08,   
    PPS_PWM3          as byte = $07,   
    PPS_CCP2          as byte = $06,   
    PPS_CCP1          as byte = $05,   
    PPS_CWG1D         as byte = $04,   
    PPS_CWG1C         as byte = $03,   
    PPS_CWG1B         as byte = $02,   
    PPS_CWG1A         as byte = $01,   
    PPS_LAT           as byte = $00,    
    PPS_NULL          as byte = PPS_LAT
#endif  // PPS_V6_1

// 26Q10, 45Q10, 46Q10, 27Q10, 47Q10
#if defined(PPS_V6_2) 
public const
    PPS_CLC8OUT       as byte = $1F,
    PPS_CLC7OUT       as byte = $1E,
    PPS_CLC6OUT       as byte = $1D,
    PPS_CLC5OUT       as byte = $1C,
    PPS_CLC4OUT       as byte = $1B,
    PPS_CLC3OUT       as byte = $1A,
    PPS_CLC2OUT       as byte = $19,
    PPS_CLC1OUT       as byte = $18,
    PPS_ADGRDB        as byte = $17,   
    PPS_ADGRDA        as byte = $16,  
    PPS_DSM           as byte = $15, 
    PPS_CLKR          as byte = $14,   
    PPS_TMR0          as byte = $13,
    PPS_MSSP2_SDO_SDA as byte = $12,
    PPS_MSSP2_SCK_SCL as byte = $11,
    PPS_MSSP1_SDO_SDA as byte = $10,
    PPS_MSSP1_SCK_SCL as byte = $0F,
    PPS_CMP2          as byte = $0E,
    PPS_CMP1          as byte = $0D,
    PPS_EUSART2_RX    as byte = $0C,
    PPS_EUSART2_TX    as byte = $0B,
    PPS_EUSART1_RX    as byte = $0A,
    PPS_EUSART1_TX    as byte = $09,
    PPS_PWM4          as byte = $08,
    PPS_PWM3          as byte = $07,   
    PPS_CCP2          as byte = $06,    
    PPS_CCP1          as byte = $05,    
    PPS_CWG1D         as byte = $04,     
    PPS_CWG1C         as byte = $03,     
    PPS_CWG1B         as byte = $02,   
    PPS_CWG1A         as byte = $01,   
    PPS_LAT           as byte = $00,     
    PPS_NULL          as byte = PPS_LAT
#endif      // PPS_V6_2

//
// to assign an output function to a pin:
//  RxxPPS = pps_output_function
// macro example:
//  pps.assign_output(RA0PPS, PPS_TMR0)         // assigns TMR0 output to RA0
//  pps.assign_output(RB1PPS, PPS_EUSART1_TX)   // assigns usart TX1 output to RB1
// note: pps output functions are limited to specific ports
//  currently the macro does not check to see if the assignment is valid (nothing does)
//  refer to REGISTER 17-2 PIN Rxy OUTPUT SOURCE SELECTION REGISTER
// note: for the Q10 family this macro doesn't really do much at all
//
public macro assign_output(pps_port_sel_reg, pps_out_function)
    pps_port_sel_reg = pps_out_function
end macro

#elseif defined(PPS_V4)
//------------------------------------------------------------------------------
// assign_output(output_fn, rp_pin)
//
// assign pps output function to a pin
//  output_fn       pps output function (ie PPS_TX2)
//  rp_pin          PPS_OUT_RPx pin (ie PPS_OUT_RP0)
// example usage:
//  assign_output(PPS_NULL, PPS_OUT_RP0)
//  assign_output(PPS_TX2, PPS_OUT_RP23)
//------------------------------------------------------------------------------
public macro assign_output(output_fn, rp_pin)
    // for the PPS Lite module we need to translate output "pin numbers"
    // to register and upper/lower nibble selection. just do it brute force
    // since the macro will remove all the unused code

    // functions that use the lower nibble of the RPORxx reg
    if (rp_pin = PPS_OUT_RP0) then
        RPOR0_1 = (RPOR0_1 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP4) then
        RPOR4_5 = (RPOR4_5 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP8) then
        RPOR8_9 = (RPOR8_9 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP12) then
        RPOR12_13 = (RPOR12_13 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP16) then
        RPOR16_17 = (RPOR16_17 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP20) then
        RPOR20_21 = (RPOR20_21 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP24) then
        RPOR24_25 = (RPOR24_25 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP28) then
        RPOR28_29 = (RPOR28_29 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP32) then
        RPOR32_33 = (RPOR32_33 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP36) then
        RPOR36_37 = (RPOR36_37 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP40) then
        RPOR40_41 = (RPOR40_41 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP44) then
        RPOR44_45 = (RPOR44_45 and $F0) or output_fn

    elseif (rp_pin = PPS_OUT_RP2) then
        RPOR2_3 = (RPOR2_3 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP6) then
        RPOR6_7 = (RPOR6_7 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP10) then
        RPOR10_11 = (RPOR10_11 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP14) then
        RPOR14_15 = (RPOR14_15 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP18) then
        RPOR18_19 = (RPOR18_19 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP22) then
        RPOR22_23 = (RPOR22_23 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP26) then
        RPOR26_27 = (RPOR26_27 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP30) then
        RPOR30_31 = (RPOR30_31 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP34) then
        RPOR34_35 = (RPOR34_35 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP38) then
        RPOR38_39 = (RPOR38_39 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP42) then
        RPOR42_43 = (RPOR42_43 and $F0) or output_fn
    elseif (rp_pin = PPS_OUT_RP46) then
        RPOR46 = (RPOR46 and $F0) or output_fn
    endif

    // functions that use the upper nibble of the RPORxx reg
    if (rp_pin = PPS_OUT_RP1) then
        RPOR0_1 = (RPOR0_1 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP5) then
        RPOR4_5 = (RPOR4_5 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP9) then
        RPOR8_9 = (RPOR8_9 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP13) then
        RPOR12_13 = (RPOR12_13 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP17) then
        RPOR16_17 = (RPOR16_17 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP21) then
        RPOR20_21 = (RPOR20_21 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP25) then
        RPOR24_25 = (RPOR24_25 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP29) then
        RPOR28_29 = (RPOR28_29 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP33) then
        RPOR32_33 = (RPOR32_33 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP37) then
        RPOR36_37 = (RPOR36_37 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP41) then
        RPOR40_41 = (RPOR40_41 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP45) then
        RPOR44_45 = (RPOR44_45 and $0F) or (output_fn << 4)

    elseif (rp_pin = PPS_OUT_RP3) then
        RPOR2_3 = (RPOR2_3 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP7) then
        RPOR6_7 = (RPOR6_7 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP11) then
        RPOR10_11 = (RPOR10_11 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP15) then
        RPOR14_15 = (RPOR14_15 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP19) then
        RPOR18_19 = (RPOR18_19 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP23) then
        RPOR22_23 = (RPOR22_23 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP27) then
        RPOR26_27 = (RPOR26_27 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP31) then
        RPOR30_31 = (RPOR30_31 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP35) then
        RPOR34_35 = (RPOR34_35 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP39) then
        RPOR38_39 = (RPOR38_39 and $0F) or (output_fn << 4)
    elseif (rp_pin = PPS_OUT_RP43) then
        RPOR42_43 = (RPOR42_43 and $0F) or (output_fn << 4)
    endif
end macro

#else
// regular V1-V3 PPS module
public macro assign_output(output_fn, rp_pin)
    rp_pin = output_fn
end macro
#endif      // (PPS_V4)

//
//------------------------------------------------------------------------------
// PPS helper functions
//------------------------------------------------------------------------------
//

//
// unlock/lock pps configuration
// Changes to the pps control registers must be unlocked in hardware prior to
// accessing them, or they will not change. This should be done with interrupts
// disabled, so unlock() records the state of the global IE flag for later use
// by the lock() routine
//
// K40 family
#if defined(PPS_V5_1) or defined(PPS_V5_1B) or defined(PPS_V5_2) or defined(PPS_V5_3)
  dim PPSLOCKED_BIT as PPSLOCK.bits(0)      // PPSLOCKED bit
  dim PPSLOCK_REG as PPSLOCK                // alias name for the PPS lock control reg
// Q10 family
#elseif defined(PPS_V6_1) or defined(PPS_V6_2)
  dim PPSLOCKED_BIT as PPSLOCK.bits(0)      // PPSLOCKED bit
  dim PPSLOCK_REG as PPSLOCK                // alias name for the PPS lock control reg
// J94/J99 family
#elseif defined (PPS_V4)
  dim PPSLOCKED_BIT as OSCCON2.bits(6)      // IOLOCK bit
  dim PPSLOCK_REG as WREG                   // alias name for the (dummy) PPS lock control reg
// all others
#else
  dim PPSLOCKED_BIT as PPSCON.bits(0)       // IOLOCK bit
  dim PPSLOCK_REG as EECON2                 // alias name for the PPS lock control reg
#endif

#if (PPS_DISABLE_INT)
  dim t_intcon as byte        // copy of INTCON register
  const GIE = 7               // GIEH bit number
#endif

//
//------------------------------------------------------------------------------
// unlock PPS configuration changes
//------------------------------------------------------------------------------
//
public sub unlock()
  #if (PPS_DISABLE_INT)
    // save current state of GIE intr bit and disable interrupts
    t_intcon = INTCON
    INTCON.bits(GIE) = 0
  #endif

    // send sequence to unlock the PPS configuration
    PPSLOCK_REG = $55
    PPSLOCK_REG = $AA
    PPSLOCKED_BIT = 0
end sub

//
//------------------------------------------------------------------------------
// lock PPS configuration
//------------------------------------------------------------------------------
//
public sub lock()
    // send sequence to lock the PPS configuration
    PPSLOCK_REG = $55
    PPSLOCK_REG = $AA
    PPSLOCKED_BIT = 1

  #if (PPS_DISABLE_INT)
    // restore the interrupt enable state previously saved by unlock()
    if (t_intcon.bits(GIE) = 1) then
        INTCON.bits(GIE) = 1
    endif
  #endif
end sub

//
//------------------------------------------------------------------------------
// assign_defaults()
// remap all RPxx pins to the default unmapped state
//------------------------------------------------------------------------------
//
// RPINR and RPOR register ranges
#if defined (PPS_V1) or defined (PPS_V1_1) or defined(PPS_V3) or defined(PPS_V3B)
  dim FIRST_RPINR   as RPINR1
  dim LAST_RPINR    as RPINR24
  dim FIRST_RPOR    as RPOR0
  dim LAST_RPOR     as RPOR18
#elseif defined (PPS_V2) or defined (PPS_V2_1) or defined (PPS_V3_1) or defined (PPS_V3B_1)
  dim FIRST_RPINR   as RPINR1
  dim LAST_RPINR    as RPINR24
  dim FIRST_RPOR    as RPOR0
  dim LAST_RPOR     as RPOR24
#elseif defined (PPS_V4)    
  dim FIRST_RPINR   as RPINR0_1
  dim LAST_RPINR    as RPINR52_53
  dim FIRST_RPOR    as RPOR0_1
  dim LAST_RPOR     as RPOR46
#endif

#if defined(PPS_V5_1) or defined(PPS_V5_1B) or defined(PPS_V5_2) or defined(PPS_V5_3) or defined(PPS_V6_1) or defined(PPS_V6_2)
public sub assign_defaults()
    // the K40 and Q10 family do not have a common "default" register setting
    // it's best to do it individually, so this is just a dummy routine
end sub
#else
public sub assign_defaults()
    // default setting depends on PPS type... V4 has two settings per reg
  #if defined (PPS_V4)
    const RPIN_UNUSED  = PPS_IN_UNUSED or (PPS_IN_UNUSED << 4)
    const RPOUT_UNUSED = PPS_OUT_UNUSED or (PPS_OUT_UNUSED << 4)
  #else
    const RPIN_UNUSED  = PPS_IN_UNUSED
    const RPOUT_UNUSED = PPS_OUT_UNUSED
  #endif

    dim wtmp as word,               // need a word to compute address differences,
        count as wtmp.bytes(0)      // but only need a byte count value result

    // the algorithm used here relies on a few assumptions:
    //  - registers in the RPINR and RPOR sections are contiguous
    //  - addresses in a section increase from first to last (last > first)
    //  - writing to an unimplemented register causes no harm
    // if any of these assumptions aren't true then the routine will
    // have unintended consequences

    // unlock pps for config changes
    unlock()

    // default inputs - tied to PPS_VSS
    // compute the count of RPINRxx regs to set
    wtmp = addressof(LAST_RPINR)
    wtmp = wtmp - addressof(FIRST_RPINR)
    count = byte(wtmp) + 1
    // init starting addr and loop setting RPINRxx
    FSR0 = addressof(FIRST_RPINR)
    repeat
        POSTINC0 = RPIN_UNUSED
        count = count - 1
    until (count = 0)

    // default outputs - set to default port pin function
    // compute the count of RPORxx regs to set
    wtmp = addressof(LAST_RPOR)
    wtmp = wtmp - addressof(FIRST_RPOR)
    count = byte(wtmp) + 1
    // init starting addr and loop setting RPORxx
    FSR0 = addressof(FIRST_RPOR)
    repeat
        POSTINC0 = RPOUT_UNUSED
        count = count - 1
    until (count = 0)

    // relock pps
    lock()
end sub
#endif

//
//------------------------------------------------------------------------------
// module initialization
//------------------------------------------------------------------------------
//

end module
Retrieved from https://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.PeripheralPinSelect
Page last modified on October 31, 2019, at 06:48 PM