SPI read problem, IMU unit ADIS16354

Hello i have problem with reading data from senzor ADIS 16354 (datasheet http://www.analog.com/static/imported-files/data_sheets/ADIS16354.pdf)
I have Arduino Duemilanove
I try read data from X accelerometer for this example.

Here is mi code

pin 10               
CS -     SS - vo?ba SPI zariadenia            
pin 11               DIN -    MOSI - Master-out, Slave-in - digitálny vstup, slúži na zápis dát z Arduina do senzora  
pin 12               DOUT -   MISO - Master-in, Slave out - digitálny výstup, slúži na ?ítanie dát zo senzora do Arduina
pin 13               SCK -    SCLK - Serial clock - nastavenie hodín a frekvencie
#define SUPPLY_OUT 		0X02
#define XGYRO_OUT		0X04
#define YGYRO_OUT 		0X06
#define ZGYRO_OUT 		0X08
#define XACCL_OUT 	 	0X0A
#define YACCL_OUT 		0X0C
#define ZACCL_OUT 		0X0E
#define XTEMP_OUT		0X10
#define YTEMP_OUT 		0X12
#define ZTEMP_OUT 		0X14
#define AUX_ADC 		0X16
// tieto adresy registrov slúžia na ?ítanie hodnôt z jednotlivých senzorov

#define XGYRO_OFF		0X1A
#define YGYRO_OFF		0X1C
#define ZGYRO_OFF		0X1E
#define XACCL_OFF		0X20
#define YACCL_OFF		0X22
#define ZACCL_OFF		0X24
#define ALM_MAG1		0X26
#define ALM_MAG2		0X28
#define ALM_SMPL1		0X2A
#define ALM_SMPL2		0X2C
#define ALM_CTRL		0X2E
#define AUX_DAC			0X30
// nastavenie a kalibrácia senzora, po zápise hodnôt (pozri datasheet senzora) sa zmenia nastavenia senzora

#define GPIO_CTRL		0X32
#define MSC_CTRL		0X34
#define SMPL_PRD		0X36    // TS = TB × (NS + 1) 

#define SENS/AVG		0X38
#define SLP_CNT			0X3A
#define STATUS			0X3C
#define COMMAND			0X3E
*/
#include <SPI.h>

int ss=10; // vyberieme SPI zariadenie, kedže sa používa iba jedno bude stále  táto hodnota nastavená na 10
byte hi;
byte lo;
word data;

void setup()
{
  pinMode(ss, LOW); // používa sa pin 10
  SPI.begin(); // inicialuzuje sa SPI

  SPI.setBitOrder(MSBFIRST);
  // senzor posle najskor MSB (most significant byte) bit ako prvý
}

void loop()
{

 //read x
 digitalWrite(ss,LOW);
 hi=SPI.transfer(0x0b);
 lo=SPI.transfer(0x0a);
 digitalWrite(ss,HIGH);
 data=((hi<8)+lo);
 data &= 0b0011111111111111;
 data<<=2;
 data>>=2;
 double xacc=data*0.4672;

 Serial.begin (9600);
 Serial.print("X Accel: ");
 Serial.print(xacc);
 Serial.println("mg");

 delay(100);

}

Here is data from serial monitor, almost all the same, even if the sensor moves

X Accel: 0.47mg
X Accel: 0.47mg
X Accel: 0.47mg
X Accel: 29.43mg
X Accel: 0.47mg
X Accel: 29.43mg
X Accel: 0.47mg
X Accel: 27.10mg
X Accel: 4.67mg
X Accel: 4.67mg
X Accel: 4.67mg
X Accel: 0.47mg

Change vary wildly.
What's wrong?

data=((hi<8)+lo);

hi < 8 ?

data=((hi<<8) | lo);

perhaps.

data=((hi<<8) | lo);

I changed specific line.
Here is result:

X Accel: 0.00mg
X Accel: 4549.13mg
X Accel: 0.00mg
X Accel: 4549.59mg
X Accel: 0.00mg
X Accel: 4549.13mg
X Accel: 0.00mg
X Accel: 4548.66mg
X Accel: 0.00mg
X Accel: 4549.13mg
X Accel: 0.00mg

I dont move with senzor and data still flowing.
It is another way to read this address and then print its value through serial.print?
Here is example read cycle from datasheet:

Put Serial.begin (9600); in setup not loop. I don't know if that has any bad effect but it ain't right where it is.

BTW, what does

data<<=2;
data>>=2;

do?


Rob

I've had a further look

hi=SPI.transfer(0x0b);
lo=SPI.transfer(0x0a);

hi will be crap because at this point the device hasn't received an address. My guess is that then you do the 0x0a transfer you get the data for 0x0b. I'd have to look at the IMU data sheet to get a better idea.


Rob

Based on a very quick look I think you do this

lo=SPI.transfer(0x0b); // get whatever crap is there from last transfer
lo=SPI.transfer(0x0a); // get low byte
hi=SPI.transfer(0x0); // get high byte, data sent doesn't matter

Normally with SPI unless the slave has preloaded the output reg the first transfer returns any old crap.

I'll continue to look at the data sheet though.


Rob

I've had a better look and basically I think you were doing the right thing, each reading would have got data from the preceeding command but that doesn't matter. There was one possible other error though

pinMode(ss, LOW);

is wrong but may have worked depending on the values for LOW and OUTPUT

Here's a slightly modified version of your code, I've removed stuff that doesn't help like xacc=data*0.4672 so we can see raw data for the time being.

#include <SPI.h>

int ss=10; // vyberieme SPI zariadenie, kedže sa používa iba jedno bude stále  táto hodnota nastavená na 10
byte hi;
byte lo;
word data; 

void setup()
{
  Serial.begin (9600);
  pinMode(ss, LOW); // používa sa pin 10
  
  SPI.begin(); // inicialuzuje sa SPI

  SPI.setBitOrder(MSBFIRST);  // is MSBFIRST correct ??
  // senzor posle najskor MSB (most significant byte) bit ako prvý
  
 hi=SPI.transfer(0x0a);  // set the IMU to read so the next command will get valid data
 lo=SPI.transfer(0x0);
}

void loop()
{

 //read x
 digitalWrite(ss,LOW);
 hi=SPI.transfer(0x0a);
 lo=SPI.transfer(0x0);   // this value doesn't matter
 digitalWrite(ss,HIGH);
 data=((hi<<8)+lo);
 //data &= 0b0011111111111111;   // this shouldn't be needed, leave it out for the moment
 //data<<=2;		// don't know what this does
 //data>>=2;
 
 //double xacc=data*0.4672;  // let's just work with raw data for starters

 Serial.print("X Accel: ");
 Serial.print(((hi<<8)+lo), HEX);
 //Serial.println("mg");

 delay(100);

}

Try this and see what happens.


Rob

Hello
I use your code and here is result :

X Accel: FFFFE7FE
X Accel: 0
X Accel: FFFFE7FD
X Accel: 0
X Accel: FFFFE7FD
X Accel: 0
X Accel: FFFFE7FD
X Accel: 0
X Accel: FFFFE7FD
X Accel: 0
X Accel: FFFFE7FD
X Accel: 0
X Accel: FFFFE7FE
X Accel: 0
X Accel: FFFFE7FE
X Accel: 0

No change, same value repeating
When the sensor moves, the data is changed somewhere

X Accel: FFFFC017
X Accel: A1F
X Accel: A3F
X Accel: 0
X Accel: A3F
X Accel: 0
X Accel: 0
X Accel: A3F
X Accel: 0
X Accel: 0

Would it be possible that you need more time after?:

 digitalWrite(ss,LOW);

Before you request:

 hi=SPI.transfer(0x0a);

You could try adding a small delay to see if that helps.

I added:
delayMicroseconds(160); - 160micro s is in datasheet at normal mode (i use normal mode)
Sensor sends almost the same values.
Any ideas?

This doesn't look right:

  digitalWrite(ss,LOW);
 hi=SPI.transfer(0x0a);
 lo=SPI.transfer(0x0);   // this value doesn't matter
 digitalWrite(ss,HIGH);

Rob seemed to realize this, but then posted the code above.

Using SPI, you can't request and receive in the same transfer. That is because each bit is sent and received at the same time.

So at the very least (and without reading the data sheet at great length, and checking timings) you would need:

 digitalWrite(ss,LOW);
 SPI.transfer(0x0a);   // request register 0x0A
 hi=SPI.transfer(0x0b);  // receive 0x0A, request 0x0B
 lo=SPI.transfer(0x0);   // receive 0x0B
 digitalWrite(ss,HIGH);

However after reading page 13 of the datasheet it says:

Reading the contents of a register requires a modification to the sequence illustrated in Figure 27. In this case, the first two bits in the DIN sequence are 0, followed by the address of the register. Each register has two addresses (an upper address and a lower address), but either one can be used to access the entire 16 bits of data. The final eight bits of the DIN sequence are irrelevant and can be counted as don’t cares during a read command.

Based on that, and the diagram, it looks like you send 16 bits, and then receive 16 bits, more like this:

 digitalWrite(ss,LOW);
 SPI.transfer(0x0a);   // request register 0x0A
 SPI.transfer (0);  // don't care
 hi=SPI.transfer(0x0a);  // request again, receive high
 lo=SPI.transfer(0x0);   // receive low, send don't care
 digitalWrite(ss,HIGH);

Because of this design, for each two bytes, you request something (which you receive two bytes later) and receive something (which you requested two bytes back).

I think the after the first two transfers everything works in pairs, send two, get two from the last send. So I did two in setup() then two in every loop().

But that obviously isn't working so I'll have another look at the DS, I still think it's right though :~

EDIT: How fast are you allowed to read this IMU, maybe 10x a second is too fast, try changing delay(100) to delay(1000).


Confused

Graynomad:
I think the after the first two transfers everything works in pairs, send two, get two from the last send. So I did two in setup() then two in every loop().

You might be right about doing that in setup. But you need to bring SS low if you are, otherwise it will ignore the attempt to do the first address setup.

The ~CS line enables the ADIS16354 SPI port and frames each SPI event. When this signal is high, the DOUT line is in a high impedance state and the signals on DIN and SCLK have no impact on operation.

But you need to bring SS low if you are, otherwise it will ignore the attempt to do the first address setup.

Correct.

Just looking deaper into the data sheet

CONVERSION RATE
Maximum Sample Rate SMPL_PRD = 0x01 819.2 SPS
Minimum Sample Rate SMPL_PRD = 0xFF 0.413 SPS

That implies to me that the best you can do is one reading every 413mS, that doesn't explain why every second one seems to work though, if it had been every 4th one I'd be happier that that is the problem, but maybe it just works better than advertised.


Rob

I do not have where or how to check if it works correctly. I'm learning to read values ??from one register, I will read the data from the X, Y, Z accelerometer, and X Y Z gyroscope. And view them in serial monitor, or save in file to HDD.
When I read the temperature (address 0x10 XTEMP_OUT) with my program ,doing the same as reading accel addresses.
I found the source code in C, the sensor is on the higher range (ADIS16355) for lower (ADIS16350).
If it helped someone, I do not know much about at that.

ExampleCode_DDS_ADIS16350Driver.zip (69.4 KB)

ExampleCode_DDS_ADIS16355Driver.zip (66.3 KB)

Did you try increasing the delay?


Rob

mmichalll:
I do not have where or how to check if it works correctly.
...
If it helped someone, I do not know much about at that.

I don't know here if he is saying it works, it doesn't work, or he doesn't know if it works or not.

Me 2.


Rob

My code work.
Reading the values, but I do not know if the correct.
I modifi code, i read x, y, z accel,, x, y, z gyro,, and x,y,z temperature.
I increase delay slightly.

Here is code: code work read values - values ??probably are not all right

/*
Arduino Duemilanove and Tri axis senzor ADIS16354
Datasheet: 
http://www.analog.com/static/imported-files/data_sheets/ADIS16354.pdf

pin 10               CS -     SS - vo?ba SPI zariadenia            
pin 11               DIN -    MOSI - Master-out, Slave-in - digitálny vstup, slúži na zápis dát z Arduina do senzora  
pin 12               DOUT -   MISO - Master-in, Slave out - digitálny výstup, slúži na ?ítanie dát zo senzora do Arduina
pin 13               SCK -    SCLK - Serial clock - nastavenie hodín a frekvencie
*/

#include <SPI.h>

int ss=10; // vyberieme SPI zariadenie, kedže sa používa iba jedno bude stále  táto hodnota nastavená na 10
byte ax, ay, az;
byte gx, gy, gz;
byte tx, ty, tz;
word datax, datay, dataz; 
word dataxg, datayg, datazg;
word dataxt, datayt, datazt;
word data;

void setup()
{
  Serial.begin (9600);
  pinMode(ss, LOW); // používa sa pin 10
  SPI.begin(); // inicialuzuje sa SPI
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(MSBFIRST);  // is MSBFIRST correct ??
  // senzor posle najskor MSB (most significant byte) bit ako prvý
 digitalWrite (SMPL_PRD, 0x0A);
 //SPI.transfer(0x0a);  // set the IMU to read so the next command will get valid data
 //SPI.transfer(0x0b);
}

void loop()
{
 //=================================================
 // Accelerometer read data
 //=================================================
 //read x accel
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 ax=SPI.transfer(0x0a);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 datax=(ax<<8);
 Serial.print("X Accel: ");
 Serial.print(datax, DEC);
 Serial.print("\t");
 delay(200);
//=================================================
 //read y accel
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 ay=SPI.transfer(0x0c);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 datay=(ay<<8);
 Serial.print("Y Accel: ");
 Serial.print((ay<<8), DEC);
 Serial.print("\t");
 delay(200);
//=================================================
 //read z accel
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 az=SPI.transfer(0x0e);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 dataz=(az<<8);
 Serial.print("Z Accel: ");
 Serial.println((az<<8), DEC);
 delay(200);
 
 //=================================================
 // Gyroscope read data
 //=================================================
 
 //read x gyro
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 gx=SPI.transfer(0x04);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 dataxg=(gx<<8);
 Serial.print("X Gyro: ");
 Serial.print(dataxg, DEC);
 Serial.print("\t");
 delay(200);
 //================================================= 
 //read y gyro
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 gy=SPI.transfer(0x06);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 datayg=(gy<<8);
 Serial.print("Y Gyro: ");
 Serial.print((gy<<8), DEC);
 Serial.print("\t");
 delay(200);
 //================================================= 
 //read Z gyro
 digitalWrite(ss,LOW);
 delayMicroseconds(160);
 gz=SPI.transfer(0x08);
 delayMicroseconds(160);
 digitalWrite(ss,HIGH);
 datazg=(gz<<8);
 Serial.print("Z Gyro: ");
 Serial.println((gz<<8), DEC);
 delay(200);
 
 //=================================================
 // Temperature read data --- ?ítanie teploty
 //=================================================
 
 //read x temp
 digitalWrite(ss,LOW);
 delayMicroseconds(200);
 tx=SPI.transfer(0x10);
 delayMicroseconds(200);
 digitalWrite(ss,HIGH);
 dataxt=(tx<<8);
 Serial.print("X Teplota: ");
 Serial.print((tx<<8), DEC);
 Serial.print("\t");
 delay(200);
//=================================================
 //read y temp
 digitalWrite(ss,LOW);
 delayMicroseconds(200);
 ty=SPI.transfer(0x12);
 delayMicroseconds(200);
 digitalWrite(ss,HIGH);
 datayt=(ay<<8);
 Serial.print("Y Teplota: ");
 Serial.print((ty<<8), DEC);
 Serial.print("\t");
 delay(200);
//=================================================
 //read z temp
 digitalWrite(ss,LOW);
 delayMicroseconds(200);
 tz=SPI.transfer(0x14);
 delayMicroseconds(200);
 digitalWrite(ss,HIGH);
 datazt=(tz<<8);
 Serial.print("Z Teplota: ");
 Serial.println((tz<<8), DEC);
 delay(200);
}

Here is the result when the sensor is in peace:

X Accel: 0	Y Accel: 0	Z Accel: -16640
X Gyro: 60928	Y Gyro: -18688	Z Gyro: -27392
X Teplota: -32768	Y Teplota: 512	Z Teplota: -32768
X Accel: 15616	Y Accel: -32768	Z Accel: 13568
X Gyro: 48896	Y Gyro: -17152	Z Gyro: -16640
X Teplota: -512	Y Teplota: -32768	Z Teplota: 1280
X Accel: 32768	Y Accel: 14848	Z Accel: -32768
X Gyro: 9728	Y Gyro: -18688	Z Gyro: -31488
X Teplota: -16640	Y Teplota: -256	Z Teplota: -32768

Here is the result when the sensor moves:

X Accel: 0	Y Accel: 0	Z Accel: 0
X Gyro: 64512	Y Gyro: 5632	Z Gyro: -16384
X Teplota: -21760	Y Teplota: -16384	Z Teplota: -24064
X Accel: 49152	Y Accel: 15616	Z Accel: -16384
X Gyro: 35328	Y Gyro: -1280	Z Gyro: -25088
X Teplota: -14592	Y Teplota: -17408	Z Teplota: -16384
X Accel: 16640	Y Accel: -16384	Z Accel: 14592
X Gyro: 64512	Y Gyro: -1024	Z Gyro: -768
X Teplota: -29440	Y Teplota: -2048	Z Teplota: 0
X Accel: 0	Y Accel: 15616	Z Accel: 0
X Gyro: 0	Y Gyro: 0	Z Gyro: 0
X Teplota: 0	Y Teplota: 0	Z Teplota: 0
X Accel: 0	Y Accel: -16384	Z Accel: 14592
X Gyro: 63744	Y Gyro: 2048	Z Gyro: 0
X Teplota: 0	Y Teplota: -3072	Z Teplota: -12032

Almost the same values.

Here is arduino code http://arduino.cc/forum/index.php/topic,13298.0.html
There is described the function which reads 8 bits and 16 bits back.(I tried this function but without result)
It is the fifth report.

BTW: I find site Gammon Forum : Electronics : Microprocessors : Connecting SRAM to your microprocessor using SPI
I try code from this side modify to my senzor. Here is code:

byte ss=10; //CS pin 10
byte dataxg;
#include <SPI.h>
#define XGYRO_OUT 0x04

void xgyro_out (const byte ss, unsigned int address, byte * dataxg, unsigned int length)
{
  if (length == 0)  // don't bother if nothing to do
     return;

  digitalWrite (ss, LOW);     // select device
  SPI.transfer (XGYRO_OUT);       // read mode
  SPI.transfer (address >> 8);    // high-order address byte
  SPI.transfer (address & 0x04);  // low-order address byte
  for ( ; length ; --length)
    *dataxg++ = SPI.transfer (0);     // data byte
  digitalWrite (ss, HIGH);    // deselect device
}

void setup()
{
  Serial.begin (9600);
  pinMode(ss, HIGH); // používa sa pin 10
  SPI.begin(); // inicialuzuje sa SPI
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV64);
  SPI.setBitOrder(MSBFIRST);
}
void loop()
{ 
 char buf [100];
 xgyro_out (ss, 100, (byte *) buf, sizeof buf);
 Serial.print("X Gyro: ");
 Serial.print(buf);
 Serial.println("\t");
 delay(200);
}

