News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

SHIn and SHOut

Started by streborc, Mar 07, 2026, 10:38 PM

Previous topic - Next topic

streborc

Is there any reason why SHIn and SHOut cannot occupy the same data pin such that the instructions below would not work?  My understanding is that the commands set the data direction of the port used.

SHIn Dat_Pin, Clk_Pin, Mode, [Var_In]

SHOut Dat_Pin, Clk_Pin, Mode, [Var_Out]

top204

#1
Technically, the MISO and MOSI pins can be shared. However, it must be remembered that while data is being clocked into a slave unit, the slave unit is also outputting data, so it will meet a pin that is output low, then output high many times over, and this may cause problems. It all depends on the slave device.

If sharing the MISO and MOSI pins, it would be wise to place series resistors in them, so current overloads should not harm the slave chip. Or Schottky diodes, so one pin does not see the output of another.

streborc

Les,

Thanks for your reply.  I think I need to provide a bit more information about my question and issue.

As you are aware I'm sure, in the world of serial peripheral devices, there are a handful of non-conformists that are almost, but not quite I2C.  I guess that in order to avoid paying licensing fees, the designers of these device deviate just enough to make their lives less expensive and our lives more complicated.  One example that you and others are likely familiar with is the TM1637 that's used in 4-digit/7-segment LED displays.  It's quite I2C except for its lacking of an I2C bus address, so interfacing it usually becomes a bit-bashing event.

I am currently working with an Everset ES100 timecode receiver.  This device receives broadcasts from the WWVB transmitter in the US\NA, which is similar to the UK's NPL/MSF transmitter.  The ES100 is another "almost I2C" interface that has a 2-wire SDA and SCL interface with 8-bit address and data, but has some goofy preamble/postamble chatter, that has to be coded for.  It's just different enough to rule out use of Positron's I2C command set.  And even if it was I2C compatible, the ES100's manufacturer recommends isolating it on its own bus so that its RF functions are not adversely affected by digital noise with other serial bus shared devices.

I wrote code in PBP a couple years ago that has been working effectively in receiving broadcasts and keeping my clock synchronized with WWVB's atomic clock.  My PBP code talks to the ES100 using the SHIFTIN/SHIFTOUT commands and uses some short bit-bashed preamble/postamble segments.  I'm now transposing the PBP code to Positron, and everything (the LCD uses I2COut and the RTC uses BusIn/BusOut) is working just fine, except for the ES100 interface.  I've transposed PBP's SHIFTIN/SHIFTOUT instructions to Positron's SHIn and SHOut instructions, but the SHIn variable always comes up empty.

The SHOut commands work exactly as required to configure a couple ES100 registers, set the receiver into reception mode, and then read the time/date data from the ES100 registers, except the ES100 register output data that is clearly present on the SDA line is never captured by the SHIn instruction.  It's as if the SDA port pin has a one-way valve on it that allows address and data to be issued to the ES100, but the byte that is returned is blocked.

I'm using a single hardware platform for testing.  I can install the PBP code and the clock works correctly.  When I install the Positron code, it never reads the ES100 registers.  I've tried every gymnastic I can think of with timing manipulations, including "Declare Shift_DelayUs", every mode and every port pin manipulation that's available (TRIS, WPU, ODCON, etc.), but nothing has worked.  In this regard, and perhaps a clue, I did have to ODCON the SDA pin in Positron to get SHOut to work, whereas this is not required in the PBP version.  I've compared the SCL/SDA waveforms on my oscilloscope, and there is no difference between the PBP and Positron bus activity.  The register byte that the ES100 outputs is present in both cases, but SHIFTIN reads it and SHIn does not.

At this point I'm completely perplexed. I asked my original question thinking that perhaps there is something is Positron's SHIn instruction that precludes it from accessing the same SDA pin assignment used by SHOut, inasmuch as the intended use of these instructions is with SPI's separate MISO/MOSI data pins.

I have an extra uC port pin available, so I'm going to use some resistors to divide the SHOut pin from the SHIn pin at the ES100's SDA pin and see if that remedies the problem.  I'll let your know the results.

trastikata

Hello streborc,

out of interest what is the uC device you are using.

Best regards.

streborc

I'm using a PIC16F18346.

