SPI transfer on board UNO : send M bytes then receive N bytes ?

Hi everybody,

I'm having a question as a newbie on Arduino programming: I have a UNO acting as SPI Master that must send a message of 4 bytes to DSPIC microcontroller to request some information. Then DSPIC will respond by a message of 12 bytes.

I have taken a look in the SPI.transfer() https://www.arduino.cc/en/Reference/SPITransfer and I can't imagine how to do this task properly. I guess that SPI.transfer(buffer,size) may work but I'm not sure if that can do the transfer for both directions. For example:

  • to send request: SPI.transfer(request,4)
  • to receive : SPI.transfer(result,12)
    The goal is to read properly the 12 bytes result that are sent by DSPIC.

Hope that anyone can give me an advice. Thank you in advance.

A few more details on my implementation: I have only 3 more pins available on DSPic and I allocated them for SCK, SDI, SDO, then connected them respectively to SCK, MOSI, MISO of Arduino UNO board (as I need to transfer on both direction, hope that's correct ?!) :o

hoangphithuong:
For example:

  • to send request: SPI.transfer(request,4)
  • to receive : SPI.transfer(result,12)

SPI always sends and receives at the same time. The 'transfer' where you use an array and a length replaces each byte being sent with the corresponding received byte.
When you send 'request' you should be aware that whatever was in the array will be replaced with whatever the other end sends when it has no data to send (typically zeroes). If you try to send that array again you will probably be sending zeroes. Re-fill the 'request' array before each send.
When you receive 'result', whatever values were in the array will be sent out. You should probably set the array contents to zeroes before you do the receive. Note: The datasheet for the device might say what dummy values to send when receiving data. If it does specify, use that value instead of zero.

My experience with SPI at the lower level is from using the ESP32 SPI API.

Still SPI is SPI.

SPI sends and receives in bytes, uint_8t or int8_t.

If one bit or 12 bits are sent, the data is going to be sent as a byte(s). When I worked with writing a ESP32 SPI library for the LSM9DS1, one of its data sends was 18 bits in size. Boy what a hair-pull that was, till I figured that I will still be getting bytes from the device but one of the bytes will not be completely full of data. And then to recreate the number, on a 32 bit MCU, not all of the 32 bits hold valid data.

hoangphithuong:
A few more details on my implementation: I have only 3 more pins available on DSPic and I allocated them for SCK, SDI, SDO, then connected them respectively to SCK, MOSI, MISO of Arduino UNO board (as I need to transfer on both direction, hope that's correct ?!) :o

CS?

If the DSPic has only SCK, SDI, and SDO then that's I2C and not SPI. You'll need one more pin for CS.

SCK to SCK clock to clock
Serial Data In goes to Master Out Slave In
Serial Data Out does to Master In Slave Out.

And

The Chip Select pin be?

Idahowalker:
CS?

If the DSPic has only SCK, SDI, and SDO then that's I2C and not SPI. You'll need one more pin for CS.

SCK to SCK clock to clock
Serial Data In goes to Master Out Slave In
Serial Data Out does to Master In Slave Out.

And

The Chip Select pin be?

The problem is that there are only 3 connectors remaining in the DSP card design and I think that we don't need SS (or CS) when there are only one slave, is that true ? If it's not the case, must I remove SDO-MISO to replace by SS, that means I only send data and cannot receive anything ?

johnwasser:
SPI always sends and receives at the same time. The 'transfer' where you use an array and a length replaces each byte being sent with the corresponding received byte.
When you send 'request' you should be aware that whatever was in the array will be replaced with whatever the other end sends when it has no data to send (typically zeroes). If you try to send that array again you will probably be sending zeroes. Re-fill the 'request' array before each send.
When you receive 'result', whatever values were in the array will be sent out. You should probably set the array contents to zeroes before you do the receive. Note: The datasheet for the device might say what dummy values to send when receiving data. If it does specify, use that value instead of zero.

Idahowalker:
My experience with SPI at the lower level is from using the ESP32 SPI API.

Still SPI is SPI.

SPI sends and receives in bytes, uint_8t or int8_t.

If one bit or 12 bits are sent, the data is going to be sent as a byte(s). When I worked with writing a ESP32 SPI library for the LSM9DS1, one of its data sends was 18 bits in size. Boy what a hair-pull that was, till I figured that I will still be getting bytes from the device but one of the bytes will not be completely full of data. And then to recreate the number, on a 32 bit MCU, not all of the 32 bits hold valid data.

Yeah actually I was wrong on understanding the use of SPI.transfer(buff,size). I believed that the buffer is an array of multiples uint16_t but it's actually a chain of bits. So I changed my idea to apply the following technique that I learnt from another topic:

  • I send firstly 3 datas (uint16_t) in the request by SPI.transfer16(data0-1-2) and no need to receive anything.
  • Then I send the 4th data by : uint16_t recv0 = SPI.transfer16(data3), in which recv0 is the first result I expect to receive.
  • Then I will receive next 11 results by sending 0 to DSP (in a for loop):
    uint16_t recv(1->11) = SPI.transfer16(0)
    Could you please confirm this technique ? Somehow, I have a problem that (as explained in others replies) : I have only 3 connectors in DSP card to connect to Arduino UNO, so I used SCK, MISO, MOSI and no place for SS. Is it possible to transfer data without using SS as I have only one slave ?
    Thank you again !

hoangphithuong:
The problem is that there are only 3 connectors remaining in the DSP card design and I think that we don't need SS (or CS) when there are only one slave, is that true ? If it's not the case, must I remove SDO-MISO to replace by SS, that means I only send data and cannot receive anything ?

Oi! If you can make SPI work without a CS go for it.

If you omit SS (or CS), then you run the risk of the receiving device losing sync with the transmitting device.

johnwasser:
SPI always sends and receives at the same time. The 'transfer' where you use an array and a length replaces each byte being sent with the corresponding received byte.
When you send 'request' you should be aware that whatever was in the array will be replaced with whatever the other end sends when it has no data to send (typically zeroes). If you try to send that array again you will probably be sending zeroes. Re-fill the 'request' array before each send.
When you receive 'result', whatever values were in the array will be sent out. You should probably set the array contents to zeroes before you do the receive. Note: The datasheet for the device might say what dummy values to send when receiving data. If it does specify, use that value instead of zero.

Hi, may I ask for another question that is how to create a buffer for 12 datas of 16 bits ? Is it possible to create a chain of 192 bits in Arduino ?

hoangphithuong:
how to create a buffer for 12 datas of 16 bits ?

uint16_t buffer[12];

hoangphithuong:
Is it possible to create a chain of 192 bits in Arduino ?

It depends on what you mean by a 'chain'. There are several ways to make a buffer of 192 bits:

uint8_t buffer8[24]; // 192 bits
uint16_t buffer16[12]; // 192 bits
uint32_t buffer32[6]; // 192 bits