Proton BASIC Compiler - MCP23S09 Port expander for P24


  • PicŪ Basic


  • MCP23S09 Port expander to upgrade Proton24 similar to 40 pin DIP PIC's

    The following Proton 24 code utilizes a Microchip MCP23S09 port expander.
    This is extremely useful as 40 pin DIP packages aren't available in the 16 bit series PIC's.
    The MCP23S09 has an SPI interface as opposed to the MCP23009 which has an I2C interface.

    This example code includes 3 versions of SPI:
    1. SHOut and SHIn. Pin selection is flexible. Easiest of the 3.
    2. LES's SPI software macro: SPI_Read and SPI_Write. Pin selection is flexible. Requires "SPI_24.inc".
    3. Hardware SPI somewhat more complicated. Fixed pins.

    This code covers the basics of:
    1. Initialize expansion port SPI.
    2. Set expansion port inputs and outputs.
    3. Set expansion port hi's and low's.
    4. Read expansion port pins.

    More can be added such as interrupt on port change.

    Norm

    Code:
      Device = 24EP128GP202
    
      Declare Xtal = 140.03
      ' Setup the Oscillator to operate the device at 140.03MHz
      ' Fosc = (7.37 * 76) / (2 * 2) = 140.03MHz
      PLL_Setup(76, 2, 2, $0300)
    
    '  Include "SPI_24.inc"      ' Load the PIC24 SPI procedures into the program
    
      Clear
      Declare Hserial_Baud = 115200           ' UART1 baud rate
      Declare Hrsout1_Pin = PORTB.6           ' Select which pin is to be used for TX with USART1
    '  Declare Hrsin1_Pin = PORTB.2            ' Select which pin is to be used for RX with USART1
      PPS_Output(cOut_Pin_RP38, cOut_Fn_U1TX)
    
      'FOR cIn_xxx SEE Device .DEF FILE IN C:\Program Files (x86)\ProtonIDE\PDS\Includes\Defs
      'RPxx 24EP128GP202
    '  cOut_Fn_NULL
    '  cOut_Fn_CxOUT
    '  cOut_Fn_UxTX
    '  cOut_Fn_UxRTS
    '  cOut_Fn_SDOx
    '  cOut_Fn_SCKx
    '  cOut_Fn_SSx
    '  cOut_Fn_OCx
    '  cOut_Fn_CTMU
    '  etc.....
    
      VARS:
      '1K RESISTORS OK AS DATA LINKS BETWEEN PIC AND MCP23S09
      Symbol cPIC_SPI_CS = PORTA.3
      Symbol cPIC_SPI_CLK = PORTB.4
      Symbol cPIC_SPI_OUT = PORTA.4
    
    '  Symbol cPIC_SPI_IN = PORTA.2
      Symbol cPIC_SPI_IN = PORTB.2
    
      Dim yCNT As Byte
      Dim yEXP_READ As Byte
    
      '******************** 24EP128GP202 OK
    '  INTERRUPT_REGISTER:
    '  INTCON1 = %1000000000000000 '%1xxxxxxxxxxxxxxx Interrupt nesting is disabled
    '
    '  INTCON2 = %1000000000000100 '%1xxxxxxxxxxxxxxx Interrupts and associated IE bits are enabled
    '                              '%xxxxxxxxxxxxx1xx Interrupt 2 on negative edge  SCREEN INT
    '                              '%xxxxxxxxxxxxxx0x Interrupt 1 on positive edge  LINE INT
    '                              '%xxxxxxxxxxxxxxx0 Interrupt 0 on positive edge  PIXEL INT
    '  INTCON3 = %0000000000000000
    '  INTCON4 = %0000000000000000
    '
    '  IFS0bits_INT0IF = 0                  ' Clear interrupt flag  INT0 PIXEL
    '  IPC0bits_INT0IP0 = %0000000000000101 ' Set priority %xxxxxxxxxxxxx101 = 5
    '  IEC0bits_INT0IE = 1                  ' Enable the interrupt
    '
    '  IFS1bits_INT1IF = 0                  ' Clear interrupt flag  INT1 LINE
    '  IPC5bits_INT1IP0 = %0000000000000000 ' Set priority %xxxxxxxxxxxxx011 = 3
    '  IEC1bits_INT1IE = 1                  ' Enable the interrupt
    '
    '  IFS1bits_INT2IF = 0                  ' Clear interrupt flag  INT2 SCREEN
    '  IPC7bits_INT2IP0 = %0000000000010000 ' Set priority %xxxxxxxxx001xxxx = 1
    '  IEC1bits_INT2IE = 1                  ' Enable the interrupt
    '
    '  'FOR cIn_xxx SEE Device .DEF FILE IN C:\Program Files (x86)\ProtonIDE\PDS\Includes\Defs
    '  PPS_Input(cIn_Pin_RP38, cIn_Fn_INT1) 'B.6 = RP38
    '  PPS_Input(cIn_Pin_RP37, cIn_Fn_INT2) 'B.5 = RP37
    '  'INT0 FIXED PIN
      '********************
    
      '********************
      TRISA = %0000000000000000
      TRISB = %0000000000000100
    
      GoTo START
    
      '********************
    '  Isr- INT0Interrupt
    '    HSerOut["INT0",13]
    '    IFS0bits_INT0IF = 0
    '  EndIsr-
    '
    '  Isr- INT1Interrupt
    '    HSerOut["INT1",13]
    '    IFS1bits_INT1IF = 0
    '  EndIsr-
    '
    '  Isr- INT2Interrupt
    '    HSerOut["INT2",13]
    '    IFS1bits_INT2IF = 0
    '  EndIsr-
      '*********************
    
      '*********************
      Proc procSET_EXP_PORT_IN_OUTS(yEXP_IO As Byte)
        Low cPIC_SPI_CS
    
        'SHOUT OK
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[%01000000\8] '%x1xxxxx0 WRITE CMD
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[%00000000\8] 'PIC SENDS EXPANDER REGISTER IODIR ADDRESS
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[yEXP_IO\8] 'PIC SENDS EXPANDER PORT IN OUT SETTING
    
        'LESs SPI MACRO OK
    '    SPI2_Write(%01000000) '%x1xxxxx0 WRITE CMD
    '    SPI2_Write(%00000000) 'PIC SENDS EXPANDER REGISTER IODIR ADDRESS
    '    SPI2_Write(yEXP_IO) 'PIC SENDS EXPANDER PORT IN OUT SETTING
    
        'REGISTERS DIRECT OK
        SPI2BUF = %01000000 '%x1xxxxx0 WRITE CMD
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = %00000000 'PIC SENDS EXPANDER REGISTER IODIR ADDRESS
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = yEXP_IO 'PIC SENDS EXPANDER PORT IN OUT SETTING
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        High cPIC_SPI_CS
        HSerOut["procSET_EXP_PORT_IN_OUTS %",Bin8 yEXP_IO,13]
      EndProc
      '*********************
    
      '*********************
      Proc procSET_EXP_PORT_HI_LOWS(yEXP_HI_LOW As Byte)
        Low cPIC_SPI_CS
    
        'SHOUT OK
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[%01000000\8]   '%x1xxxxx0 WRITE CMD
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[%00001001\8]   'PIC SENDS EXPANDER REGISTER GPIO ADDRESS
    '    SHOut cPIC_SPI_OUT, cPIC_SPI_CLK, MsbFirst_L,[yEXP_HI_LOW\8] 'PIC SENDS PORT PINS HI OR LOW SETTINGS
    
       'LESs SPI MACRO OK
    '    SPI2_Write(%01000000) '%x1xxxxx0 WRITE CMD
    '    SPI2_Write(%00001001) 'PIC SENDS EXPANDER REGISTER GPIO ADDRESS
    '    SPI2_Write(yEXP_HI_LOW) 'PIC SENDS PORT PINS HI OR LOW SETTINGS
    
        'REGISTERS DIRECT OK
        SPI2BUF = %01000000 '%x1xxxxx0 WRITE CMD
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = %00001001 'PIC SENDS EXPANDER REGISTER GPIO ADDRESS
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = yEXP_HI_LOW 'PIC SENDS PORT PINS HI OR LOW SETTINGS
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        High cPIC_SPI_CS
        HSerOut["procSET_EXP_PORT_HI_LOWS %",Bin8 yEXP_HI_LOW,13]
      EndProc
      '*********************
    
      '*********************
      Proc procREAD_EXP_PORT() 'MCP23S09 PORT REQUIRES PULLUPS TO READ AS HI ON OUT HI
        yEXP_READ = 0
        Low cPIC_SPI_CS
    
        'LESs SPI INC OK
    '    Low cPIC_SPI_CS
    '    SPI2_Write(%01000001) '%x1xxxxx1 READ CMD
    '    SPI2_Write(%00001001) 'PIC SENDS EXPANDER REGISTER GPIO ADDRESS
    '    yEXP_READ = SPI2_Read() 'PIC READS PORT PINS HI OR LOW SETTINGS
    '    High cPIC_SPI_CS
    '    HSerOut["READ EXP %",Bin8 yEXP_READ,13]
    
        'REGISTERS DIRECT OK
        SPI2BUF = %01000001 '%x1xxxxx1 READ CMD
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = %00001001 'PIC SENDS EXPANDER REGISTER GPIO ADDRESS
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF
    
        SPI2BUF = %00000000
        While SPI2STAT.0 = 0 : Wend 'WHILE TX/RX COMPLETE
        yEXP_READ = SPI2BUF 'PIC READS PORT PINS HI OR LOW SETTINGS
    
        High cPIC_SPI_CS
        HSerOut["READ EXP %",Bin8 yEXP_READ,13]
    
      EndProc
      '*********************
    
      '*********************
    ' Initialise the SPI interface
    ' Input     : None
    ' Output    : None
    ' Notes     : Also configures PPS for the SPI1 peripheral
    '           : Final SPI speed (in KHz) = ((fOSC / 2) / 1000) / (Secondary Prescale * Primary Prescale)
    '
      Proc SPI2_Init()
    '   Setup the SPI as master Mode 0:0
    '   When operating at 32MHz, the prescaler values below will operate the SPI clock at 8MHz:
    '   ((32000000 / 2) / 1000) / (2 * 1) = 8000KHz
    '   ((140030000 / 2) / 1000) / (2 * 1) = 35.007 MHz 'RUNS BUT FAR ABOVE SPEC OF 10 MHz
    '   ((140030000 / 2) / 1000) / (2 * 4) =  8.751 MHz 'OK
        'MCP23S09 SPI RATED AT 10 MHz
        '24EP128GP202 SPI2 SPI RATED AT 9 MHz FULL DUPLEX,  SPI2 IS SLOWER THAN SPI1 OF 10 MHz FULL DUPLEX
    
        'LESs SPI INC OK
    '    SPI2_Open(cSPI_MODE0 & cSEC_PRE_2_1 & cPRI_PRE_1_1, cSPI_ON & cSPI_IDLE_ON & cSPI_RX_OVFLOW_CLR)
    
        'REGISTERS DIRECT OK
        SPI2CON2 = %0000000000000000
        SPI2CON1 = %0000001110111010 'SEC PRESCALE 2:1   PRI PRESCALE 4:1
        SPI2STAT = %1000000000011100 'SET LAST FOR SOME REASON
        '3: Do not set both primary and secondary prescalers to the value of 1:1
    
        'SPI2
        PPS_Output(cOut_Pin_RP36, cOut_Fn_SCK2)    'SPI
        PPS_Output(cOut_Pin_RP20, cOut_Fn_SDO2)    'SPI
        PPS_Input(cIn_Pin_RPI34, cIn_Fn_SDI2)      'SPI
    
        'Setup the PPS pins for SPI1   'SPI1 NOT RECONFIGUABLE PINS
    '    PPS_Output(cOut_Pin_RP39, cOut_Fn_SCK1)             ' To SPI peripheral's CLK pin
    '    PPS_Output(cOut_Pin_RP40, cOut_Fn_SDO1)             ' To SPI peripheral's SDO pin
    '    PPS_Input(cIn_Pin_RP41, cIn_Fn_SDI1)                ' From SPI peripheral's SDI pin
        High cPIC_SPI_CLK                                    ' Make the SCK pin output high
        High cPIC_SPI_OUT                                    ' Make the SDO pin output high
        Input cPIC_SPI_IN                                    ' Make the SDI pin an input
        High cPIC_SPI_CS                                     ' Make the CS pin output high
        HSerOut["SPI_Init",13]
      EndProc
      '*********************
    
      '*********************
      '*********************
      START:
    
      DelayMS 3000
      HSerOut[13,"START 140 MHz",13]
      HSerOut["U1MODE = 0b",Bin16 U1MODE,13]
      HSerOut["U1STA = 0b",Bin16 U1STA,13]
      HSerOut["U1TXREG = 0b",Bin16 U1TXREG,13]
      HSerOut["U1RXREG = 0b",Bin16 U1RXREG,13]
      HSerOut["U1BRG = 0b",Bin16 U1BRG,13]
    
      SPI2_Init() 'Configure the SPI2 interface
    
      procSET_EXP_PORT_IN_OUTS(%00000000) 'ALL OUTPUTS
    
      While
        HSerOut[Dec yCNT,13]
        procSET_EXP_PORT_HI_LOWS(%00000000) 'ALL HIGH
        procREAD_EXP_PORT()
        DelayMS 1000
        procSET_EXP_PORT_HI_LOWS(%11111111) 'ALL LOW
        procREAD_EXP_PORT()
        DelayMS 1000
        Inc yCNT
      Wend
    
    ' Configure for internal 7.37MHz oscillator with PLL
    ' OSC pins are general purpose I/O
      Config FICD = ICS_PGD1, JTAGEN_OFF
      Config FPOR = ALTI2C1_OFF, ALTI2C2_OFF, WDTWIN_WIN75
      Config FWDT = FWDTEN_OFF, PLLKEN_ON, WDTPOST_PS512, WDTPRE_PR128, WINDIS_OFF
      Config FOSC = FCKSM_CSECME, IOL1WAY_OFF, OSCIOFNC_ON, POSCMD_NONE
      Config FOSCSEL = FNOSC_FRCPLL, IESO_OFF
      Config FGS = GCP_OFF, GWRP_OFF
    
      End