Code work, but results are very wild :frowning:

X Gyro: ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂ	
X Gyro: 	
X Gyro: 	
X Gyro: ÿ	
X Gyro: 	
X Gyro: ÿ	
X Gyro: 	
X Gyro: À

Hello everyone,

I have been trying to do something similar to what is written in this post and stuck with the same problem as mentioned here. I am unable to read the sensor data sent back from the sensor. I am using ADIS16210 accelerometer sensor which is connected to Arduino UNO board through SPI pins.

I am trying to get the Product ID of the sensor by accessing its PROD_ID register, According to oscilloscope waveform output of my program I am able to see register address being sent at the MOSI pin as request but on MOSI I always see same output waveform (reflecting 0x40) and on serial monitor it shows 1024 always. please refer to the attached code and let me know how to get the value from sensor and display it on my serial monitor. If you are successful in getting response from Arduino then please le me know how to write code for that part i.e reading bytes from the slave device. I feel that's the tricky part for SPI communication.

As per datasheet =(I have raised the CS pin after each 16 bit cycle and introduced a delay of 45us to avoid minimum stall time of the sensor. Please refer to page 4 & 7 of the datasheet at below link for more understanding.

Please let me know if you require more information

Thanks,

Syed

 digitalWrite(CS, LOW);
  digitalWrite(AVG_CNT,0x09);
  
  //Before communication starts, the Chip Select pin needs to be set high.
  
  digitalWrite(CS, HIGH);
  
delay(45);  

}



void loop()

{
  
digitalWrite(CS, LOW);
SPI.transfer(0x56); // 0x56 for PROD_ID, 0x04 for XACCL_OUT, 0x06 for YACCL_OUT, 0x08 for ZACCL_OUT
SPI.transfer(0);
delay(45);
digitalWrite(CS, HIGH);
delay(45);
digitalWrite(CS, LOW);

byte resultHigh = SPI.transfer(0x00);
byte resultLow = SPI.transfer(0x00);

delay(45);
digitalWrite(CS, HIGH);
delay(45);

unsigned int result = (resultHigh << 8) | resultLow;


delay(45);
Serial.print(result);
Serial.print('\n');


delay(1000);

}