Hi everyone,
I’m trying to use the SCA3000 accelerometer breakout board that I got from SFE. I’m kind of a noob so I don’t have to much confidence with this, especially since it doesn’t seem to quite work right. This is my first time to try using SPI.
Any help is greatly appreciated!
Here’s the behavior I’m seeing:
-
essentially nothing seems to work until I read the MODE register (0x14)
-
a STATUS read (0x02) after the MODE command will shift subsequent reads so that…
-
reading the device ring-buffer style (6, 1 byte reads, 3 MSB/LSB pairs) spits out something resembling accellerometer data on the LSB
-
it doesn’t matter much what address is specified for subsequent reads after the MODE register is read: data returned is always ring-buffer style, except the MSB doesn’t make sense.
-
the LSB values only vary 0-40 for 1g, and go 255->215 for -1g, plus or minus 40 is a long way from the 1300 step resolution the device is supposed to have.
-
pulling the reset pin low for a millisecond resets the SCA3000, and data reads will just return Zeros until the MODE register is read again.
Here’s the hardware setup:
I’m using a Seeduino board running at 3.3v to simplify the interface. I’ve got the SCA300 on a protoshield board with the CSB pulled high and connected to pin 10. MOSI, MISO, and SCK are directly connected to 11, 12, and 13 respectively. I’ve also pulled the RST high and connected it to pin 8 so I could try that.
Software:
-
Arduino SPI library
-
I found some example SPI code for the Atmel168, but when I tried it, it just hung on the device SPI writes, making me wonder about the SPSR definition.
I modified my code so I can send the SCA3000 various commands, as well as let it run in a loop doing XYZ reads. The hope was that some interactive hacking would reveal the solution, but it didn’t.
Here’s my Arduino sketch (for the brave):
// SCA3000 accelerometer test program
// Trying to make sense of the SCA3000 chip with the SFE breakout board.
// I’m running a Seeduino set to 3.3v to simplify the interface
// CSB (pin 10) and RST (pin 8) are both pulled HIGH
// MOSI, MISO, and SCK are direct hookup (pins 11, 12, & 13)
// Serial Commands :
// Rh - read address h (hex)
// RM - read 0x14, the MODE register
// X - pull reset pin LOW for 1 millisecond then HIGH
// Mi - set mode to i;
// Z - read x,y,z buffers in loop
// B - read BUF_DATA in loop
// any other key - will break looped reads
// looped reads are doing a 11-bit integer conversion, but from what I
// have seen it might as well be a 8-bit because the last 3 bits of the MSB
// seem to always be zero.
// the XYZ looped read is setup to display the upper and lower bytes in binary
/* Mystery demo sequence:
- start program
- send a Z command
- observe data stream, almost makes sense: values vary 0-42, 255-212 or so for +/- 1g
this isn’t at all what the datasheet says it outputs
- send a X command, resets SCA3000
- send a Z command: only reads zeros
- send a X command, resets SCA3000
- send a RM command: reads the MODE register
- send a R2 command: reads the 0x02 STATUS register
- send a Z command: now getting data again
- try skipping the STATUS read and notice how the XYZ bytes get shifted off
(and how the upper bytes don’t make any sense)
*/
#include <Spi.h>
#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;
char cmd;
byte addr;
boolean xyz=false;
boolean buf_read=false;
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;
}//end fmtSpace
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’);
}
}//end binaryPrint
void readXYZregisters()
{
// 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;
}
float getTemp()
{
float temp_in;
int b1, b2;
b1 = Spi.transfer(0x12); //msb
b2 = Spi.transfer(0x13); //lsb
// temp_in = read_register16(TEMP);
temp_in = float(int(UBLB(b1,b2)));
temp_in = temp_in -256*b2;
temp_in = (temp_in/(1.8 *b2)) + 23;
return temp_in;
}
void readRingBuffer()
// I’m sure this is wrong, but it’s just a stab at what happens if I
// do repeated reads of a given address
{
b1 = Spi.transfer(BUF_DATA); //x axis msb
b2 = Spi.transfer(BUF_DATA); //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(BUF_DATA); //y axis msb
b2 = Spi.transfer(BUF_DATA); //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(BUF_DATA); //z axis msb
b2 = Spi.transfer(BUF_DATA); //z 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);
} // end readRingBuffer
int charToHex(char ch)
{
switch (ch) {
case ‘0’:
return 0x00;
case ‘1’:
return 0x01;
case ‘2’:
return 0x02;
case ‘3’:
return 0x03;
case ‘4’:
return 0x04;
case ‘5’:
return 0x05;
case ‘6’:
return 0x06;
case ‘7’:
return 0x07;
case ‘8’:
return 0x08;
case ‘9’:
return 0x09;
case ‘F’:
return 0x0F; //BUF_DATA
case ‘T’:
return 0x12;
case ‘U’:
return 0x13;
case ‘M’:
return 0x14; //mode
default:
return -1;
}
}
void setup()
{ Serial.begin(9600);
delay(20);
// Serial.print("RevID: ");
// Serial.println(Spi.transfer(0x00),DEC);
pinMode(RESET_PIN,OUTPUT);
digitalWrite(RESET_PIN,LOW);
delay(1);
digitalWrite(RESET_PIN,HIGH);
n = Spi.transfer(OPSTATUS);
Serial.print("status = ");
Serial.println(n);
int n = Spi.transfer(MODE);
Serial.print("mode = ");
Serial.println(n);
n = Spi.transfer(OPSTATUS);
Serial.print("status = ");
Serial.println(n);
delay(1000);
}// end setup
void loop()
{
if (xyz) readXYZregisters();
if (buf_read) readRingBuffer();
if (Serial.available())
{ delay(10);
buf_read=false;
xyz=false;
cmd = Serial.read();
Serial.print(cmd);
if (Serial.available())
{
addr = charToHex(Serial.read());
Serial.print(addr,HEX);
}
else
addr = -1;
while (Serial.available()) Serial.read(); // toss the rest
Serial.println();
switch (cmd) {
case ‘X’:
digitalWrite(RESET_PIN,LOW);
delay(1);
digitalWrite(RESET_PIN,HIGH);
break;
case ‘R’:
val = Spi.transfer(addr);
binaryPrint(val);
Serial.print(’ ');
Serial.println(val,DEC);
break;
case ‘M’:
Spi.mode(addr);
Serial.print("Mode returned: ");
Serial.println(val,DEC);
break;
case ‘B’:
buf_read=true;
break;
case ‘Z’:
xyz = true;
break;
}
}
}