Basic SPI Question (beginner)

Hello Everyone!

I'm new to Arduino and the forum and I'm working on a project involving SPI communications with a gyroscope. I'm following the Barometer example, but am having some trouble understanding how everything works. The sensor is an ADIS16080 from Analog Devices. I know this is a lot to ask- but could I have some help with the questions below.

How do I get 2 pieces of data from the sensor into tempData and velocityData, respectively?

Here's what I have...

[size=8pt]#include <SPI.h>
const int VELOCITY = 0x31;  //12 bit velocity reading
const int TEMP = 0x71;   //12 bit temperature reading
const byte READ_1 = 0x56;     // iSensor set format gyro command offset binary
const byte READ_2 = 0x00;  // Second half of read information

// pins used for the connection with the sensor
const int dataReadyPin = 6;
const int chipSelectPin = 7;

void setup() {
  Serial.begin(9600);

  // start the SPI library:
  SPI.begin();

  // initalize the  data ready and chip select pins:
  pinMode(dataReadyPin, INPUT);
  pinMode(chipSelectPin, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  SPI.setBitOrder(MSBFIRST);

  // give the sensor time to set up:
  delay(100);
}

void loop() {

  // don't do anything until the data ready pin is high:
  if (digitalRead(dataReadyPin) == HIGH) {
    // Read the temperature data
    int tempData = readRegister(0x21, 2);
    // Read the velocity data
    int velocityData = readRegister(0x20, 2);
   }
}
// Read from temperature register on iSensor
unsigned int readRegister(byte thisRegister, int bytesToRead ) {
  byte inByte = 0;           // incoming byte from the SPI
  unsigned int result = 0;   // result to return
  byte dataToSend = READ_T;
  Serial.println(thisRegister, BIN);
  // take the chip select low to select the device:
  digitalWrite(chipSelectPin, LOW);
  // send the device the register you want to read:
  SPI.transfer(dataToSend);
  // send a value of 0 to read the first byte returned:
  result = SPI.transfer(0x00);
  // decrement the number of bytes left to read:
  bytesToRead--;
  // if you still have another byte to read:
  if (bytesToRead > 0) {
    // shift the first byte left, then get the second byte:
    result = result << 8;
    inByte = SPI.transfer(0x00);
    // combine the byte you just got with the previous one:
    result = result | inByte;
    // decrement the number of bytes left to read:
    bytesToRead--;
  }
  // take the chip select high to de-select:
  digitalWrite(chipSelectPin, HIGH);
  // return the result:
  return(result);
}
}
//Read from velocity register on iSensor:
unsigned int readRegister(byte thisRegister, int bytesToRead ) {
  byte inByte = 0;           // incoming byte from the SPI
  unsigned int result = 0;   // result to return
  byte dataToSend = READ_V;
  Serial.println(thisRegister, BIN);
  // take the chip select low to select the device:
  digitalWrite(chipSelectPin, LOW);
  // send the device the register you want to read:
  SPI.transfer(dataToSend);
  // send a value of 0 to read the first byte returned:
  result = SPI.transfer(0x00);
  // decrement the number of bytes left to read:
  bytesToRead--;
  // if you still have another byte to read:
  if (bytesToRead > 0) {
    // shift the first byte left, then get the second byte:
    result = result << 8;
    inByte = SPI.transfer(0x00);
    // combine the byte you just got with the previous one:
    result = result | inByte;
    // decrement the number of bytes left to read:
    bytesToRead--;
  }
  // take the chip select high to de-select:
  digitalWrite(chipSelectPin, HIGH);
  // return the result:
  return(result);
}[/size]

(code tags added by moderator)

That's very difficult to read, and therefore people are not inclined to do so, can you put it into [ code] tags?

But one thing, aren't there two identical functions called readRegister()? A bad cut and paste job or a new C++ feature?


Rob

where you read the tempdata and velocity data, those variables are only going to be in scope in that 2 line code block. This may not be what you actually want.

theironspud:
How do I get 2 pieces of data from the sensor into tempData and velocityData, respectively?

Without reading the data sheet myself, basically each SPI.transfer sends something and receives something at the same time. So you need to send some initial data (eg. what you want to get) and then receive it, and ask for something else.

Again, totally without looking at how this device works, something like this:

  SPI.transfer (read_temp);
  byte temperature = SPI.transfer (read_velocity);
  byte velocity = SPI.transfer (0);

So each transfer reads the thing you requested previously. Of course the data sheet might specify that commands are two bytes, so you need to read what it says, and it probably has examples.

I did a writeup on SPI here:

Nick- thanks a lot for this. That was exactly what I was looking for.

Thanks to everyone else too (although, for sure, I'll be back :))

I'm playing my "newbie" status card again here, so please bear with me.

Each command and response is two bytes, and I believe that there is only one read per clock cycle allowed.

So, if the command "5600" for temp and "5700" for velocity, would my code need to look like this?

if (digitalRead(dateReadyPin) == LOW {
digitalWrite(chipSelectPin, LOW);
SPI.transfer (0x56);
byte temp_high = SPI.transfer (0x00);
byte temp_low = SPI.transfer(0);
digitalWrite(chipSelectPin, HIGH);
} 

delay(100);

if (digitalRead(dateReadyPin) == LOW {
digitalWrite(chipSelectPin, LOW);
SPI.transfer (0x57);
byte velocity_high = SPI.transfer (0x00);
byte velocity_low = SPI.transfer (0);
digitalWrite(chipSelectPin, HIGH);
}

Almost. See page 12 of the datasheet. It seems to work in 16 bit quantities, so you send 16 bytes (two transfers) and get the reply in the next two transfers. During that second two you could be requesting the next reply and so on.

Also note their comments about "use a clock phase setting of 0 and a clock polarity setting of 1.".

I think you will need this in setup:

SPI.setDataMode(SPI_MODE2);

So to get the temperature you send 16 bits and receive 16 bits:

digitalWrite(chipSelectPin, LOW);
SPI.transfer (0x56);   // request temperature
SPI.transfer (0x00);
byte temp_high = SPI.transfer (0);  // get temperature
byte temp_low = SPI.transfer(0);
digitalWrite(chipSelectPin, HIGH);

I must say that I don't see 0x5600 as being "get the temperature" but I'll let you work it out from the bit patterns on page 13.

I just wanted to share what finally worked. Thank you for your help Nick.

#include <SPI.h>
const int CS = 7;
const int DR = 6;
void setup (){
  Serial.begin(9600);
  SPI.begin();
  pinMode(CS, OUTPUT);
  pinMode(DR, INPUT);
  delay(100);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV8);
  digitalWrite(CS, HIGH);
  delay(1000);  
}
void loop()
 
{  
if(digitalRead(DR) == HIGH); 
{digitalWrite(CS, LOW);
byte resultHigh = SPI.transfer(0x56);
byte resultLow = SPI.transfer(0x00);
 
digitalWrite(CS, HIGH);
int dev_high = (int) resultHigh << 8;
int device_ID = dev_high | (int)resultLow;
Serial.println(device_ID);
}
delay(500);
}