TRANSFER & RECEIVE from SLAVE to MASTER, using SPI.transfer16(unsigned int data)

Hello good afternoon
My name is Adrian, I am trying to learn about ARDUINO’s projects, and I I'm stuck about how to TRANSFER data between SLAVE to MASTER using SPI.

Initially I connected an ARDUINO NANO as MASTER to an ARDUINO ONE as SLAVE, using the pins ->
pin 10 (SS) -> Green
pin 11 (MOSI) -> Gray
pin 12 (MISO) -> Orange
pin 13 (SCK) -> Cyan

  • 5v (if required) -> Red
    GND (for signal return) -> Black

I have attached a squematic in PDF.

I have obtained these components in BANGGOOD:
Links: https://www.banggood.com/
-> Geekcreit® UNO R3 ATmega328P Development Board For Arduino No Cable
-> Geekcreit® ATmega328P Nano V3 Controller Board Compatible Arduino Improved Version Module

On my first POST I have received an answer on how transfer FLOATS using:

union{
  float rxmyTemp;
  byte rxmyTempArray[4];
} data1, data2;

but when I tried to send TWO float numbers between MASTER & SLAVE, I’ve got good transmission data, if both numbers was temperature data, but garbage if I intented to send temperature and humidity (also both float numbers), so I decide to investigate with SPI.transfer16(unsigned int data)
Perhaps, I have the same problem with the unsigned integer, so I try to explain with details...

Problem: TRANSFER & RECEIVE unsigned Integer from SLAVE to MASTER, using SPI.transfer16(unsigned int data)

When the MASTER requests it (sending ONE unsigned int <11>, or <12>, or not matter wich number send at this moment, I'll hope obtain an Unsigned INT, sending from the SLAVE, and watch the Receiving: masterSEND number in the Serial Monitor (COMM 10) associated to the MASTER.

SEND <11> I expect received
SEND <12> I expect received
SEND <13> I expect received

SEND <21> I expect received and so on...

In order to VERIFY what number is SENDING, and what number is RECEIVING, I thought that is was easy to SEND sequential Unsigned Integer from 250 to 800, viewing each pair of numbers at
• Slave Serial Monitor (COMM14) or
• Master Serial Monitor (COMM10).

Why 250 ¿???
Because, from [0 to 255], there was NO problem, the MSBFIRST byte, arraived from SLAVE to MASTER.

    //If I send -> 250(decimal) -> 00 00 00 FA (hex) -> FROM SLAVE >>>>>
    13:52:00.110 ->   slaveSEND= 250  
    13:52:00.110 ->   hex= 00 00 00 FA
    //  I MUST RECEIVED at MASTER <<<<<<<<<<<<<<<<<<<<<<<
    13:52:04.185 ->   masterRECEIVED= 64000   hex= 00 00 FA 00   Swap-> 250

IT IS WORK OK ¡!!!!!!!!!!!!!!!!!!!!!


but when I send 256 ...

    // 256 (decimal)  -> 00 00 01 00 (hex) -> FROM SLAVE >>>>>
    13:52:12.446 -> slaveSEND= 256
    13:52:12.446 ->   hex= 00 00 01 00
    // The number I received in hex was 00 00 00 00 (cero) not -> 00 00 01 00!!!!!
    13:52:16.523 -> [b]masterRECEIVED = 0   hex= 00 00 00 00[/b]  Swap-> 0

If you continue with the loop from [250 ->800], you could watch, what I’m watching in the Serial Monitor. These are the output from Master & Slave.

MASTER Output

13:43:27.399 -> Master-Digest-01cRandom.ino 
13:43:27.399 -> Versión N°: 01c 
13:43:27.435 -> Ultima modificación: 30/09/2019 09:30 
13:43:27.470 -> tA= 64768 hex= FD00 masterRECEIVED-> 253
13:43:29.499 -> tA= 32907 hex= 808B masterRECEIVED-> 35712
13:43:31.542 -> tA= 65024 hex= FE00 masterRECEIVED-> 254
13:43:33.618 -> tA= 256 hex= 100 masterRECEIVED-> 1
13:43:35.662 -> tA= 512 hex= 200 masterRECEIVED-> 2
13:43:37.694 -> tA= 768 hex= 300 masterRECEIVED-> 3

// was removed for space !!!!!!!!!!!!!

13:52:04.185 -> tA= 64000 hex= FA00 masterRECEIVED-> 250
13:52:06.228 -> tA= 64256 hex= FB00 masterRECEIVED-> 251
13:52:08.306 -> tA= 64512 hex= FC00 masterRECEIVED-> 252
13:52:10.338 -> tA= 64768 hex= FD00 masterRECEIVED-> 253
13:52:12.379 -> tA= 65024 hex= FE00 masterRECEIVED-> 254
13:52:14.447 -> tA= 65280 hex= FF00 masterRECEIVED-> 255
13:52:16.523 -> tA= 0 hex= 0 masterRECEIVED-> 0
13:52:18.550 -> tA= 256 hex= 100 masterRECEIVED-> 1
13:52:20.612 -> tA= 512 hex= 200 masterRECEIVED-> 2
13:52:22.647 -> tA= 768 hex= 300 masterRECEIVED-> 3
13:52:24.681 -> tA= 1024 hex= 400 masterRECEIVED-> 4

SLAVE Output

13:43:30.292 -> Slave-Digest-01c.ino
13:43:30.292 -> Versión N°: 01c
13:43:30.327 -> Ultima modificación: 30/09/2019 09:30
13:43:31.609 -> slaveSEND= 2
13:43:33.659 -> slaveSEND= 3

// ... was removed for space !!!!!!!!

13:52:08.346 -> slaveSEND= 254
13:52:10.411 -> slaveSEND= 255
13:52:12.446 -> slaveSEND= 256
13:52:14.513 -> slaveSEND= 257

I know that I must make a MISTAKE on my code, but I couldn’t find it, so if anybody could run it, perhaps show me the error, in the code, or in the CONCEPT of transfer data using SPI.transfer16(unsigned int data)
Well, this part is where I get lost.

Thank you very much for your time, I'll hope receive any suggest

Best regards,
Adrian
(Spanish spoken)

MasterSlave_SPI.Transfer16.pdf (710 KB)

Master_S_Transfer16.ino (11.8 KB)

Slave_M_Transfer16.ino (4.33 KB)

tempDHT11.H (4.23 KB)

You send and receive one byte at a time. The SPDR register is only 8 bits wide. If you use SPI.write16() this method just calls SPI.write() twice. On the reception side you must read one byte after the other. If that's done in an interrupt you have to take care that you declare all variables shared between normal execution and interrupt handler as "volatile".

I hope that you understand well the working principle of SPI Communication Protocol with reference to the following diagram. SPI is a byte oriented protocol; where you read arrived data once it is ready, and it is known from the HIGH status value of the SPIF flag of SPSR Register. If interrupt structure has been enabled, then you can read the arrived data on interrupt process -- an strategy that is usually used in the SPI protocol.
spi328x.png

Can you please, post the sketch that worked for you to exchange one unit float data. I will try to expand that one for your DHT11 sensor.

spi328x.png

Pylon&Mostafa
Thank you so much for your quickly answer, I was very bussy at work, so the hobbie must stand alone for a few days.
These are the codes from Master & SLAVE trying to SEND and RECEIVED an unsigned integer.

RESUME:
I want to send from MASTER:

a) 11 -> requesting an Unsigned INTEGER sequential number [250, 270]
b) 12 -> requesting an Unsigned INTEGER sequential number [1250, 1230]

