Go Down

Topic: SPI read problem, IMU unit ADIS16354 (Read 2 times) previous topic - next topic

mmichalll

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

Code: [Select]
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
*/


Code: [Select]
#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
Code: [Select]

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?

Nick Gammon

Quote
Code: [Select]
data=((hi<8)+lo);



hi < 8 ?

Code: [Select]
data=((hi<<8) | lo);

perhaps.

mmichalll

#2
Sep 10, 2011, 08:42 am Last Edit: Sep 10, 2011, 08:44 am by mmichalll Reason: 1
Quote
Code: [Select]
data=((hi<<8) | lo);

I changed specific line.
Here is result:
Code: [Select]

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:

Graynomad

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
Rob Gray aka the GRAYnomad www.robgray.com

Graynomad

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

Rob Gray aka the GRAYnomad www.robgray.com

Graynomad

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
Rob Gray aka the GRAYnomad www.robgray.com

Graynomad

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.

Code: [Select]
#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
Rob Gray aka the GRAYnomad www.robgray.com

mmichalll

#7
Sep 10, 2011, 05:12 pm Last Edit: Sep 10, 2011, 05:19 pm by mmichalll Reason: 1
Hello
I use your code and here is result :
Code: [Select]

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
Code: [Select]
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

cyclegadget


Would it be possible that you need more time after?:
Code: [Select]
digitalWrite(ss,LOW);

Before you request:
Code: [Select]
hi=SPI.transfer(0x0a);

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

mmichalll

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

Nick Gammon

This doesn't look right:

Code: [Select]

  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:

Code: [Select]

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:

Quote
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:

Code: [Select]

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).

Graynomad

#11
Sep 11, 2011, 02:07 am Last Edit: Sep 11, 2011, 02:14 am by Graynomad Reason: 1
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

Rob Gray aka the GRAYnomad www.robgray.com

Nick Gammon


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.

Quote
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.

Graynomad

Quote
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

Quote
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
Rob Gray aka the GRAYnomad www.robgray.com

mmichalll

#14
Sep 11, 2011, 09:05 am Last Edit: Sep 11, 2011, 09:07 am by mmichalll Reason: 1
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.

Go Up