PeripheralPinSelect

Download PeripheralPinSelect v1.5
pps_v15.zip

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