News:

Let's find out together what makes a PIC Tick!

Main Menu

Bit banging driven by an external clock

Started by kcsl, Mar 09, 2024, 12:03 PM

Previous topic - Next topic

kcsl

We have the synchronous SHin / SHout commands but the clocks are supplied by the PIC - which makes sense when your trying to access SPI based devices connected to the PIC, making the PIC the master I suppose.

Is there a form of bit banging supported that uses an external clock; so the PIC acts as a slave device?

Thought I'd check I'm not missing something obvious before writing the code.

Thanks,
Joe
There's no room for optimism in software or hardware engineering.

trastikata

#1
Quote from: kcsl on Mar 09, 2024, 12:03 PMThought I'd check I'm not missing something obvious before writing the code.

QuoteOPERATION
When initializing the SPI, several options need to be
specified. This is done by programming the appropriate
control bits (SSPCON1<5:0> and SSPSTAT<7:6>).
These control bits allow the following to be specified:
• Master mode (SCK is the clock output)
• Slave mode (SCK is the clock input)

However I never used the PIC in a slave hardware SPI mode.

tumbleweed

QuoteIs there a form of bit banging supported that uses an external clock; so the PIC acts as a slave device?
It's hard to imagine that working out very well.

Since everything on the slave side would be done in software by polling pin states, the master would have to run the clock VERY slowly to give the slave a chance to catch it, and even then it would never be sure that the slave wasn't busy at the time and missed a bit.

You could get it to work under limited conditions but it would be incredibly fragile and prone to failure.


Pepe

Demo Proteus Master Slave with Pic

Teo

Hi Pepe,
Please be kind and post the code for master and slave.
Thanks in advance,
Teo

Pepe

#5
Modified to be able to share source programs

top204

An SPI slave can be created using bit-banging with an 18F device, but it would be slower than using a dedicated peripheral, and the slave would need to be in a very tight loop and could miss things when it is looking elsewhere. Or an alternative method could be to use INTx interrupts to wait for clock pulses within an interrupt handler, then check the state of the data line to build up byte segments, but, again, this would be slower than a dedicated peripheral that performs these tasks in the background. So it is better to use the MSSP peripheral as an SPI slave.

Quite a few years ago, I created a commercial project that had 80 SPI slaves on it, all implemented with PIC18F devices using their MSSP peripheral, and they worked extremely well. So I have created a simple demo to show how an SPI slave and master can be created using an 18F25K20 device. SPI master/slave can be made to work on any PIC device that has an MSSP peripheral capable of operating as Slave, but the SPI peripheral's SFRs (Special Function Registers) will need to be changed for the device used.

Below is the Slave code listing that acts as a block of RAM with a size of 255 bytes, and it can be written too or read from by the master. It is written for use on a PIC18F25K20 device operating at 64MHz, but this can be changed with SFR changes etc...

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate an SPI slave to read and write a block of RAM on a PIC18F25K20 device
'
' Written for the Positron8 BASIC compiler by Les Johnson
'
' Pin Settings...
'
' Master                 Slave
' SDO(RC5) ------------> SDI(RC4)
' SDI(RC4) <------------ SDO(RC5)
' CLK(RC3) ------------> CLK(RC3)
' CS(RA5)  ------------> SS(RA5)
'
    Device = 18F25K20                                   ' Tell the compiler to compile for a PIC18F25K20 device
    Declare Xtal = 64                                   ' Tell the compiler, the device is operating at 64MHz
    On_Hardware_Interrupt GoTo ISR_Handler              ' Point the interrupt to its handler
'
' Setup USART1
'
    Declare Hserial_Baud = 9600                         ' Set the Baud rate
    Declare HRsout_Pin   = PORTC.6
'
' Setup the SPI peripheral's pins
'
    Symbol SPI_CLK_Pin = PORTC.3
    Symbol SPI_SDI_Pin = PORTC.4
    Symbol SPI_SDO_Pin = PORTC.5
    Symbol SPI_SS_Pin = PORTA.5
'
' Variables
'
    Dim SPI_tDataReady  As Bit                          ' Signals that the SPI has data
    Dim SPI_bByteCount  As Byte Access                  ' Counts the amount of bytes received
    Dim SPI_bValue      As Byte Access                  ' Holds the value to write to RAM
    Dim SPI_bMnemonic   As Byte                         ' Holds the mnemonic for read or write
    Dim SPI_bAddress    As Byte                         ' Holds the address of the RAM to write/read
    Dim bRAM_Array[255] As Byte Heap                    ' A block of RAM to read/write