Fanie

#5
Quote from: streborc on Mar 07, 2026, 10:38 PMIs there any reason why SHIn and SHOut cannot occupy the same data pin such that the instructions below would not work?  My understanding is that the commands set the data direction of the port used.

SHIn Dat_Pin, Clk_Pin, Mode, [Var_In]

SHOut Dat_Pin, Clk_Pin, Mode, [Var_Out]

You will have to set conditions so the pic and the peripheral knows when to send and when to read.
(Assuming you have a peripheral device  ;D )

top204

The SHin command makes the relevant data pin an Input, and the Clock pin an Output, and the SHout command makes the data pin an Output and the Clock pin an Output.

A better understanding of a software based (bit-bashed) SPI interface can be had by creating some procedures to perform read and write. It also means they can be changed to suit a particular requirement. Below is a code listing of a demo to write and read to /from an SPI EEPROM, using a software SPI interface, so that it can be seen working:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Write and read, to/from an SPI EEPROMs, such as the 25LCxxx range etc, using software based procedures.
'
' Write to the first 16 locations of an SPI EEPROM
' Read first 16 locations back and send to a serial terminal
' Note. For SPI EEPROMs with a 16-bit address
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
'
    Device = 16F18856                               ' Tell the compiler what device to compile for
    Declare Xtal = 32                               ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Auto_Heap_Strings = On                  ' Tell the compiler to create Strings above standard variables, so assembler code is more efficient
    Declare Auto_Heap_Arrays = On                   ' Tell the compiler to create Arrays above standard variables, so assembler code is more efficient
    Declare Auto_Variable_Bank_Cross = On           ' Tell the compiler to create any multi-byte variables in the same RAM bank. For more efficiency
    Declare Create_Coff = True                      ' Create a COF file for debugging in a simulator
'
' Setup UART1
'
    Declare Hserial1_Baud = 9600                    ' Set UART1 Baud rate
    Declare HSerout1_Pin = PORTC.6                  ' Set UART1 TX pin
'
' Define the pins for the SPI interface
'
$define SPI_CLK_Pin  PORTC.3                        ' Connects to the slave device's CLK pin
$define SPI_MISO_Pin PORTC.4                        ' Connects to the slave device's Data Out pin
$define SPI_MOSI_Pin PORTC.5                        ' Connects to the slave device's Data In pin
$define SPI_CS_Pin   PORTC.0                        ' Connects to the slave device's CS pin
'
' Create global variables and constants here
'
    Dim wAddress As Word                            ' Holds the EEPROM Address
    Dim bData    As Byte                            ' Holds the data for transfer to/from the EEPROM

'------------------------------------------------------------------------
' The main program loop starts here.
' Write and read to/from an SPI EEPROM, and display the results on a serial terminal
'
Main:
    Setup()                                         ' Setup the program and any peripherals
'
' Write to the SPI EEPROM
'
    HRSOut1Ln "Writing"
    For wAddress = 0 To 15                          ' Loop 16 times
        bData = Random                              ' bData is data for EEPROM
        HRSOut1Ln "Address ", Dec2 wAddress,_       ' \ Transmit to a serial terminal
                  " will contain ", Dec3 bData      ' /
        EE_Write(wAddress, bData)                   ' Write to EEPROM
        DelayMS 5                                   ' Delay 5ms after each write
    Next
'
' Read from the SPI EEPROM
'
    HRSOut1Ln "\rReading"
    For wAddress = 0 To 15                          ' Loop 16 times
        bData = EE_Read(wAddress)                   ' Read from EEPROM
        HRSOutLn "Address ", Dec2 wAddress,_        ' \ Transmit to a serial terminal
                 " holds ", Dec3 bData              ' /
    Next

'-----------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinHigh SPI_CS_Pin                              ' Make the SPI CS pin an output high (SPI disabled)
    PinLow SPI_CLK_Pin                              ' Make the SPI CLK pin an output low
EndProc