At SLAVE, you could watch at Output, it seem it is OK
At MASTER, I tried and I have a mistake.
I understand that I need to read TWICE, because SPI.transfer16(uint data) have a wide of ONE BYTE, but I do not HOW.

So please, could you show me how to change the code?

Because of the 9000 characters limits, I have attached the code, best regards

Adrian

SLAVE Output

Slave_M_Transfer16b.ino
13:58:11.153 -> Version N°: 16b
13:58:11.278 -> Last modification: 07/10/2019 10:00
13:58:13.169 -> N°= 1250
13:58:13.169 -> 000004E2
13:58:15.139 -> N°= 250
13:58:15.139 -> 000000FA
13:58:19.172 -> N°= 251
13:58:19.172 -> 000000FB
13:58:23.157 -> N°= 252
13:58:23.157 -> 000000FC
13:58:27.142 -> N°= 1249
13:58:27.142 -> 000004E1
13:58:29.159 -> N°= 1248
13:58:29.159 -> 000004E0
13:58:31.175 -> N°= 1247
13:58:31.175 -> 000004DF
13:58:33.144 -> N°= 1246
13:58:33.144 -> 000004DE
13:58:35.162 -> N°= 253
13:58:35.162 -> 000000FD
13:58:37.131 -> N°= 1245
13:58:37.131 -> 000004DD
13:58:39.149 -> N°= 254
13:58:39.149 -> 000000FE
13:58:43.133 -> N°= 1244
13:58:43.133 -> 000004DC
13:58:45.149 -> N°= 255
13:58:45.149 -> 000000FF
13:58:47.166 -> N°= 256
13:58:47.166 -> 00000100
13:58:49.135 -> N°= 257
13:58:49.135 -> 00000101
13:58:53.166 -> N°= 1243
13:58:53.166 -> 000004DB
13:58:55.137 -> N°= 1242
13:58:55.137 -> 000004DA
13:59:03.153 -> N°= 1241
13:59:03.153 -> 000004D9
13:59:07.140 -> N°= 258
13:59:07.140 -> 00000102
13:59:09.157 -> N°= 1240
13:59:09.157 -> 000004D8
13:59:11.172 -> N°= 1239
13:59:11.172 -> 000004D7
13:59:13.141 -> N°= 259
13:59:13.141 -> 00000103
13:59:15.157 -> N°= 260
13:59:15.157 -> 00000104
13:59:17.153 -> N°= 1238
13:59:17.153 -> 000004D6
13:59:21.158 -> N°= 1237
13:59:21.158 -> 000004D5
13:59:23.162 -> N°= 261
13:59:23.162 -> 00000105
13:59:29.170 -> N°= 1236
13:59:29.170 -> 000004D4
13:59:31.140 -> N°= 1235
13:59:31.140 -> 000004D3
13:59:37.130 -> N°= 1234
13:59:37.130 -> 000004D2
13:59:41.123 -> N°= 262
13:59:41.123 -> 00000106
13:59:47.136 -> N°= 1233
13:59:47.136 -> 000004D1
13:59:49.150 -> N°= 263
13:59:49.150 -> 00000107
13:59:53.126 -> N°= 264
13:59:53.126 -> 00000108
13:59:57.128 -> N°= 265
13:59:57.128 -> 00000109
14:00:01.164 -> N°= 1232
14:00:01.164 -> 000004D0
14:00:03.134 -> N°= 1231
14:00:03.134 -> 000004CF
14:00:05.123 -> N°= 1250
14:00:05.123 -> 000004E2
14:00:07.139 -> N°= 1249
14:00:07.139 -> 000004E1
14:00:09.158 -> N°= 266
14:00:09.158 -> 0000010A