'
' SPI Mnemonics
'
    Symbol cMnWrite = $F0                               ' Write command
    Symbol cMnRead = $0F                                ' Read command

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif

'-----------------------------------------------------------------------------------
' The main program starts here
' Read the stream of SPI data from the master and read or write RAM accordingly
'
Main:
    Setup()                                             ' Initialise the SPI peripheral as a slave on a PIC18F25K20 device

    Do                                                  ' Create a loop
        '
        ' Trap an unexpected activation of the SS pin
        '
        If SPI_SS_Pin = 1 Then                          ' Is the SS line high?
            PIR1bits_SSPIF = 0                          ' Yes. So clear the SPI flag
            WREG = SSPBUF                               ' Clear SSPBUF by reading it
            SPI_bByteCount = 0                          ' Reset the byte counter
            SPI_tDataReady = False                      ' Reset the ready flag
        EndIf
        '
        ' Read the data structure. i.e. Mnemonic, Address, Value
        '
        If SPI_tDataReady = True Then                   ' Has a byte been read from the SPI interrupt?
            SPI_tDataReady = False                      ' Yes. So reset the ready flag
            If SPI_bByteCount = 1 Then                  ' Have we read the first byte?
                SPI_bMnemonic = SPI_bValue              ' Yes. So this is the mnemonic

            ElseIf SPI_bByteCount = 2 Then              ' Have we read the second byte?
                SPI_bAddress = SPI_bValue               ' Yes. So this is the address
                If SPI_bMnemonic = cMnRead Then         ' Is the mnemonic a read command?
                    SSPBUF = bRAM_Array[SPI_bAddress]   ' Yes. So setup for the return byte
                EndIf

            Else                                        ' Otherwise... It must be a third byte
                If SPI_bMnemonic = cMnWrite Then        ' Is the mnemonic a write command?
                    bRAM_Array[SPI_bAddress] = SPI_bValue ' Yes. So place the byte read into the RAM array
                EndIf
                SPI_bByteCount = 0                      ' Reset the byte counter
            EndIf
        EndIf
    Loop                                                ' Do it forever

'-----------------------------------------------------------------------------------
' Initialise the SPI slave routines on a PIC18F25K20 device
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    INTCON = $00                                        ' Make sure interrupts are disabled
    WREG = SSPBUF                                       ' Clear the SSPBUF of any erroneous data
'
' Setup the SPI peripheral
'
    SSPCON1 = $04                                       ' \ Disable SPI and configure SCK, SDO, SDI and SS as SPI port pins
                                                        ' | Idle state for clock is a low level
                                                        ' / SPI Slave mode, clock = SCK pin, SS pin control enabled
    SSPSTAT = $00                                       ' \ Input data sampled at middle of data output time
                                                        ' / Transmit occurs on transition from Idle to active clock state
'
' SPI slave pin configurations
'
    PinInput SPI_CLK_Pin                                ' Make the SCK pin an input
    PinInput SPI_SDI_Pin                                ' Make the SDI pin an input
    PinOutput SPI_SDO_Pin                               ' Make the SDO pin an output
    PinInput SPI_SS_Pin                                 ' Make the SS pin an input

    SPI_tDataReady = False                              ' Clear the data ready flag
    SPI_bByteCount = 0
    SPI_bValue = 0
    Clear bRAM_Array                                    ' Clear the RAM buffer array
'
' Setup and enable the SPI interrupt mechanism
'
    PIR1bits_SSPIF = 0                                  ' Clear the SPI interrupt flag
    SSPCON1bits_SSPEN = 1                               ' Enable the SPI peripheral
    PIE1bits_SSPIE = 1                                  ' Enable the SPI peripheral interrupt
    INTCON = $C0                                        ' Enable peripheral and global interrupts
EndProc

'-----------------------------------------------------------------------------------
' Interrupt handler
' Reads mnemonic, address and either writes or reads from a RAM block
'
ISR_Handler:
    Context Save

    If PIR1bits_SSPIF = 1 Then                          ' Is it an SPI interrupt?
        Repeat: Until SSPSTATbits_BF = 1                ' Yes. So wait for the byte
        SPI_bValue = SSPBUF                             ' Read the SPI buffer
        Inc SPI_bByteCount                              ' Increment the byte counter
        SSPCON1bits_WCOL = 0                            ' \
        SSPCON1bits_SSPOV = 0                           ' / Clear any possible errors
        SPI_tDataReady = True                           ' Signal that there's data to be worked upon
        PIR1bits_SSPIF = 0                              ' Reset the SPI interrupt flag
    EndIf

    Context Restore

