Go Down

Topic: ADIS16209 / SPI Interfacing? (Read 3027 times) previous topic - next topic

Adrastos

Hello,

I'm trying to interface an Arduino with ADIS16209 dual-axis accelerometer. The accelerometer is digital and supposedly controlled through standard SPI.

However, I can't seem to talk to it at all! According to the datasheet, the device uses SPI phase = 1 and SPI polarity = 1 and 16 bit commands. (The datasheet is at http://www.analog.com/static/imported-files/data_sheets/ADIS16209.pdf). The timing diagram from the datasheet is here:
.
The 'operation' section of the datasheet says this:
Quote
The ADIS16209 requires only power/ground and SPI connec-tions. The SPI is simple to hook up and is supported by many common digital hardware platforms. Figure 20 provides a simple hook-up diagram, while Table 2, Figure 2, and Figure 3 provide timing and bit assignments. Figure 4 provides the bit sequence for accessing the register memory structure. Each function within the ADIS16209 has its own 16-bit, 2-byte reg-ister. Each byte has its own unique 6-bit address. Note that all 16 SCLK cycles are required for the DIN bit sequence to configure the output for the next data frame. The ADIS16209 supports full duplex mode operation. Table 6 provides the entire user register map for the ADIS16209. For each register, the lower bytes address is given. For those registers that have two bytes, the upper bytes address is simply the lower bytes address, incremented by 0x01.


Whenever I try to use it, using either native AVR SPI commands or bit-banging it, all I ever get in response is all return bits set high (0xFFFF).

Can anyone shed some insight into what's going on here?

The code I'm using to initialize the SPI system is as such:
Code: [Select]
// set the SPI register directions
// even though I'm *not* using the CS
// pin, it still has to be set as an output
// to work.
// PINN_ACCI is the CS of the accelerometer
SB(DDR_SPI, PINN_MOSI);
SB(DDR_SPI, PINN_SCLK);
CB(DDR_SPI, PINN_MISO);
SB(DDR_SPI, PINN_SS);
SB(DDR_ACCI, PINN_ACCI);

// disable the chip select
// (by setting the lines high)
SB(PORT_SPI, PINN_SS);
SB(PORT_ACCI, PINN_ACCI);

// setup the spi register
// enable spi
// set as master
// set polarity
// set phase
// set speed to 1/16th clock speed
SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR0);

// clear the registers
clr = SPSR;
clr = SPDR;


Then when I try to access data from the accelerometer (such as read the x-axis acceleration, which is at address byte 0x04) I do this:
Code: [Select]
#define SPI_TIMEOUT 16000

// dummy variable used to clear some of the SPI registers
byte clr;

// SPI timeout flag, must be cleared manually
byte spi_err;

// one full-duplex cycle (write one byte and read one byte)
byte SPI(volatile uint8_t data)
{
 long c = 0;
 SPDR = data;
 // start the transmission by loading the output
 // byte into the SPI data register

 // check status register for transfer finished flag
 while (!(SPSR & (1<<SPIF)))
 {
   if (++c==SPI_TIMEOUT)
   {
     spi_err=1;
     break;
   }
 }

 return SPDR;    //return the received byte
}

uint16_t ReadACC(uint8_t addr)
{
 byte buf[4];
 
 // enable chip select
 CB(PORT_ACCI, PINN_ACCI);
 
 // read / write to the spi
 // the two returned bytes
 // are data from the last command
 buf[0] = SPI(addr);
 // check to make sure we didn't time out
 if(spi_err)
 {
   // and disable chip select
   SB(PORT_ACCI, PINN_ACCI);
   spi_err = 0;
   return 42;
 }
 buf[1] = SPI(0);
 if(spi_err)
 {
   // and disable chip select
   SB(PORT_ACCI, PINN_ACCI);
   spi_err = 0;
   return 42;
 }
 
 // and disable chip select
 SB(PORT_ACCI, PINN_ACCI);
 // enable chip select
 CB(PORT_ACCI, PINN_ACCI);
 
 // these should be what we want
 // just clock the serial, don't
 // try to do anything
 buf[2] = SPI(0);
 if(spi_err)
 {
   // and disable chip select
   SB(PORT_ACCI, PINN_ACCI);
   spi_err = 0;
   return 42;
 }
 buf[3] = SPI(0);
 if(spi_err)
 {
   // and disable chip select
   SB(PORT_ACCI, PINN_ACCI);
   spi_err = 0;
   return 42;
 }
 
 // and disable chip select
 SB(PORT_ACCI, PINN_ACCI);
 
 return (buf[2] << 8 | buf[3]);
}


And all the ReadACC function ever returns is 0xFFFF.

*Any* help at all would be greatly appreciated, as I need to have this working within the next two weeks.

Thanks!

RuggedCircuits

This is a 3.3V device. How are you handling the 5V<-->3.3V level conversion?

Any chance you're holding the reset pin (9) low all the time?

Also, the timing diagram suggests there's a minimum period of time (tstall) between one chip access and another, but your 16-bit accesses are back-to-back with no delay. Perhaps add a small delay between the 16-bit command and the 16-bit data?

--
Check out our new shield: http://www.ruggedcircuits.com/html/gadget_shield.html

Adrastos

Yes, I forgot to mention I'm running this on an 8 Mhz 3.3V Arduino (modified Arduino Mega. I know the SPI works on it because I've interfaced with other things just fine with it), so no level conversion is needed.

The reset pin is tied high (should never reset).

I tried adding a delay of 10 ms between clocking in words, but it didn't help at all.

Thanks for the ideas though!

julian1222

Why don't you use the spi libary?

Go Up