'------------------------------------------------------------------------
' Read data from an SPI EEPROM
' Input     : pAddress holds the 16-bit address to read
' Output    : Returns the byte read from the SPI EEPROM
' Notes     : None
'
Proc EE_Read(pAddress As Word), Byte
    PinClear SPI_CS_Pin                             ' Enable the SPI interface
    SPI_Write8($03)                                 ' Send the read command to the EEPROM
    SPI_Write8(pAddress.Byte1)                      ' \ Send the 16-bit address
    SPI_Write8(pAddress.Byte0)                      ' /
    Result = SPI_Read8()                            ' Read the data
    PinSet SPI_CS_Pin                               ' Disable the SPI interface
EndProc

'------------------------------------------------------------------------
' Write data to an SPI EEPROM
' Input     : pAddress holds the 16-nit address to write
'           : pData holds the byte to write to the SPI EEPROM
' Output    : None
' Notes     : None
'
Proc EE_Write(pAddress As Word, pData As Byte)
    PinClear SPI_CS_Pin                             ' Enable the SPI interface
    SPI_Write8($06)                                 ' Send the write enable command to the EEPROM
    PinSet SPI_CS_Pin                               ' Disable the SPI interface to execute command

    PinClear SPI_CS_Pin                             ' Enable the SPI interface
    SPI_Write8($02)                                 ' Send the write command to the EEPROM
    SPI_Write8(pAddress.Byte1)                      ' \ Send the 16-bit address
    SPI_Write8(pAddress.Byte0)                      ' /
    SPI_Write8(pData)                               ' Send the data byte
    PinSet SPI_CS_Pin                               ' Disable the SPI interface
EndProc

'------------------------------------------------------------------------
' Write 8-bits to an SPI interface
' Input     : pData holds the byte to write to the SPI interface
' Output    : None
' Notes     : SPI Mode 0. MSB
'
Proc SPI_Write8(pData As Byte)
Global Dim SPI_bBits As Byte Shared                 ' Holds the loop counter for the 8-bits

    PinOutput SPI_MOSI_Pin                          ' Make the MOSI pin an output
    For SPI_bBits = 7 DownTo 0                      ' Create an 8-bit SPI loop
        Rol pData                                   ' Rotate the next bit MSB, into the Carry flag
        PinClear SPI_MOSI_Pin                       ' Default to a clear SPI_MOSI_Pin low
        If STATUSbits_C = 1 Then                    ' Is the Carry flag set?
            PinSet SPI_MOSI_Pin                     ' Yes. So set the SPI_MOSI_Pin high
        EndIf
        PinSet SPI_CLK_Pin                          ' Set the CLK pin high
        DelayUS 1                                   ' A small delay
        PinClear SPI_CLK_Pin                        ' Pull the CLK pin low
        DelayUS 1                                   ' A small delay
    Next
EndProc

'------------------------------------------------------------------------
' Read 8-bits from an SPI interface
' Input     : None
' Output    : Returns the 8-bits read from the SPI interface
' Notes     : SPI Mode 0. MSB
'
Proc SPI_Read8(), Byte
Global Dim SPI_bBits As Byte Shared                 ' Holds the loop counter for the 8-bits

    PinInput SPI_MISO_Pin                           ' Make the MISO pin an input
    For SPI_bBits = 7 DownTo 0                      ' Create an 8-bit SPI loop
        Result = Result << 1                        ' Shift the next bit into MSB
        PinSet SPI_CLK_Pin                          ' Set the SCK pin high
        DelayUS 1                                   ' A small delay
        Result.0 = SPI_MISO_Pin                     ' Capture the current bit from the MISO Pin
        PinClear SPI_CLK_Pin                        ' Pull the CLK pin low
        DelayUS 1                                   ' A small delay
    Next
EndProc