'-----------------------------------------------------------------------------------
' Setup the config fuses for a PIC18F25K20 device to operate at 64MHz using a 16MHz crystal (4xPLL enabled)
'
Config_Start
    FOSC = HSPLL        ' HS oscillator, PLL enabled and under software control
    Debug = Off         ' Background debugger disabled' RB6 and RB7 configured as general purpose I/O pins
    XINST = Off         ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
    STVREN = Off        ' Reset on stack overflow/underflow disabled
    WDTEN = Off         ' WDT disabled (control is placed on SWDTEN bit)
    FCMEN = Off         ' Fail-Safe Clock Monitor disabled
    IESO = Off          ' Two-Speed Start-up disabled
    WDTPS = 128         ' Watchdog is 1:128
    BOREN = Off         ' Brown-out Reset disabled in hardware and software
    BORV = 18           ' VBOR set to 1.8 V nominal
    MCLRE = On          ' MCLR pin enabled, RE3 input pin disabled
    HFOFST = Off        ' The system clock is held Off until the HF-INTOSC is stable.
    LPT1OSC = Off       ' T1 operates in standard power mode
    PBADEN = Off        ' PORTB<4:0> pins are configured as digital I/O on Reset
    CCP2MX = PORTC      ' CCP2 input/output is multiplexed with RC1
    LVP = Off           ' Single-Supply ICSP disabled
    Cp0 = Off           ' Block 0 (000800-001FFF) not code-protected
    CP1 = Off           ' Block 1 (002000-003FFF) not code-protected
    CPB = Off           ' Boot block (000000-0007FF) not code-protected
    CPD = Off           ' Data eeprom not code-protected
    WRT0 = Off          ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off          ' Block 1 (002000-003FFF) not write-protected
    WRTB = Off          ' Boot block (000000-0007FF) not write-protected
    WRTC = Off          ' Configuration registers (300000-3000FF) not write-protected
    WRTD = Off          ' Data eeprom not write-protected
    EBTR0 = Off         ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off         ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB = Off         ' Boot block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

And below is the Master code listing that writes to the slave's RAM, then reads it. It also sends some duff bytes deliberately, to make sure the slave's recovery mechanism is OK. Again, it is written for use on a PIC18F25K20 device operating at 64MHz, but this can be changed with SFR changes etc...

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' SPI Master demo to write and read RAM in the SPI slave on a PIC18F25K20 device
'
' Written for the Positron8 BASIC compiler by Les Johnson
'
' Pin Settings...
'
' Master                 Slave
' SDO(RC5) ------------> SDI(RC4)
' SDI(RC4) <------------ SDO(RC5)
' CLK(RC3) ------------> CLK(RC3)
' CS(RA5)  ------------> SS(RA5)
'
    Device = 18F25K20                                   ' Tell the compiler to compile for a PIC18F25K20 device
    Declare Xtal = 64                                   ' Tell the compiler, the device is operating at 64MHz
'
' Setup USART1
'
    Declare Hserial_Baud = 9600                         ' Set the Baud rate
    Declare HRsout_Pin   = PORTC.6
'
' Setup the SPI peripheral's pins
'
    Symbol SPI_CLK_Pin = PORTC.3
    Symbol SPI_SDI_Pin = PORTC.4
    Symbol SPI_SDO_Pin = PORTC.5
    Symbol SPI_CS_Pin = PORTA.5
'
' SPI Mnemonics
'
    Symbol cMnWrite = $F0                               ' Write command
    Symbol cMnRead = $0F                                ' Read command
'
' Variables
'
    Dim SPI_bAddress As Byte                            ' Holds the address of the RAM to write/read
    Dim SPI_ByteOut  As Byte                            ' Holds the byte to write to the slave
    Dim SPI_ByteIn   As Byte                            ' Holds the byte read from the slave

'-----------------------------------------------------------------------------------

$define SPI_Enable() PinClear SPI_CS_Pin
$define SPI_Disable() PinSet SPI_CS_Pin

'-----------------------------------------------------------------------------------
' The main program starts here
' Write to the SPI slave acting as an external RAM, then read from it.
'
Main:
    Setup()                                             ' Setup the program and the SPI peripheral

    SPI_bAddress = 0
    Do                                                  ' Create a loop
        HRSOutLn "**** Writing ****"
        For SPI_ByteOut = 255 DownTo 0                  ' Create a loop to write to the slave's RAM
            Command_Write(SPI_bAddress, SPI_ByteOut)    ' Write to the slave's RAM
            Inc SPI_bAddress                            ' Move up the Address
            DelayMs 10
        Next                                            ' Close the loop

        HRSOutLn "\r**** Reading ****"
        For SPI_bAddress = 0 To 255                     ' Create a loop to read from the slave's RAM
            If SPI_bAddress // 10 = 1 Then              ' Have we reached the 10th read?
                Command_Wrong(SPI_bAddress)             ' Yes. So send a malformed command for testing
                HRSOutLn "Incorrect Command Deliberately Sent"       ' Signal that it has been sent
            Else                                        ' Otherwise...
                SPI_ByteIn = Command_Read(SPI_bAddress) ' Read from the slave's RAM
                HRSOutLn "Read Value = ", Dec SPI_ByteIn  ' Display what was read
            EndIf
        Next                                            ' Close the loop
    Loop                                                ' Do it forever

