Software SPI.transfer (Solved!)

I was wondering it there is a software version of the SPI.transfer function from the SPI.h library.

I know of the shiftout and shiftin functions, but you can't just use them both to simulate the transfer function..

Is there something like this available anywhere?

Yes, there is, have you tried google "Arduino software SPI"?
it gives this relevant hit - Is there a 'Software SPI'? - Networking, Protocols, and Devices - Arduino Forum -

This justs shifts the data out right? I'm looking for the SPI.Transfer function, but without the hardware SPI pins. The transfer function returns a received byte aswell.

yep SPI is just shifting...

Yes, I know, but just shifting out a byte doesn't get you a received byte..

What is your reason for avoiding the hardware SPI?

with SW SPI you must explicitly wait for incoming data.

SurferTim:
What is your reason for avoiding the hardware SPI?

I've got a big bunch of sound reactive lights, but it's a pain to run jack cables to all of them, so I'd like to broadcast the 'decoded' audio to all lights at once via nrf24l01+ modules.

One of the lights:

The lights however use the shiftPWM library, which uses the hardware SPI aswell.

In the MIRF library for the nrf24l01+ modules, sending and receiving is all done with the SPI.transfer function.
I'm looking for a function to replace that function, but using softwareSPI.

So what data do you need to read from the lights? Are they not write only?

This is from the shiftPWM page. http://www.elcojacobs.com/shiftpwm/

To SPI or not to SPI
You can use ShiftPWM with the hardware SPI or without. Using it without the hardware SPI is about 2.5x slower, but allows you to use the SPI port for something else.

Something else like the nrf24?

I'm softwarePWMing the 24 LED channels. This has te be done pretty fast, so this will need the hardwareSPI. I know it can be done the other way around, but the leds need 4096 bytes shifted out every time there will be one message coming on the nrf24 module. I also have an other light that just uses the 6 arduino PWM pins, so for that i'd also have to clear pin 11.

What do you mean with "Something else like the nrf24?" ?

It took a while, but I ended up writing it myself!
At first replacing the function didn't work at all, but that ended up being because the SPI was still "on", so I couldn't write to the 13 and 11 pins myself..

Here's the code:

uint8_t softSpiTransfer(uint8_t shOut){
  uint8_t shIn = 0;
  for(int i = 0; i < 8; i++) {
    if (shOut > 127)  digitalWrite (outPin,1);
    else              digitalWrite (outPin,0);
    if (digitalRead(inPin)) shIn += 1;
    digitalWrite (clkPin,1);
    digitalWrite (clkPin,0);
    if (i != 7)	shIn <<= 1;
    shOut <<= 1;
  }
  return shIn;
}

Thanks for sharing your solution!

I have just built a "proper" software SPI interface for the Arduino.

It inherits the normal SPI class as its parent, so anything that uses SPI should work with SoftSPI with little or no changes.

To use it:

#include <SPI.h>
#include <SoftSPI.h>

SoftSPI mySPI(2, 3, 4); // MOSI = 2, MISO = 3, SCK = 4

void setup() {
  mySPI.begin();
}

void loop() {
  uint8_t out = 0x69;
  uint8_t in = mySPI.transfer(out);
}

It handles (or should handle) all the normal SPI methods, like setDataMode, setBitOrder, setClockDivider.

It only works as a master though, so don't try and get it working as a slave cus it just won't.

majenko:
I have just built a "proper" software SPI interface for the Arduino.
It only works as a master though, so don't try and get it working as a slave cus it just won't.

Must be flavour of the month as I'm also doing a SoftSPI library. :smiley:
What does your waveform look like on a logic analyser as I found working with the minimum of delay I could only match something like DIV16 or DIV32 (not at home to confirm results) and the clock was not 50% duty cycle.
I had considered resorting to machine code but that makes it less portable. I also pre arrange the output data but into an array, I like your idea of just swapping bit order so reducing memory access.
The core transfer routine.

  for (byte count = 0; count <8; count++){      // 8 bits to transfer
    
    if (rxtxbits[count])                        // Set mosi pin
      *_mosiPort |= _mosiMask;
    else
      *_mosiPort &= ~_mosiMask;
    
    *_clkPort |= _clkMask;                      // Set clock pin
    
    delayMicroseconds(1);                       // Delay (* needs to be a better way)
    
    *_clkPort &= ~_clkMask;                     // Clear clock pin
    
    delayMicroseconds(1);                       // Delay to allow slave time to load bit
    rxtxbits[count] = *_misoPort & _misoMask;   // Read the bit
  }