'------------------------------------------------------------------------
' Setup the config fuses to operate the PIC16F18856 device with an external crystal.
'
    Config1 FEXTOSC_HS,_                            ' External Oscillator enabled
            CLKOUTEN_ON,_                           ' CLKOUT function enabled
            CSWEN_ON,_                              ' Writing to NOSC and NDIV is allowed
            FCMEN_OFF                               ' Fail-Safe Clock Monitor timer disabled

    Config2 MCLRE_ON,_                              ' MCLR pin is Master Clear function
            PWRTE_ON,_                              ' Power-up Timer enabled
            LPBOREN_OFF,_                           ' Low-Power BOR disabled
            BOREN_ON,_                              ' Brown-out Reset Enabled. SBOREN bit is ignored
            BORV_LO,_                               ' Brown-out Reset Voltage set to 2.45V
            ZCD_OFF,_                               ' Zero-cross detect circuit is disabled at POR
            PPS1WAY_OFF,_                           ' The PPSLOCK bit can be set and cleared repeatedly by software
            STVREN_ON,_                             ' Stack Overflow or Underflow will cause a reset
            DEBUG_OFF                               ' Background Debugger disabled

    Config3 WDTCPS_WDTCPS_31,_                      ' WDT Divider ratio 1:65536. Software control of WDTPS
            WDTE_OFF,_                              ' WDT Disabled. SWDTEN is ignored
            WDTCWS_WDTCWS_7,_                       ' WDT window always open (100%). Software control. Keyed access not required
            WDTCCS_SC                               ' WDT input clock is Software Control

    Config4 WRT_OFF,_                               ' User NVM Write protection off
            SCANE_NOT_AVAILABLE,_                   ' Scanner module is mot available
            LVP_OFF                                 ' High Voltage on MCLR/Vpp must be used for programming

    Config5 CP_OFF,_                                ' Program Memory code protection disabled
            CPD_OFF                                 ' Data EEPROM code protection disabled

It is written for an enhanced 14-bit core device, but the procedures are using nothing special, so they can be used on most devices.

It shows exactly how the interface is operating, and the SPI_Write8 and SPI_Read8 procedures even set the pins for output/input where relevant, before the loop that clocks the bits out or in, so a single pin for MOSI and MISO can be tried. It also allows the delays between clock pulses to be easily changed, in case the compiler is creating assembler code that makes the interface too fast for the slave device.

In a simulator, it looks like:

SPI_Write_Read.jpg

A zip file containing the source codes and proteus project file is attached to this post below.

top204

If a more flexible mechanism is required for choosing the Clock and Data lines for the SPI read and write procedures, the compiler's Pin variables can be used as parameters. However, they are not as efficient as a direct Port . Pin directive, but they give more flexability.

The code listing below, is the same as above, but uses the Pin variables in the SPI_Read8 and SPI_Write8 procedures, so they can use different pins within the same code listing:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Write and read, to/from an SPI EEPROM, such as the 25LCxxx range, using software based mechanisms.
' The SPI Read and Write procedures use the Pin directive for their Clock and Data pin selections.
'
' Write to the first 16 locations of an SPI EEPROM.
' Read first 16 locations back and send to a serial terminal.
' Note. For SPI EEPROMs with a 16-bit address.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
'
    Device = 16F18856                               ' Tell the compiler what device to compile for
    Declare Xtal = 32                               ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Auto_Heap_Strings = On                  ' Tell the compiler to create Strings above standard variables, so assembler code is more efficient
    Declare Auto_Heap_Arrays = On                   ' Tell the compiler to create Arrays above standard variables, so assembler code is more efficient
    Declare Auto_Variable_Bank_Cross = On           ' Tell the compiler to create any multi-byte variables in the same RAM bank. For more efficiency
    Declare Create_Coff = True                      ' Create a COF file for debugging in a simulator
'
' Setup UART1
'
    Declare Hserial1_Baud = 9600                    ' Set UART1 Baud rate
    Declare HSerout1_Pin = PORTC.6                  ' Set UART1 TX pin
'
' Define the pins for the SPI interface to the EEPROM
'
$define EE_CLK_Pin  PORTC.3                         ' Connects to the slave EEPROM's CLK pin
$define EE_MISO_Pin PORTC.4                         ' Connects to the slave EEPROM's Data Out pin
$define EE_MOSI_Pin PORTC.5                         ' Connects to the slave EEPROM's Data In pin
$define EE_CS_Pin   PORTC.0                         ' Connects to the slave EEPROM's CS pin
'
' Create global variables and constants here
'
    Dim SPI_bMOSI_MISO_Pin As Pin Access            ' Used as a shared Data parameter
    Dim SPI_bCLK_Pin       As Pin Access            ' Used as a shared CLK parameter
   
    Dim wAddress As Word                            ' Holds the EEPROM Address
    Dim bData    As Byte                            ' Holds the data for transfer to/from the EEPROM

