Help with SPI to interface servo and sensor.

Hello, I am new to Arduino and this is my first post.

I am working on a project for a class of mine where we are designing an underwater toy that remains at a constant depth using a pressure sensor to control a servo. We want to set it to go to a certain depth, which will be determined base on pressure, and remain at that depth using a servo to control diving wings.

This project is being carried over from a previous semester and they have gotten to the point where they are receiving the output data from the sensor, a MS5541-CM from Measurement Specialties, using SPI code they found here:
http://forum.arduino.cc/index.php?topic=67188.0, they pretty much just copied the whole code and added a few details for themselves.

The issue I am experiencing is that the servo will not run with the code they used. It will lock up and start overheating. I am not really sure what I need to do to remedy the issue, but I assume I will probably need to use SPI in some way to control the servo. Any help with SPI would be helpful. Below is the code I received, with the lcd portion removed.

/*
 MS5535C Pressure Sensor calwords readout
 This program will read your MS5535C or compatible pressure sensor every 5 seconds and show 
 you the calibration words, the calibration factors, 
 the raw values and the compensated values of temperature and pressure.
 Once you read out the calibration factors you can define them in the header of any sketch 
 you write for the sensor.
 
Pins:
 MS5535C sensor attached to pins 10 - 13:
 DIN (MOSI): pin 11
 DOUT (MISO): pin 12
 SCLK: pin 13
 MCLK: pin 9
 
 Modified February 2012 by spincrisis for the MS5535C.
 */

// include library:
#include <SPI.h>
#include <LiquidCrystal.h>
#include <Servo.h>

// generate a MCKL signal pin
const int clock = 9;
LiquidCrystal lcd(8,6,5,4,3,2);   //12,9,5,4,3,2);
Servo myservo;

//position of servo
int pos = 0;

//the present depth of the sensor in meters
int present_depth = 0;
//the density of water in kilograms/(meters^3)
int density = 1.275; //freshwater = 1000, saltwater = 1020-1029, air = 1.275
//gravity in meters/(seconds^2)
int gravity = 9.81;
//the desired depth for trolling in meters, this value should be set by the user
int desired_depth = 10;

void resetsensor() //this function keeps the sketch a little shorter
{
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
}

void setup() {
  //serial prints to the serial port window
  Serial.begin(9600);
  SPI.begin(); //see SPI library details on arduino.cc for details
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT);
  delay(100);
  
  //prints to the lcd, we printed to the lcd to test the accuracy of the sensor 
  lcd.begin(16,2);
  lcd.print("Temp: ");
  
  //the servo is connected to pin A0
  //we commented moving the servo due to interference with the pressure measurements
  myservo.attach(14);
  
  delay(100);
}