MASTER Output

13:59:27.248 -> Master_S_Transfer16b.ino
13:59:27.248 -> Version N°: 16b
13:59:27.248 -> Last modification: 07/10/2019 10:00
13:59:27.294 -> mSEND= 12
13:59:27.294 -> 4
13:59:27.294 -> ___________________________
13:59:29.310 -> mSEND= 12
13:59:29.357 -> 1
13:59:29.357 -> ___________________________
13:59:31.327 -> mSEND= 13
13:59:31.421 -> 4
13:59:31.421 -> ___________________________
13:59:33.378 -> mSEND= 13
13:59:33.472 -> 4
13:59:33.472 -> ___________________________
13:59:35.442 -> mSEND= 12
13:59:35.536 -> 4
13:59:35.536 -> ___________________________
13:59:37.505 -> mSEND= 13
13:59:37.552 -> 4
13:59:37.552 -> ___________________________
13:59:39.553 -> mSEND= 11
13:59:39.600 -> 4
13:59:39.600 -> ___________________________
13:59:41.592 -> mSEND= 13
13:59:41.686 -> 4
13:59:41.686 -> ___________________________
13:59:43.655 -> mSEND= 13
13:59:43.702 -> 1
13:59:43.702 -> ___________________________
13:59:45.704 -> mSEND= 12
13:59:45.751 -> 1
13:59:45.751 -> ___________________________
13:59:47.746 -> mSEND= 11
13:59:47.840 -> 1
13:59:47.840 -> ___________________________
13:59:49.806 -> mSEND= 13
13:59:49.853 -> 4
13:59:49.853 -> ___________________________
13:59:51.861 -> mSEND= 11
13:59:51.907 -> 1
13:59:51.907 -> ___________________________
13:59:53.903 -> mSEND= 13
13:59:53.950 -> 1
13:59:53.950 -> ___________________________
13:59:55.967 -> mSEND= 11
13:59:56.013 -> 1
13:59:56.013 -> ___________________________
13:59:58.019 -> mSEND= 13
13:59:58.065 -> 1
13:59:58.065 -> ___________________________
14:00:00.050 -> mSEND= 12
14:00:00.144 -> 1
14:00:00.144 -> ___________________________
14:00:02.102 -> mSEND= 12
14:00:02.195 -> 1
14:00:02.195 -> ___________________________
14:00:04.139 -> mSEND= 12
14:00:04.233 -> 4
14:00:04.233 -> ___________________________
14:00:06.202 -> mSEND= 12
14:00:06.295 -> 4
14:00:06.295 -> ___________________________
14:00:08.265 -> mSEND= 11
14:00:08.312 -> 4
14:00:08.312 -> ___________________________

