SCA3000 Accellerometer?

Has anyone out there used one of the SCA3000 accellerometer breakouts that are available from SparkFun? I’m a newb, but I decided to try this because of its digital output and high resolution. I put header pins on the breakout and socketed it to a prototype shield. I ran the CSB to pin 10, and the MOSI,MISO, and SCK to 11, 12, and 13 respectively. I’m pulling the CSB high to the Vin with a 10k, and I’ve got Vin hooked up to the 3.3v. The protoshield is stacked on a Seeduino set to run at 3.3 to simplify the interface. Hopefully thats all standard textbook stuff.

I’m having some luck with the Spi library that’s available from the playground, but the numbers I’m getting don’t really make sense.
I tried some official sample C code that was written for the Atmel 168 but it just hung when it tried to write to the device.

I was getting total garbage with the Spi library till I tried a mode(0) command (which is supposed to return the version), which made it start spitting out mostly 0’s, then I commented out the mode(0) and now it almost looks like I’m getting real data, at least from the LSB. The axis seem out of order, and the values are all 0-255. I’m throwing a mask on the MSB to take a 11 bit reading, but it looks like bits 0-2 are always zero, so I’m just getting 8bit from the LSB.

Here’s a few x,y,z readings in binary and 11bit decimal
11110000 00101001 01001000 00000101 10010000 00000110 41 5 6

00111000 00101000 11010000 00000101 10101000 00000110 40 5 6

10010000 00101000 11100000 00000101 11000000 00000101 40 5 5

11011000 00101000 00001000 00000101 10100000 00000110 40 5 6

00011000 00101001 00001000 00000101 00111000 00000110 41 5 6

00110000 00101000 11000000 00000101 10111000 00000110 40 5 6

01010000 00101000 10110000 00000101 10100000 00000101 40 5 5

These values change as I tilt the board, but like I said it just don’t seem right. I just now tried to add a status read to the setup code and that seems to have shifted all the subsequent data reads. The chip seems to be in Ring mode (which I don’t even know how to invoke).

When I use the mode command to set the mode it doesn’t return the same value each time, which doesn’t generate much confidence.

Here’s my code

#include <Spi.h>

#define UBLB(a,b) ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )

byte b1,b2;
int Ax,Ay,Az;
unsigned int temp,n;

void setup()
{ Serial.begin(9600);
delay(20);
// Serial.print("RevID: ");
// Serial.println(Spi.transfer(0x00));
int n = Spi.transfer(0x14);
Serial.print("mode = ");
Serial.println(n);
Spi.mode(0);
delay(2);
n = Spi.transfer(0x2);
Serial.print("status = ");
Serial.println(n);
/*
n = Spi.transfer(0x14);
Serial.print("mode = ");
Serial.println(n);
delay(1000);
*/
}

char* fmtSpace(int i, char *buf)
{
int j,k;
for (j=0;j<7;j++) buf[j]=0;
itoa(i,buf,10);
j=0;
if (i<10000) j=1; // less than 5 characters, 1 space
if (i<1000) j=2;
if (i<100) j=3;
if (i<10) j=4;
for (k=5-1;k>=0 ;k–)
{
buf[k]= (k-j>=0)? buf[k-j] : ’ ';
}
return buf;
}

void binaryPrint(byte in_b)
{ int i,j;
byte b;
for (i=7;i>=0;i–)
{
if (in_b & 1<<i)
Serial.print(‘1’);
else
Serial.print(‘0’);
}
}