'------------------------------------------------------------------------
' The main program loop starts here.
' Write and read to/from an SPI EEPROM, and display the results on a serial terminal
'
Main:
    Setup()                                         ' Setup the program and any peripherals
'
' Write to the SPI EEPROM
'
    HRSOut1Ln "Writing"
    For wAddress = 0 To 15                          ' Loop 16 times
        bData = Random                              ' bData is data for EEPROM
        HRSOut1Ln "Address ", Dec2 wAddress,_       ' \ Transmit to a serial terminal
                  " will contain ", Dec3 bData      ' /
        EE_Write(wAddress, bData)                   ' Write to EEPROM
        DelayMS 5                                   ' Delay 5ms after each write
    Next
'
' Read from the SPI EEPROM
'
    HRSOut1Ln "\rReading"
    For wAddress = 0 To 15                          ' Loop 16 times
        bData = EE_Read(wAddress)                   ' Read from EEPROM
        HRSOutLn "Address ", Dec2 wAddress,_        ' \ Transmit to a serial terminal
                 " holds ", Dec3 bData              ' /
    Next

'-----------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinHigh EE_CS_Pin                               ' Make the EEPROM's CS pin an output high (SPI disabled)
EndProc

'------------------------------------------------------------------------
' Read data from an SPI EEPROM
' Input     : pAddress holds the 16-bit address to read
' Output    : Returns the byte read from the SPI EEPROM
' Notes     : None
'
Proc EE_Read(pAddress As Word), Byte
    PinClear EE_CS_Pin                              ' Enable the SPI interface
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, $03)            ' Send the read command to the EEPROM
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, pAddress.Byte1) ' \ Send the 16-bit address
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, pAddress.Byte0) ' /
    Result = SPI_Read8(EE_MISO_Pin, EE_CLK_Pin)         ' Read the data
    PinSet EE_CS_Pin                                ' Disable the SPI interface
EndProc

'------------------------------------------------------------------------
' Write data to an SPI EEPROM
' Input     : pAddress holds the 16-nit address to write
'           : pData holds the byte to write to the SPI EEPROM
' Output    : None
' Notes     : None
'
Proc EE_Write(pAddress As Word, pData As Byte)
    PinClear EE_CS_Pin                              ' Enable the SPI interface
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, $06)        ' Send the write enable command to the EEPROM
    PinSet EE_CS_Pin                                ' Disable the SPI interface to execute command

    PinClear EE_CS_Pin                              ' Enable the SPI interface
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, $02)        ' Send the write command to the EEPROM
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, pAddress.Byte1) ' \ Send the 16-bit address
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, pAddress.Byte0) ' /
    SPI_Write8(EE_MOSI_Pin, EE_CLK_Pin, pData)      ' Send the data byte
    PinSet EE_CS_Pin                                ' Disable the SPI interface
EndProc

'------------------------------------------------------------------------
' Write 8-bits to an SPI interface
' Input     : pMOSI_Pin holds the MOSI pin for the SPI interface
'           : pCLK_Pin holds the CLK pin for the SPI interface
'           : pData holds the byte to write to the SPI interface
' Output    : None
' Notes     : SPI Mode 0. MSB
'
Proc SPI_Write8(pMOSI_Pin As SPI_bMOSI_MISO_Pin, pCLK_Pin As SPI_bCLK_Pin, pData As Byte)
Global Dim SPI_bBits As Byte Shared                 ' Holds the loop counter for the 8-bits

    PinLow pCLK_Pin                                 ' Make the SPI CLK pin an output low
    PinOutput pMOSI_Pin                             ' Make the SPI MOSI pin an output
    For SPI_bBits = 7 DownTo 0                      ' Create an 8-bit SPI loop
        PinClear pMOSI_Pin                          ' Default to a low MOSI Pin
        If pData.7 = 1 Then                         ' Is the Bit-7 of pData set?
            PinSet pMOSI_Pin                        ' Yes. So set the MOSI Pin high
        EndIf
        Rol pData                                   ' Rotate the next bit into bit-7 (MSB)
        PinSet pCLK_Pin                             ' Set the CLK pin high
        DelayUS 1                                   ' A small delay
        PinClear pCLK_Pin                           ' Pull the CLK pin low
        DelayUS 1                                   ' A small delay
    Next
