Some spi help please

I have been trying to get some data out of an accelerometer ic I have. The data sheet for it is located here http://www.muratamems.fi/sites/default/files/documents/sca103t_inclinometer_datasheet__8261700a3_0.pdf . I have an arduino mega adk and am using I believe pin48 set to high to supply 5volt pin49 set to low as a ground pin50 to 53 for miso mosi clk and ss. If anyone can provide me with some code to help me get my project idea rolling. My plan is to move a servo in relation to the angle of the the servo to keep the servo horn at a horizontal position. Another thought is to use it on a self balancing robot. My thought of trying to make this work is that I believe this chip is about 60 dollars and would be much cooler that going and spending 20 or 30 on an accelerometer made to interface with the arduino with better documentation. Also I am not apposed to sending a person one of these that helps me to get it working seeing that I have about 4 of them.

1 Like

I paid $7 for a 6050 chip accelerometer, it must be lower resolution than yours. I bought direct from China.
I got stuck on some other projects and still haven't screwed with it yet.

The ground through a pin is probably a VERY BAD IDEA as it's going to have real problems when current going through it gets around 40mA or higher, as in you might smell smoke.

You really want a SOLID GROUND shared by everything not isolated, especially with a motive unit!

Thank you for the info about the ground subject. I'm somewhat new to arduino and aside from looking up the specs I did not know that. I had a 6 conductor ribon cable with to 6 pin connectors (2*3). I just cut off one end, soldered the wires to the pins of the surface mount chip with a capacitor between + and ground under it with the chip off of the board I got it from. I thn just figured I would use male header pins between the female connector and arduino.

You probably don't want to supply the servo power from an Arduino pin either. The better way is to go from the pin through a resistor to transistor to switch power through that. You really want to limit current through the pins to 20mA or less and total draw through the Arduino to 200mA or less.
A lot of good info on what-all to use can be found just browsing the General Electronics part of the forum here.

I've used SPI to connect to SD cards, even 2 cards on the same bus using the SPI library in my IDE. That's about it.

ok im fixing the way i have the spi setup to use a common ground allon with the servo both using the 5 volt regulated aruino output. im posting the code i found with what i added to get the servo to work but i im sure i am not getting the data i want from the accelerometer.

// include the library code:
#include <SPI.h>
#include <DSPI.h>
#include <SoftSPI.h>
#include <math.h>
#include <Servo.h>

// initialize the library with the numbers of the interface pins


//SPI Pins
#define slaveSelect 53    // Chip Select Pin
#define dataOut 51       // MOSI
#define dataIn 50         // MISO
#define spiClock 52       // SCK serial-clock
int v= 48;
int g=49;
Servo myservo;
int val;
//----------------------------------------------------------------------
void setup()
{
 pinMode(v,OUTPUT);
 pinMode(g,OUTPUT);
  pinMode(slaveSelect, OUTPUT);
  pinMode(dataOut, OUTPUT);
  pinMode(dataIn, INPUT);
  pinMode(spiClock, OUTPUT);
  digitalWrite(v,HIGH);
  digitalWrite(g,LOW);
     
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
   myservo.attach(12);
  delay(10);
 
  Serial.begin(9600);
 
}