void loop() 
{
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite (clock, 128) ; 

  resetsensor();//resets the sensor - caution: afterwards mode = SPI_MODE0!

  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D); //send first byte of command to get calibration word 1
  SPI.transfer(0x50); //send second byte of command to get calibration word 1
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  result1 = SPI.transfer(0x00); //send dummy byte to read first byte of word
  result1 = result1 << 8; //shift returned byte 
  inbyte1 = SPI.transfer(0x00); //send dummy byte to read second byte of word
  result1 = result1 | inbyte1; //combine first and second byte of word
  Serial.print("Calibration word 1 =");
  Serial.println(result1);

  resetsensor();//resets the sensor

  //Calibration word 2; see comments on calibration word 1
  unsigned int result2 = 0;
  byte inbyte2 = 0; 
  SPI.transfer(0x1D);
  SPI.transfer(0x60);
  SPI.setDataMode(SPI_MODE1); 
  result2 = SPI.transfer(0x00);
  result2 = result2 <<8;
  inbyte2 = SPI.transfer(0x00);
  result2 = result2 | inbyte2;
  Serial.print("Calibration word 2 =");
  Serial.println(result2);  

  resetsensor();//resets the sensor

  //Calibration word 3; see comments on calibration word 1
  unsigned int result3 = 0;
  byte inbyte3 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x90); 
  SPI.setDataMode(SPI_MODE1); 
  result3 = SPI.transfer(0x00);
  result3 = result3 <<8;
  inbyte3 = SPI.transfer(0x00);
  result3 = result3 | inbyte3;
  Serial.print("Calibration word 3 =");
  Serial.println(result3);  

  resetsensor();//resets the sensor

  //Calibration word 4; see comments on calibration word 1
  unsigned int result4 = 0;
  byte inbyte4 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0xA0);
  SPI.setDataMode(SPI_MODE1); 
  result4 = SPI.transfer(0x00);
  result4 = result4 <<8;
  inbyte4 = SPI.transfer(0x00);
  result4 = result4 | inbyte4;
  Serial.print("Calibration word 4 =");
  Serial.println(result4);

  //now we do some bitshifting to extract the calibration factors 
  //out of the calibration words; read datasheet AN510 for better understanding
  long c1 = result1 >> 3 & 0x1FFF;
  long c2 = ((result1 & 0x07) << 10) | ((result2 >> 6) & 0x03FF);
  long c3 = (result3 >> 6) & 0x03FF;
  long c4 = (result4 >> 7) & 0x07FF;
  long c5 = ((result2 & 0x003F) << 6) | (result3 & 0x003F);
  long c6 = result4 & 0x007F;

  Serial.println(c1);
  Serial.println(c2);
  Serial.println(c3);
  Serial.println(c4);
  Serial.println(c5);
  Serial.println(c6);

  resetsensor();//resets the sensor

  //Temperature:
  unsigned int tempMSB = 0; //first byte of value
  unsigned int tempLSB = 0; //last byte of value
  unsigned int D2 = 0;
  SPI.transfer(0x0F); //send first byte of command to get temperature value
  SPI.transfer(0x20); //send second byte of command to get temperature value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  tempMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  tempMSB = tempMSB << 8; //shift first byte
  tempLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D2 = tempMSB | tempLSB; //combine first and second byte of value
  Serial.print("Temperature raw =");
  Serial.println(D2); //voilá!

  resetsensor();//resets the sensor

  //Pressure:
  unsigned int presMSB = 0; //first byte of value
  unsigned int presLSB =0; //last byte of value
  unsigned int D1 = 0;
  SPI.transfer(0x0F); //send first byte of command to get pressure value
  SPI.transfer(0x40); //send second byte of command to get pressure value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  presMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  presMSB = presMSB << 8; //shift first byte
  presLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D1 = presMSB | presLSB; //combine first and second byte of value
  Serial.print("Pressure raw =");
  Serial.println(D1);

  //calculation of the real values by means of the calibration factors and the maths
  //in the datasheet. const MUST be long
  const long UT1 = (c5 << 3) + 10000;
  const long dT = D2 - UT1;
  const long TEMP = 200 + ((dT * (c6 + 100)) >> 11);
  const long OFF  = c2 + (((c4 - 250) * dT) >> 12) + 10000;
  const long SENS = (c1/2) + (((c3 + 200) * dT) >> 13) + 3000;
  long PCOMP = (SENS * (D1 - OFF) >> 12) + 1000;
  float TEMPREAL = TEMP/10;
  
  //pressure is converted from mbar to Pa, and the present depth of the sensor is calculated in meters
  present_depth = (PCOMP * 100) / (density * gravity);// ((Pressure/0.0145037738)*100)/(1000*9.81)
 
  //if the present depth is more than 2 meters above the desired depth, the servo is rotated CW
  //if the present depth is less than 2 meters above the desired depth, the servo is rotated CCW
  if (present_depth > desired_depth + 2) {
    while(present_depth > desired_depth + 2 && pos <= 90) {
      pos += 1;
      myservo.write(pos);
      delay(15);
   }
  } else if (present_depth < desired_depth - 2) {
    while(present_depth < desired_depth - 2 && pos >= 90) {
      pos -= 1;
      myservo.write(pos);
      delay(15);
   }
  }  

  //2nd order compensation only for T > 0°C
  const long dT2 = dT - ((dT >> 7 * dT >> 7) >> 3);
  const float TEMPCOMP = (200 + (dT2*(c6+100) >>11))/10;
  Serial.print("2nd order compensated temperature in °C =");
  Serial.println(TEMPCOMP);  
  
  delay(500);
}