char ibuf[10];
int c=0;
short s;
void loop()
{
// if (!c) // my loop counter
// Serial.println("Ax Ay Az ");

b1 = Spi.transfer(0x05); //x axis msb
b2 = Spi.transfer(0x04); //x axis lsb
binaryPrint(b1);
Serial.print(’ ');
binaryPrint(b2);
b1 &= B00000111; //just 11 bit so clear all but last 3 of msb
Ax = UBLB(b1,b2);

b1 = Spi.transfer(0x07); //y axis msb
b2 = Spi.transfer(0x06); //y axis lsb
Serial.print(" “);
binaryPrint(b1);
Serial.print(’ ');
binaryPrint(b2);
b1 = b1 & B00000111; //just 11 bit so clear all but last 3 of msb
Ay = UBLB(b1,b2);
b1 = Spi.transfer(0x09); //y axis msb
b2 = Spi.transfer(0x08); //y axis lsb
Serial.print(” “);
binaryPrint(b1);
Serial.print(’ ');
binaryPrint(b2);
b1 &= B00000111; //just 11 bit so clear all but last 3 of msb
Az = UBLB(b1,b2);
fmtSpace(Ax,ibuf);
Serial.print(” ");
Serial.print(ibuf);
fmtSpace(Ay,ibuf);
Serial.print(ibuf);
fmtSpace(Az,ibuf);
Serial.println(ibuf);
// c++;
// c = c % 20;
}

Well, no responces yet, but here's an update on what I've figured out for the behavior:

  • I don't get any data until I've read the MODE register
  • I can read the REVID register, but then I can't get any data out of the device!
  • setting the mode (with Spi.mode(0))has no effect as determined by the behavior. Mode register returns 2 or 3 usually but sometimes I'll get a higher bit for a value like 66 or 67.
  • adding one more read of anything after the first MODE read shifts the subsequent bytes so that it appears the device is in some sort of ring buffer mode.
  • It doesn't matter what address I specify, the device returns ZYX registers
  • the MSB seems useless and the LSB seems to vary ~ +/- 40g, e.g. 0-40ish and 255 down to 215ish. This hardly seems proper for a device that is supposed to give 1300 count/g. As far as I can figure from the spec sheet it doesn't even have a sensitivity level that could explain these readings.

Well after reading the spec sheet every day for a week or more now, and getting some clues from the product demo kit documentation, I now have everything working fine. It’s a wonderful feeling to see the data scrolling by at 1300 resolution per g.
The key was shifting the register address for the reads(addr<<2), once this was done, I figured out that the data returned needed to have the last 3 bits tossed (data>>3), and viola.
If anyone wants the code I’ll post it.

I'm a Arduino newbie not familiar with SPI, interested in SCA3000 accelerometer. Your help will be greatly appreciated!

Nenad

Saw a similar post on another forum. I have a similar setup running on the decimillia and would like to see the updated code. Im pretty much a newb on bitwise stuff so im trying to figure it out. would be amazing if you could help me out :)

I’ve written a sketch that takes serial commands and makes a stab at a calibration routine (saving various orientation values to EEPROM), but it’s too big to post in a message.
I noticed that the -1G and +1G values are different for each axis on my unit (slowly rotating the unit to observe the maximum or minimum value while holding the unit otherwise still) so clearly there is not only pitch/roll calibration but also normalization prior to pitch/roll calculations.
Any math wiz’s out there that would like to contribute to the pitch/roll calculation for calibration, the help would be greatly appreciated.

Here’s the important part for reading the SCA3000, notice that the readXYZ() function averages the data to reduce noise …

#define UBLB(a,b)  ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )
//Register Addresses from the SCA300 spec sheet
#define REVID 0x00      //ASIC Revision Number
#define OPSTATUS 0x02   //Operation Status
#define X_LSB 0x04      // x-axis LSB
#define X_MSB 0x05      // x-axis MSB
#define Y_LSB 0x06      // y-axis LSB
#define Y_MSB 0x07      // y-axis MSB
#define Z_LSB 0x08      // z-axis LSB
#define Z_MSB 0x09      // z-axis MSB
#define BUF_DATA 0x0F   // Ring buffer output register
#define TEMP_LSB 0x12   // temperature LSB
#define TEMP_MSB 0x13
#define MODE 0x14       // Operational mode: mode selection, output buffer, freefall detection
#define BUF_COUNT 0x15  // number of unread data samples
#define INT_STATUS 0x16 // interrupt status register
#define I2C_RD_SEL 0X17  //Register address for I2C read operation
#define CTRL_SEL 0X18    //Register address pointer for indirect control registers.
#define UNLOCK 0x1E      //Unlock register
#define INT_MASK 0x21    //Interrupt mode configuration mask
#define CTRL_DATA 0x22   //data to/from which conf address is in CTRL_SEL register

#define BUF_EN (1<<7)
#define BUF_8BIT (1<<6)
#define FFD_EN (1<<4)

#define RESET_PIN 8

byte b1,b2;
int Ax,Ay,Az;
unsigned int temp,n;
char ibuf[10];
int c=0;
short s;
int val;


/***************************************************************/

#define SPI_CSB 0x04 // This is PB2 at the port
#define SPI_PORT PORTB

// Function takes in the 8-bit register address and returns 16-bit register value.
int transfer16(unsigned int Address)
{
  int result;
  result = 0;
  Address = Address << 2; // RW bit is set to zero by shifting the bit
                        // pattern to left by 2
  SPI_PORT = SPI_PORT & (~SPI_CSB); // Set CSB to zero
  SPDR = Address; // Write command to SPI bus
  while(!(SPSR & (1 << SPIF))); // Wait until data has been sent

  SPDR = 0x00; // Write dummy byte to line
  // in order to generate SPI clocks for data read
  while(!(SPSR & (1 << SPIF))); // Wait until data has been sent

  result = SPDR; // Get MSB of the result
  result = result << 8; // Shift the MSB of the result to left by 8
  SPDR = 0x00; // Write dummy byte to line
  // in order to generate SPI clocks for data read
  while(!(SPSR & (1 << SPIF))); // Wait until data has been sent

  result |= SPDR; // Get LSB of the result
  SPI_PORT = SPI_PORT | SPI_CSB; // Set CSB to one
  return result;
}

/**************************************************************/
#define X_AXIS 0
#define Y_AXIS 1
#define Z_AXIS 2

#define N_DATA 100
void readXYZ()
{ float accel;
  long x,y,z;
  x = 0;
  y = 0;
  z = 0;
  for (int i=0;i<N_DATA;i++)
  {  x = x + (transfer16(0x05)>>3); //x axis msb
     y = y + (transfer16(0x07)>>3);
     z = z + (transfer16(0x09)>>3);
     delay(5); // >=4 because SCA3000 updates 250 times/sec
  }
  // end min/max for loops
  
  if (x%N_DATA >= N_DATA/2)
    Ax = x/N_DATA + 1;
  else
    Ax = x / N_DATA;
  if (y%N_DATA >= N_DATA/2)
    Ay = y/N_DATA + 1;
  else
    Ay = y / N_DATA;
  if (z%N_DATA >= N_DATA/2)
    Az = z/N_DATA + 1;
  else
    Az = z / N_DATA;

  Serial.print(Ax,DEC);
  Serial.print(", ");
  Serial.print(Ay,DEC);
  Serial.print(", ");
  Serial.print(Az,DEC);
  Serial.print(", ");
  accel = sqrt(pow(Ax,2)+pow(Ay,2)+pow(Az,2))/1333.0;
  Serial.print(accel);
  Serial.print("   ");
}