6

I have an Arduino Due with a SAM3X8E chip and am trying to read SPI data from an external source that is communicating in SPI. I was able to get data by identifying specific bytes that are identifiers but realized that the clock for my board is not synced with the source coming in. I print out the bytes in hexadecimal format (08 00 FF AB etc) and each message is 128 bytes long.

To be clear, the source is an SPI master that is sending out data on its own MOSI line, but I am currently treating my board as a master as well since I do not know how to do Slave mode on Due. I connect the Slaves MOSI line to my boards MISO line, and just transfer data and read 128 bytes but it would appear that I am not getting the same data. Is there a way for my to take in the clock from the external clock and synchronize my board with that clock to make sure? My source code is below. The only methods I can think of are to either figure out how to implement the board in slave mode (i'm not familiar enough with the registers and how to change this, or read data in slave mode) or synchronize the clocks so my board is reading and sampling the source data correctly.

Could someone check if my thinking is correct, or do I not need to make any changes since the data is in a shift register?

Thanks


void setup(){
Serial.begin(9600);
SPI.begin();
SPISettings settings (50000000, LSBFIRST, SPI_MODE1); //Sampling rate    50Mhz, source's max speed
SPI.beginTransaction(settings);
}


void loop(){
  int i = 0;
  uint8_t value;
  value = SPI.transfer(0x00);
  while (value != 8){//searching for identifier 0x08
    value = SPI.transfer(0x00);
  }
  SPI.transfer(buffer, 127);//get the rest of the 127 bytes
  Serial.print(value, HEX);
  Serial.print(" ");
  for (i = 0; i < 127; i++){
    if (buffer[i] == 0){
      Serial.print(buffer[i],HEX);
      Serial.print(0, HEX);
    }
    else{
      Serial.print(buffer[i], HEX);
    }
    Serial.print(" ");
  }
  Serial.println("\n");
}
Majenko
  • 105,851
  • 5
  • 82
  • 139
wallenut
  • 63
  • 4

1 Answers1

3

For your external source to be an SPI bus master, it has to be the only one generating the clock signal. Yet, calling SPI.transfer() also generates a clock signal from the Arduino; both devices are attempting to drive the clock line simultaneously, hence your problems.

You have to bit-bang this or manipulate the SAM registers yourself to configure it as a slave; the SPI library doesn't support slave mode. In order to bit-bang, you'll have to define your own MOSI, SCK, SS (and MISO, if you'll be writing to the master) pins and do all the sampling yourself with digitalRead(); there are no registers to be read from since you aren't using the SAM's SPI peripheral.

Since your SPI mode is MODE 1, it means the clock idle polarity is LOW, and that data is sampled on the falling edge. To bit-bang with digitalRead(), it is necessary that the SCK frequency be below 50 kHz (digitalRead() takes about 4us), taking overhead into account. You should use direct port manipulation, if you need a higher frequency. If you'll be blocking till you've read data, and assuming that the external source always sends data in byte units, then a basic algorithm:

  1. Create a byte array to hold all the expected bytes
  2. Define a byte variable (curr_byte, maybe) for holding each byte received
  3. Wait till the SS pin goes LOW
  4. Clear curr_byte to zero
  5. Wait till SCK goes HIGH
  6. Wait till SCK goes LOW
  7. Read the bit on the MOSI line and shift it into curr_byte
  8. If you've received up to 8 bits so far, save curr_byte to the byte array; if SS is still LOW, go to step 4, else exit this loop. But if you haven't received a complete byte yet, go to step 5.

After you leave the loop, you can then confirm the bytes you've received with Serial. If the external device can send data with any number of bits, then you should always check the SS line after you shift in a bit, to determine if the Due has been deselected or not i.e. if there are any more incoming bits.

SoreDakeNoKoto
  • 2,422
  • 2
  • 14
  • 23