iracanis: The issue I am experiencing is that the servo will not run with the code they used. It will lock up and start overheating.

Maybe the servo is bad. Maybe you're trying to make it work beyond its capacity. Maybe you don't have it hooked up right. What's your servo "experience level"?

iracanis: I am not really sure what I need to do to remedy the issue,

OK...

iracanis: but I assume I will probably need to use SPI in some way to control the servo.

Explain.

Well your program looks like rubbish.

You only need to read the calibration data from the sensor, once.

Servos do not use SPI ( except some fancy, expensive, Korean ones, apparently ). You control the position of a servo by sending a variable width PWM pulse to it. Nothing to do with SPI.

Determining the pressure and then controlling the servo are two separate things which you can debug separately.

You can write a separate arduino sketch which merely initialises the servo and checks it's range of motion. There are plenty of examples of this.

You need to check that you are getting sensible pressure readings, and that you are converting these somehow to the servo position that you think you want.

It seems very odd, that you calculate those calibration terms, and print them, over and over and over again, although you only need to do it once, yet you DON'T print the only actually interesting number in the entire process, which is "present_depth" ??? Why not ??

You also don't seem to know what the actual angle limits of your servo are, and you don't seem to do any limit checking at all on your variable "pos" to keep it within those limits. I suggest you review some basic tutorial examples of how to use servos, which you can find on google or using youtube.

You also need to make sure that you have a proper power supply for the servo. You cannot power the servo directly from the arduino.

[quote author=Runaway Pancake link=topic=216188.msg1582568#msg1582568 date=1391910086]

iracanis: The issue I am experiencing is that the servo will not run with the code they used. It will lock up and start overheating.

Maybe the servo is bad. Maybe you're trying to make it work beyond its capacity. Maybe you don't have it hooked up right. What's your servo "experience level"?

iracanis: but I assume I will probably need to use SPI in some way to control the servo.

Explain.

[/quote] I know I have the servo connected properyly, it runs with the Knob and Sweep sample programs, as for the SPI that was just my assumption.

michinyon: Servos do not use SPI ( except some fancy, expensive, Korean ones, apparently ). You control the position of a servo by sending a variable width PWM pulse to it. Nothing to do with SPI.

That clarifies that.

michinyon: Determining the pressure and then controlling the servo are two separate things which you can debug separately.

You can write a separate arduino sketch which merely initialises the servo and checks it's range of motion. There are plenty of examples of this.

I will check on that ASAP.

michinyon: You need to check that you are getting sensible pressure readings, and that you are converting these somehow to the servo position that you think you want.

It seems very odd, that you calculate those calibration terms, and print them, over and over and over again, although you only need to do it once, yet you DON'T print the only actually interesting number in the entire process, which is "present_depth" ??? Why not ??

Sorry, looks like I accidentally removed that when I removed some lines to avoid the posting limit.

  //prints tge present depth in meters to the serial port
  Serial.print("Present Depth in m=");
  Serial.println(present_depth);
  //prints the present depth in meters to the lcd. Temp needs to be commented out.
  lcd.setCursor(0,1);
  lcd.print("Depth: ");
  lcd.print(present_depth);
  lcd.print(" m");

That went right after the present_depth calculation.

michinyon: You also don't seem to know what the actual angle limits of your servo are, and you don't seem to do any limit checking at all on your variable "pos" to keep it within those limits. I suggest you review some basic tutorial examples of how to use servos, which you can find on google or using youtube.

Will do.