//----------------------------------------------------------------------
void loop() 
{
  unsigned short int Yaxis;
  float a, alpha;
 
 //START SPI------------------------------------------------------------- 
  digitalWrite(slaveSelect,LOW);
  delay(50);
  SPI.transfer(0x15);  
  Yaxis = Yaxis | SPI.transfer(0x00);  
  digitalWrite(slaveSelect,HIGH);
  Yaxis = Yaxis << 8;  
  digitalWrite(slaveSelect,LOW);
  SPI.transfer(0x10);  
  Yaxis = Yaxis | SPI.transfer(0x00);  
  digitalWrite(slaveSelect,HIGH);
  //END SPI---------------------------------------------------------------
  
  a = (float)Yaxis / 32000.0 *90.0;
  alpha = asin(a);
  val=map(Yaxis,0,255,0,179);
  
  Serial.print(alpha,DEC);
  Serial.println(" ");
  Serial.println(Yaxis);
 myservo.write(val); 
  delay(25);

You get something then.
What's with all the delays? And the floats. Pure slow.

I'm surprised myself that this actually does anything the code is copied from the internet with my addition of the servo coding. Even with powering the accelerometer the way I was I could tilt the ic and get the servo to react(obviously not the way I would exactly like it to). The float is in there I believe for calculation of the data for the device this code was meant to measure and not mine. The delays I'm not exactly sure about. In my data sheet it is written that there needs to be a delay of 120us for measurement. Without having the data sheet open while I'm writing this I can't write word for word of what exactly the delay they want is for. On on other note after learning a lot over the past few days about bits, hex and a boat load of other things I now know I'm looking for an 11 bit "word" from two measurements the accelerometer is making.

I saw the 'word' building parts of the code, but want to avoid digging into what I don't have the hardware or actual inclination to play with.

If/when I get into my module I start out like with any other. I get the raw data and start finding out how I can screw with the get data process, looking for angles and pitfalls. Then I work towards solutions/applications.

As far as the floats, there's an old trick to bypass massive calculations quickly.
It's far older than electronic computers.
You make/get (a) table(s) and do lookups and if need be, interpolate between near-linear values.

That's why we have so much flash, extra room for tables and constants including text.

You can put the calculation formula into a spreadsheet and feed it to a range of expected inputs that you graph to check that every point to point is close to a straight line in between (so you can interpolate, if desired, accurately) and then use the spreadsheet output right in your Arduino source to fill the table in PROGMEM.
At run time, you get your raw value and do a lookup, maybe interpolate, and have your answer in less time than it takes to do a floating point multiply or divide. If you can, make the output to be values you can feed directly to the servo.

Table lookup is what it took to run even primitive flight sims on 1 MHz 8-bit computers up to everything pre-200 Mhz Pentium. It's also how Charles Moore was able to steer major telescopes with computers as far back as 1959.

I know from reading the data sheet that I do not need to use that float or any of the computing I'd does so I will omit that from the code. I would like some more knowledge about what the spi transfer function does other than what I have read in the reference section and also on the wiki. How I understand it and I'm sure I'm completely wrong is that I send my module 8 bits in hex of what I want it to do and what it sends back is 11 bits of data depending on what command I sent. My understanding is that what it sends back is stored in the variable that Is set before the spi transfer.

The SPI hardware clocks bytes, I would expect to get 2 bytes back that contain 11 bits data + 5 bits of filler.

So I learned that an int is 16 bits. If I take that and shift it 5 bits will it leave me with my 11 bits I'm looking for?

From Figure 11, I would expect that you would need a 3-byte transfer to get all your data.
Something like:

digitalWrite(csbPin, LOW);
SPI.transfer(command);
byte bit10to3 = SPI.transfer(dummyByte); // upper 8 bits
byte bit2to0 = SPI.transfer(dummyByte); // lower 3, but in bit 7-6-5
digitalWrite(csbPin, HIGH);
int 16bits = (bit10to3<<8) | bit2to0; // OR lower 8 in - ADD instead?
11bits = 16bits>>5;

I want to thank goforsmoke and also crossroads for both of your help. I would also like to add that although this is somewhat over my head and frustrating at times, it is also rewarding as I cross hurdles and learn. For months after reading about this arduino thing and years of working on computer controlled automotive wheel alignment and wheel balancing equipment I had to go get one. My one question is that should I put down this project and look at some better documented sensors just about made to make it easy to to deal with or go along my path of hey this part is free why not see if I can get it to work.

What about the sensor do you find not documented well enough?
Looks like you just need to do some math after you read the data back.

The data sheet that that I found from the company has tons of info, much of it I don't quite get like temperature offset graphs. If I do a google search with arduino and sca103t I don't see where anybody has documented interfacing that with their arduino. I also mostly see example code of people sending spi data to a digital pot. I'm sure there is something out there but haven't found it yet.

I think I understand your sample code. From the data sheet and what I think I got from it is that I'm looking for to sets of 11-bit numbers in binary format measured at the same Time, called RDAY and RDAX. If I send command 0x10 hex and 0x11 hex without setting the cc pin back to logic one(or do I have to toggle between commands), then subtract RDAY from RDAX. I then take that and convert it to decimal, compare that to a chart they spec in the data sheet for angle to decimal conversion.

Mysticmindset:
So I learned that an int is 16 bits. If I take that and shift it 5 bits will it leave me with my 11 bits I'm looking for?

An int is a 16 bit signed integer. If you right shift a signed integer (int or other name like int16_t) that has the high bit (bit 15) set, the high bit copies but stays set. It's better to use an unsigned int (aka uint16_t).

But I doubt that you have to shift anything. It's more likely that the 11 low bits will have the value and the high 5 bits will be zeros. All you have to do to find out is collect some raw data and see what it looks like. I would interpret the data as hex because I know the bits but binary can do the same job.

Example of printing the same number in hex and binary.
It's not tested, but that's like testing how to spell CAT;

void setup()
{
  Serial.begin( 9600 );
  unsigned int x = 63;
  Serial.println( x, HEX );
  Serial.println( x, BIN );
}

void loop()
{
}

Setup is a good place to do short tests and get easy/quick answers.

I have seen some sketches that use (int8_t). Is that a way of streamlining code to use only 8 bits to hold that variable instead of using int = x and using 16 bits? Also in your example do you have to declare x before setup?

int8_t (the t is for type, variable type, easier to remember that way, eh?)

int8_t is the same as char (signed 8 bit integer) and on Arduino, the same as short.

I used 16 bit because you will need 16 bits to hold the return from the module.

If I declare a variable outside of all functions it is then a global variable that all my code can see it.
Globals never go out of scope that I know of. They are stored in the heap as opposed to the stack.

If I declare a variable inside of a function then only that function can see it.
If I make it static then the variable will stay and hold its value, it is stored on the heap.

If I do not make it static then the variable disappears when the function returns.
It is kept on the stack with passed args and the function return address, all are released when the function ends.

In the test example, x is a local variable of setup(). It is gone when setup() ends.