SPI slave, SPI.transfer question

I have an application where I need to have my Photon act as a SPI slave device.
The SPI slave example, is a bit confusing to me because the example uses:
SPI.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), onTransferFinished);

For a slave device why do we need to pass tx_buffer ? We are not sending data out, we are waiting for our SS line to be pulled low from the SPI master and clock in data to us.

Yes you do send out data to the master. These are dummy bytes to request one byte after the other, otherwise the master wouldn’t know that the slave has “seen” the transaction request and is willing to read the bytes.
One byte out will bring one byte in - at least this is how the DMA transfer is implemented here.
https://docs.particle.io/reference/firmware/photon/#transfer-void-void-size_t-std-function-

1 Like

A slave device does not always send data to the master. Some devices do like a SPI temp sensor, while others dont.

For example. Say I have a APA102C (SPI RGB lerd) connected to my photon.

Since I am the master I send the slave (RGB LED) SPI color data. The salve does not send any data back, because its a slave.

Likewise, If I want to particle to be a SPI slave, I do not have to send the master data. I just need to receive it.
Make sense ?

Have you read the docs about how the DMA transfer is implemented in the link I provided?

Hi @mikemoy

See this picture in Wikipedia for why there is a transmit buffer required-there is a circular shift-register between the two chips. The master can ignore the slave data, but it is always sent.

1 Like

Yes, DMA transfer acting as a master this makes sense. But for a slave is where it gets a little convoluted.
If the Photon is a slave, it does not need to send data to the master. It just needs to wait to receive it.

@bko,
It is true the master can ignore it. The problem is if your a slave and are waiting to receive 32 bits of data from a master. by forcing to send out 32 bits causes a time lag that will then cause you to miss the received 32 bits.

Another way to put it. The master I am connected to belches out 64 bits of data in 1.5ms. Then waits 10us, and burps out another 64 bits. The way this SPI.transfer is set up is that I have to send 64 bits in order to get 64 bits. The sending of the 64 bits takes time, and causes it to miss all the 64 bits received because its busy sending them out first which is not necessary for a slave to do. Its a receiver.

I just re-wired my setup using an Atmga328P, and it works fine here because you don’t need to send data out as a slave.

Hi @mikemoy

I really think you should look at the Wikipedia article to understand how SPI works at the hardware level. For every bit sent in one direction, there is another bit sent in the other direction. That is just the way it works.

Your master might be ignoring the presumably zeros that it is receiving but it does not slow down the SPI for the slave to send bits back to the master.

If you are having trouble with timing, you should be using DMA as @ScruffR pointed out. You can pass a pointer to an array of one or more zero bytes. You can also control the SPI clock with the documented functions. Particle has hardware SPI so once you set it up, it is fast; it is not the case that software is bit-banging out data from the Photon.

1 Like

Thanks guys for the help. I don't mean to sound rude. But you cannot believe everything you read on the internet. This even goes for Wikipedia. I am a embedded hardware engineer. Have been doing this for over 25 years. I know SPI like the back of my hand.

I can tell you Wikipedia is not 100% correct concerning SPI.

They state:

During each SPI clock cycle, a full duplex data transmission occurs. The
master sends a bit on the MOSI line and the slave reads it, while the
slave sends a bit on the MISO line and the master reads it. This
sequence is maintained even when only one-directional data transfer is
intended.

This is not 100% true. There are many, many devices that do not do this. I have shown one in the beginning of this post.
That device like many others do not even have a MISO line.

They state:

Every slave on the bus that has not been activated using its chip select
line must disregard the input clock and MOSI signals, and must not
drive MISO.

This also is not 100% true. There are many devices out there.that have an address to select them. Much like I2C does.
again, the device I gave in the post does not even have a CS line.

I probably was not real clear on the problem. Lets say you want to monitor or spy on two parts talking to one another over SPI. If the Master clocks out 64bits. (4 separate writes with 16 bits each) to the slave, which in this case the process takes 1.5ms. Since we must clock out 64 bits to get 64 bits, The moment we detect the SS line going low from the master, we shoot out 64 bits. But wait!!! clocking out those 64 bits took some time, and while we were sending those out, we missed the part if not all the of the 64 bits coming from the master, so we never catch it all.

On the Atmel part you can setup the SPI as a true slave. It does not need to clock out the data to get data. It triggers on the SS pin, and the clock serially shifts in the data into the SPI data receive register. When 8 bits are there you get an IRQ to read it out of the register.

This post is mute now, because in this case this is exactly what i am doing. I am spying on 2 chips talking to one another. Turns out they are using 17 bits. So that throws most of this out the window. Even when using the Atmel chips I am using I cannot use the "SPI" peripheral, because its 8 bit shift register. So I had to resort to bit reading the data manually. I don't think the Photon is fast enough to do this, but I might give it try.