'-----------------------------------------------------------------------------------
' Setup the program and the SPI peripheral
' Input     : None
' Output    : None
' Notes     : The SPI peripheral is setup for use on a PIC18F25K20 device
'
Proc Setup()
    DelayMS 100                                         ' Give time for the slave to power up

    SSPCON1 = $02                                       ' Setup SPI for master mode, Fosc / 64 (1MHz operation)
    SSPCON1bits_CKP = 0                                 ' Clock Polarity Select : Clock idle low
    SSPSTATbits_CKE = 0                                 ' Clock Edge Select Bit : Transmit on idle to active transition
    SSPSTATbits_SMP = 0                                 ' Data Input sample phase: Sample in middle of data
    PIR1bits_SSPIF = 0                                  ' Clear buffer full status

    PinOutput SPI_CLK_Pin                               ' Make the Clock pin an output
    PinInput SPI_SDI_Pin                                ' Make the Data in pin an input
    PinOutput SPI_SDO_Pin                               ' Make the Data out pin an output
    PinHigh SPI_CS_Pin                                  ' Disable the SPI slave
    SSPCON1bits_SSPEN = 1                               ' Enable the SPI peripheral
EndProc

'-----------------------------------------------------------------------------------
' Write a byte to the slave
' Input     : pAddress holds the 8-bit address
'           : pValue holds the byte to write
' Output    : None
' Notes     : Has a small delay to give time for the SPI slave to write the value
'
Proc Command_Write(pAddress As Byte, pValue As Byte)
    SPI_Enable()                                        ' Enable the SPI
    SPI_Write(cMnWrite)                                 ' Send the 'Write' mnemonic to the slave
    SPI_Write(pAddress)                                 ' Send the address to write to the slave
    SPI_Write(pValue)                                   ' Write the value to the slave
    DelayCS 50                                          ' Give a small delay for the slave to sort itself out (just in case)
    SPI_Disable()                                       ' Disable the SPI
EndProc

'-----------------------------------------------------------------------------------
' Read a byte from the slave
' Input     : pAddress holds the 8-bit address
' Output    : pResult holds the byte read from the slave
' Notes     : Has a small delay to give time For the SPI slave to read the value
'
Proc Command_Read(pAddress As Byte), WREG
    SPI_Enable()                                        ' Enable the SPI
    SPI_Write(cMnRead)                                  ' Send the 'Read' mnemonic to the slave
    SPI_Write(pAddress)                                 ' Send the address to read from to the slave
    DelayCS 50                                          ' Give a small delay for the slave to sort itself out (just in case)
    Result = SPI_Write($FF)                             ' Read the slave
    SPI_Disable()                                       ' Disable the SPI
EndProc

'-----------------------------------------------------------------------------------
' Write and read a single byte (8-bits) to/from the SPI bus
' Input     : Single 8-bit variable for SPI bus
' Output    : Returns the value read from the SPI interface
' Notes     : This SPI peripheral code is for a PIC18F25K20 device
'
Proc SPI_Write(pDataOut As WREG), WREG
    SSPSTATBits_BF = 0                                  ' Empty the SSPBUF buffer flags
    PIR1bits_SSPIF = 0                                  ' Clear the interrupt flag
    SSPBUF = WREG                                       ' Place the data to send into SSPBUF
    Clrwdt                                              ' Keep the watchdog happy
    Repeat: Until PIR1bits_SSPIF = 1                    ' Wait until cycle complete
    Result = SSPBUF                                     ' Read SSPBUF into WREG
EndProc

'-----------------------------------------------------------------------------------
' Deliberately send a malformed SPI command
' Input     : pValue holds the byte to send to the slave
' Output    : None
' Notes     : This will test the reset mechanism of the slave SPI
'
Proc Command_Wrong(pValue As Byte)
    SPI_Enable()                                        ' Enable the SPI
    SPI_Write(pValue)                                 ' Just send a value that the SPI slave cannot know the meaning of
    SPI_Disable()                                       ' Disable the SPI
EndProc