EndProc

'------------------------------------------------------------------------
' Read 8-bits from an SPI interface
' Input     : pMISO_Pin holds the MISO pin for the SPI interface
'           : pCLK_Pin holds the CLK pin for the SPI interface
' Output    : Returns the 8-bits read from the SPI interface
' Notes     : SPI Mode 0. MSB
'
Proc SPI_Read8(pMISO_Pin As SPI_bMOSI_MISO_Pin, pCLK_Pin As SPI_bCLK_Pin), Byte
Global Dim SPI_bBits As Byte Shared                 ' Holds the loop counter for the 8-bits

    PinLow pCLK_Pin                                 ' Make the SPI CLK pin an output low
    PinInput pMISO_Pin                              ' Make the SPI MISO pin an input
    For SPI_bBits = 7 DownTo 0                      ' Create an 8-bit SPI loop
        Result = Result << 1                        ' Shift the next bit into MSB
        PinSet pCLK_Pin                             ' Set the SCK pin high
        DelayUS 1                                   ' A small delay
        Result.0 = GetPin pMISO_Pin                 ' Capture the current bit from the MISO Pin
        PinClear pCLK_Pin                           ' Pull the CLK pin low
        DelayUS 1                                   ' A small delay
    Next
EndProc

'------------------------------------------------------------------------
' Setup the config fuses to operate the PIC16F18856 device with an external crystal.
'
    Config1 FEXTOSC_HS,_                            ' External Oscillator enabled
            CLKOUTEN_ON,_                           ' CLKOUT function enabled
            CSWEN_ON,_                              ' Writing to NOSC and NDIV is allowed
            FCMEN_OFF                               ' Fail-Safe Clock Monitor timer disabled

    Config2 MCLRE_ON,_                              ' MCLR pin is Master Clear function
            PWRTE_ON,_                              ' Power-up Timer enabled
            LPBOREN_OFF,_                           ' Low-Power BOR disabled
            BOREN_ON,_                              ' Brown-out Reset Enabled. SBOREN bit is ignored
            BORV_LO,_                               ' Brown-out Reset Voltage set to 2.45V
            ZCD_OFF,_                               ' Zero-cross detect circuit is disabled at POR
            PPS1WAY_OFF,_                           ' The PPSLOCK bit can be set and cleared repeatedly by software
            STVREN_ON,_                             ' Stack Overflow or Underflow will cause a reset
            DEBUG_OFF                               ' Background Debugger disabled

    Config3 WDTCPS_WDTCPS_31,_                      ' WDT Divider ratio 1:65536. Software control of WDTPS
            WDTE_OFF,_                              ' WDT Disabled. SWDTEN is ignored
            WDTCWS_WDTCWS_7,_                       ' WDT window always open (100%). Software control. Keyed access not required
            WDTCCS_SC                               ' WDT input clock is Software Control

    Config4 WRT_OFF,_                               ' User NVM Write protection off
            SCANE_NOT_AVAILABLE,_                   ' Scanner module is mot available
            LVP_OFF                                 ' High Voltage on MCLR/Vpp must be used for programming

    Config5 CP_OFF,_                                ' Program Memory code protection disabled
            CPD_OFF                                 ' Data EEPROM code protection disabled

On the serial terminal, it shows:

Writing
Address 00 will contain 139
Address 01 will contain 023
Address 02 will contain 047
Address 03 will contain 094
Address 04 will contain 189
Address 05 will contain 122
Address 06 will contain 245
Address 07 will contain 235
Address 08 will contain 215
Address 09 will contain 174
Address 10 will contain 092
Address 11 will contain 184
Address 12 will contain 113
Address 13 will contain 226
Address 14 will contain 197
Address 15 will contain 138

Reading
Address 00 holds 139
Address 01 holds 023
Address 02 holds 047
Address 03 holds 094
Address 04 holds 189
Address 05 holds 122
Address 06 holds 245
Address 07 holds 235
Address 08 holds 215
Address 09 holds 174
Address 10 holds 092
Address 11 holds 184
Address 12 holds 113
Address 13 holds 226
Address 14 holds 197
Address 15 holds 138


Regards
Les