Master_S_Transfer16b.ino (6.49 KB)

Slave_M_Transfer16b.ino (5.5 KB)

tempDHT11.H (4.23 KB)

There are two major mistakes in the code.
First, your ISR is called after the first byte has been transferred from the master to the slave. So if you want to send 2 bytes back to the master you have to call SPI.transfer() at least 3 times on the master (transfer16() is the same as twice transfer()).
Second, you cannot read the SPDR register in the loop. It might have a completely different value at that time.

So your ISR have to be something like this:

volatile command = 0;
volatile union{
  int T;
  byte myArray[2];  
} data;


ISR (SPI_STC_vect) {
  if (i == 0) {
    command = SPDR;
    if (command == 11) data = seqNumber;
    if (command == 12) data = seqNumber1;
  }
  SPDR = data.myArray[i];
  i++;
  if (i == 2){
    i = 0;
  }
  dataRECEIVED = true;                        
}

Pylon, good afternoon
Thank you very much for your help, I'll run the code tonight.

Only another doubt, at the Master CODE, do I need to make one or two calls to SPI.transfer16(uint data) ?

In order to view two bytes = ONE unsigned integer !!!!!!!!

//  ONLY ONE CALL to SPI.transfer16() ???????????????
//
    unsigned int masterRECEIVED = SPI.transfer16(data.myTemp);    
    
    Serial.print(F("\t mRECEIVED-> "));
    uint8_t isOK = sprintf(buff,"%.8X",masterRECEIVED);

If Master SEND <12> and the SLAVE received OK, should I see at MASTER side (e.g. masterRECEIVED=1240) and on Serial Monitor <00 00 04 D8> ???

Or I need to make two calls to:

//    FIRST call

unsigned int masterRECEIVED = SPI.transfer16(data.myTemp);

//    SECOND call                   
masterRECEIVED = SPI.transfer16(data.myTemp);

Best regards,
Adrian

aruffato:
RESUME:
I want to send from MASTER:

a) 11 -> requesting an Unsigned INTEGER sequential number [250, 270]
b) 12 -> requesting an Unsigned INTEGER sequential number [1250, 1230]

a) Master sends 11 (0x0B) to Slave; in return, Master receives 250 (0xFA) and 270 (0x010E)
Screen shot:
smSpi.png
Figure-1:

Codes:
Master-UNO

#include <SPI.h>
byte myData[] = {11, 0x00, 0x00, 0x00};
void setup (void)
{
  Serial.begin(115200);
  SPI.begin ();
  digitalWrite(SS, LOW);    //Slave is selected
  SPI.setClockDivider(SPI_CLOCK_DIV32);  //500 Kbits/sec
  delay(100);
  //-----------------------------------------
  for (int i = 0; i < 4; i++)
  {
    myData[i] = SPI.transfer(myData[i]);
    delay(1);
  }
  Serial.print("Received data in response of 11: ");
  Serial.print(myData[1], DEC);
  Serial.print(" and ");
  Serial.println((myData[2] << 8 | myData[3]), DEC);
}

void loop()
{

}

Slave-NANO

#include <SPI.h>
volatile bool flag1 = false;
byte myData[] = {0xFA, 0x01, 0x0E};
int i = 0;
byte x;

void setup ()
{
  Serial.begin(115200);
  pinMode(SS, INPUT_PULLUP);  // ensure SS stays high for now
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= !(_BV(MSTR)); //Arduino is Slave
  SPCR |= _BV(SPIE); //SPI.attachInterrupt();
  sei();
  SPDR = 0x67;  //test value to be returned to Master at the very call#1 of byte x = SPI.transfer.
  // delay(100);
}

void loop()
{

}

ISR(SPI_STC_vect)
{
  if (flag1 == false)
  {
    x = SPDR;
    if (x == 11)
    {
      flag1 = true;
    }
  }
  SPDR = myData[i];
  i++;
  if (i == 3)
  {
    flag1 = false;
    i = 0;
  }
}

b) Master sends 12 to Slave; in return, Master receives 1250 (0x04E2) and 1230 (0x04CE)
The solution is the straight forward extension of the codes of Step-a.

smSpi.png

Only another doubt, at the Master CODE, do I need to make one or two calls to SPI.transfer16(uint data) ?

I wouldn't use that method at all as it makes you think that it does something special. Use only the SPI.transfer() function to transmit one byte and receive one byte but keep in mind that the first byte from the slave will be received in the second call of SPI.transfer()!

So you may transmit a 16 bit integer to the slave by sending the first byte in call #1, the second in call #2. The response of the slave will be in the return value of call #2 (first byte) and call #3 (second byte).