'-----------------------------------------------------------------------------------
' Setup the config fuses for a PIC18F25K20 device to operate at 64MHz using a 16MHz crystal (4xPLL enabled)
'
Config_Start
    FOSC = HSPLL        ' HS oscillator, PLL enabled and under software control
    Debug = Off         ' Background debugger disabled' RB6 and RB7 configured as general purpose I/O pins
    XINST = Off         ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
    STVREN = Off        ' Reset on stack overflow/underflow disabled
    WDTEN = Off         ' WDT disabled (control is placed on SWDTEN bit)
    FCMEN = Off         ' Fail-Safe Clock Monitor disabled
    IESO = Off          ' Two-Speed Start-up disabled
    WDTPS = 128         ' Watchdog is 1:128
    BOREN = Off         ' Brown-out Reset disabled in hardware and software
    BORV = 18           ' VBOR set to 1.8 V nominal
    MCLRE = On          ' MCLR pin enabled, RE3 input pin disabled
    HFOFST = Off        ' The system clock is held Off until the HF-INTOSC is stable.
    LPT1OSC = Off       ' T1 operates in standard power mode
    PBADEN = Off        ' PORTB<4:0> pins are configured as digital I/O on Reset
    CCP2MX = PORTC      ' CCP2 input/output is multiplexed with RC1
    LVP = Off           ' Single-Supply ICSP disabled
    Cp0 = Off           ' Block 0 (000800-001FFF) not code-protected
    CP1 = Off           ' Block 1 (002000-003FFF) not code-protected
    CPB = Off           ' Boot block (000000-0007FF) not code-protected
    CPD = Off           ' Data eeprom not code-protected
    WRT0 = Off          ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off          ' Block 1 (002000-003FFF) not write-protected
    WRTB = Off          ' Boot block (000000-0007FF) not write-protected
    WRTC = Off          ' Configuration registers (300000-3000FF) not write-protected
    WRTD = Off          ' Data eeprom not write-protected
    EBTR0 = Off         ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off         ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB = Off         ' Boot block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

Below is a screenshot of the SPI master and slave units working in the Proteus simulator, and the demo code listings and proteus design files are also attached below:

SPI_Master_Slave - 18F25K20.jpg

Pepe

#7
Teo Demo with source

Teo

Les and Pepe ,
Thank you very much !
Teo

kcsl

Thanks everybody.
Unfortunately the 12F1501 I'm currently stuck using doesn't have a SPI support, hence the reason for bit-banging.

For this project speed isn't overly important, but the ability to chain multiple devices together is.
Short on RAM, program space and I/O pins, I'm somewhat painted into a corner with this one.

I am going to see if I can move to something like a PIC12F1840 which does have SPI. Actually it has more of everything and only slightly more expensive.


Regards,
Joe



There's no room for optimism in software or hardware engineering.

tumbleweed

An SPI slave can be tricky to get working reliably even when you have an SPI peripheral.

The MSSP hardware only has a single input/output buffer (SSP1BUF) which is updated with the contents of the SPI shift register (SSP1SR) when the master transfers a byte. That means that basically you must be able to handle bytes every 8 SPI clocks or you could lose data.

In Les's example he's using an SPI clock of 1MHz, so the slave ISR + main loop execution time cannot exceed 8us. You can add delays between sending bytes on the master side, but that means the master must know how long the slave might take to process the bytes.

If you tried to do this in software you'd have to run the master clock VERY slow to give the slave a chance to catch all the clock transitions and assemble the incoming byte, which is even worse.

Pepe's code is using the MSSP I2C hardware, so that doesn't apply to what you asked for.





 

trastikata

Quote from: kcsl on Mar 10, 2024, 09:33 AMUnfortunately the 12F1501 I'm currently stuck using doesn't have a SPI support, hence the reason for bit-banging.

PIC12F1501 has hardware IOC (Interrupt on change) capability which could greatly speed-up software SPI.

In the IOC routine fill a 2-byte ping-pong buffer with the data-pin state, then raise a flag for the Main program when one of the buffer bytes is full.

tumbleweed

I don't know that interrupts will necessarily make it any faster, but at least it might make it slightly more reliable in assembling the incoming data byte.

trastikata

Quote from: tumbleweed on Mar 10, 2024, 03:03 PMI don't know that interrupts will necessarily make it any faster

I think the hardware interrupt jump on pin change (positive or negative edge can be selected) would be at least few tens of cycles faster than checking and comparing the Clock pin state with its previous state in a software loop.

I agree reliability will be significantly enhanced.

normnet

Didn't Les say a while ago that bit banging with a 16 bit device is faster than the hardware SPI?     

Pepe