MS5541 depth sensor communication

Hi there,
our current project is a k-meter, a device to measure the attenuation of light in the water column (which is a core question in fotobiology, biological ozeanography, ecology, etc.). The final version is supposed to have a visible light sensor and separate UV-A and UV-B channels as well as temperature, salinity and depth measurement, a hardware clock and a µSD-Card for data storage. And it is all based on Arduino of course, right now we plan with a MiniArduino but plan to have a small sized Arduino clone with USB on a circlular 60 mm diameter PCB (so you might use it for a cansat ;-))
So far I managed to implement data storage on µSD, hardware clock (DS1307), visible light sensor and temperature (DS18S20). Right now I am about to include the MS5541 depth sensor, which will be hooked onto the SPI-Bus (where already sits the µSD; I ordered the 74HTC1G125 as indicated in the datasheet of the sensor in order to connect it to a shared SPI-Bus).
I searched deeply but did not find anything I could use right away (and I am not so much of a programer, if I musn't). Of course I already have all the datasheets and the information to start putting a code together (if I'd knew how to do it quick'n'easy), but does anybody by chance have a working code to read the sensor data? Unfortunately most topics I found in the internet seize without a final documentation and I did not recieve answers on my eMails.
I already wondered if it would be a good idea to adapt a code for one of the other SPI-using MS**** sensors, any comments about that?

We deeply appreciate the Arduino community which already helped us a lot in building (and dreaming about) other small equipment for our scientific work. If anybody is interested in joining that project of ours, you are welcome!
Thank you all very much for sharing great and inspiring ideas and helping most selflessly people who otherwise would propably not dare to start building cool stuff!
Greetings from Patagonia
Sebastian
http://www.efpu.org.ar

Hi Sebastian,

Welcome to Arduino forum, sounds like a very interesting abnd valuable project. Have you seen this project @ lady ada: - Data-Logger Shield for Arduino - I recalled it when I read your story.

I already wondered if it would be a good idea to adapt a code for one of the other SPI-using MS**** sensors, any comments about that?

You must compare the datasheets, if they look alike, it gives you a good starting point, if they don't you better start from scratch.

I don't have a library for the sensor you named, but if you build it and want a code review, you can post it here.

Be aware that every SPI device has its own select line and you can have only one SPI device active at the same time. Give this enough attention as you would not be the first with SPI interference caused by this.

If you like a review of your code you build so far feel free to post it.

Regards from the Netherlands..
Rob
How is the weather in Patagonia?

Hi Rob,
thanks for your quick answer! Bedankt!
Yes, in deed I know that project and I think I even used the code for learning the logging procedure. The setup is a little to rough for our kind of radiation measurement, but it is a great project to learn from it.
Thanks for the advice with the SPI-Bus; I am thinking in making a string of all the data first and then writing it to the card so every slave would be adressed exclusively.
As soon as I have something post-worthy I'll do, and I also hope to provide a good documentation one day if it works neatly.
Regards and saludos
Seb
PS: Weather is fine, a little cold at night, but not so much ashes any more from Puyehue volcano. You can check our weather station on the webpage below (and fotos of the beautiful place).

Uuh, swell! With all the software challenges I did not care for hardware restrictions. Now I got about 21kB to squeeze into the Mini's memory... even without the sensor comunication.
Did anybody ever change the 168 for a 328 on an Arduino Mini board and it worked? I do have a USBtinyISP and spare chips, so the bootloader might not be the problem. I only find that it is "irreplaceable", well, how irreplaceable exactly?
Thanks
Sebastian

_ _ _ UPDATE _ _ _
Irreplaceable my ...! HA! It IS possible to change the chip! OK, it is not a walk in the park, but it is definitely possible:
I cut of the chip, because I didn't want to temper with the other components by heating the entire circuit board up. I used my swiss army knife after rejecting the idea do dremel it of - there are lots of vias under the chip, so I think it is safer to cut the pins. Then I cleaned the pads from the pin rests and checked for connections between the pads and also if the pads still were connected to the outbreak pins. Soldering the new chip onto it was quite challenging. Started with a corner pin, then adjusted neatly and attached the opposite corner. Then one pin by one, using a desktop lamp and a magnifying lens to see when the tin got liquid and sucked under the pins. Next time I use one of our stereo microscopes for that. Anyway, afterwards I checked again for shortcuts and corrected. Then I burned the bootloader with my USBtinyISP. And then I used my Duemilanove to upload sketches; this worked with "Duemila or Nano w/ ATmega 328" selected as board, not with the "Mini with ATmega 328". Happy happy, joy joy!
Some additional remarks:

  • I didn't use extra tin but only the rest on the pads. I do not have SMD soldering paste yet.
  • I know there is a Mini with a 328 available, but I have no possibility to get one here (within a week or two. Besides: everybody could buy one :slight_smile: ).
    OK; the basic problem remains, though, but we will try something about it next week.

Hi,
today I tried some code I put together:

/*
  MS5541 Pressure Sensor Display
 
 Circuit:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13

 */

// library:
#include <SPI.h>

//Sensor memory register addresses:
const int PRESSURE = 0x0F;      //MSB pressure
const int PRESSURE_LSB = 0x40;  //LSB of pressure
const int TEMPERATURE = 0x0F;   //MSB temperature
const int TEMPERATURE_LSB = 0x20;  //LSB temperature
const int W1M = 0x1D; // MSB Calibration word 1
const int W1L = 0x50; // LSB Calibration word 1
const int W2M = 0x1D; // MSB Calibration word 2
const int W2L = 0x60; // LSB Calibration word 2
const int W3M = 0x1D; // MSB Calibration word 3
const int W3L = 0x90; // LSB Calibration word 3
const int W4M = 0x1D; // MSB Calibration word 4
const int W4L = 0xA0; // LSB Calibration word 4
const byte RST1 = 0x15; //Reset sequence word 1
const byte RST2 = 0x55; //Reset sequence word 2
const byte RST3 = 0x40; //Reset sequence word 3


// CS just in case
const int chipSelectPin = 10;

void setup() {
  Serial.begin(9600);
  SPI.begin();
  pinMode(chipSelectPin, OUTPUT);
  delay(100);
}

void loop() {
  //RESET
  SPI.setDataMode(1); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  delay(100);
  
  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.transfer(0x1D);
  SPI.transfer(0x50);
  SPI.setDataMode(0); 
  result1 = SPI.transfer(0x00);
  result1 = result1 <<8;
  inbyte1 = SPI.transfer(0x00);
  result1 = result1 | inbyte1;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Calibration word 1 =");
  Serial.println(result1);
  
  //Calibration word 2
  unsigned int result2 = 0;
  byte inbyte2 = 0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.setDataMode(1); 
  SPI.transfer(0x1D);
  SPI.transfer(0x60);
  SPI.setDataMode(0); 
  result2 = SPI.transfer(0x00);
  result2 = result2 <<8;
  inbyte2 = SPI.transfer(0x00);
  result2 = result2 | inbyte2;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Calibration word 2 =");
  Serial.println(result2);  
  
  //Calibration word 3
  unsigned int result3 = 0;
  byte inbyte3 = 0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.setDataMode(1); 
  SPI.transfer(0x1D);
  SPI.transfer(0x90);
  SPI.setDataMode(0); 
  result3 = SPI.transfer(0x00);
  result3 = result3 <<8;
  inbyte3 = SPI.transfer(0x00);
  result3 = result3 | inbyte3;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Calibration word 3 =");
  Serial.println(result3);  
  
  //Calibration word 4
  unsigned int result4 = 0;
  byte inbyte4 = 0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.setDataMode(1); 
  SPI.transfer(0x1D);
  SPI.transfer(0xA0);
  SPI.setDataMode(0); 
  result4 = SPI.transfer(0x00);
  result4 = result4 <<8;
  inbyte4 = SPI.transfer(0x00);
  result4 = result4 | inbyte4;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Calibration word 4 =");
  Serial.println(result4);
  
  //Temperature:
  unsigned int tempMSB = 0;
  byte tempLSB =0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.setDataMode(1); 
  SPI.transfer(0x0F);
  SPI.transfer(0x20);
  delay(30);
  SPI.setDataMode(0); 
  tempMSB = SPI.transfer(0x00);
  tempMSB = tempMSB <<8;
  tempLSB = SPI.transfer(0x00);
  tempMSB = tempMSB | tempLSB;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Temperature raw =");
  Serial.println(tempMSB);
  
  
  //Pressure:
  unsigned int presMSB = 0;
  byte presLSB =0;
  digitalWrite (chipSelectPin, LOW);  
  SPI.setDataMode(1); 
  SPI.transfer(0x0F);
  SPI.transfer(0x40);
  delay(30);
  SPI.setDataMode(0); 
  presMSB = SPI.transfer(0x00);
  presMSB = presMSB <<8;
  presLSB = SPI.transfer(0x00);
  presMSB = presMSB | presLSB;
  digitalWrite(chipSelectPin, HIGH);
  Serial.print("Pressure raw =");
  Serial.println(presMSB);
  
  
  delay(10000);
}

First it looked quite good, then I extracted the calibration factors (5422, 2908, 702, 366, 1202, and 27) from the calibration words (43378, 55058, 44978, and 46875) and I am pretty far away from the usual values in the datasheet. But who cares taking in account that the pressure and temperature reading is overflowing (both 65535)?
I am pretty sure my wiring is ok; the OSC signal is quite low (~0,2V), is that ok? I get it from pin 2 of a DS1307. Shall I better generate a signal with an I/O-pin? The 47µF Tn cap is not very close to the pins (~5 cm).
Thanks in advance, nice weekend to all!

PS: SPI.setDataMode is not really doing anything. Doesn't matter if it is there or not or the other way 'round.
PPS: Tried another sensor. Different values, but in the same range. Obviously my code does not work.
The workflow for the temp and pressure values is wrong, but I don't know how to do this:

Two additional clocks at SCLK are required after the acknowledge signal. Then SCLK is to be held low by the microcontroller until a high to low transition on DOUT indicates the end of the conversion.

Hi all, as you see, it is really somehow work in progress...
I implemented a clock generated as described here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271194241. Basically I inserted

const int clock = 9;
...
pinMode(clock, OUTPUT);

and

TCCR1B = (TCCR1B & 0xF8) | 1 ;
analogWrite (clock, 128) ;

Now I have a beautiful clock signal and if I am asking for the values I get everything as befor except the temperature reading, which now changes between 65535 and 32767.
OK then, what now? 8)
Nice weekend to all of you!

Hi, here is a new version of the code.

/*
  MS5541 Pressure Sensor Display
 
 Circuit:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9
 
 Voltage divider converts 5V to 3.3V on all lines except MISO
 
 created 4 August 2011
 by SMStrauch
 */

// library:
#include <SPI.h>

// MCKL signal pin
const int clock = 9;

void setup() {
  Serial.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT);
  delay(100);
}

void loop() {
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite (clock, 128) ; 
  
  //RESET
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  delay(100);

  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x50);
  SPI.setDataMode(SPI_MODE1); 
  result1 = SPI.transfer(0x00);
  result1 = result1 << 8;
  inbyte1 = SPI.transfer(0x00);
  result1 = result1 | inbyte1;
  Serial.print("Calibration word 1 =");
  Serial.println(result1);
  
  //RESET
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Calibration word 2
  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);  
  
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Calibration word 3
  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);  

  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
   
  //Calibration word 4
  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);
  
  unsigned int c1 = 0;
  unsigned int c2 = 0;
  unsigned int c3 = 0;
  unsigned int c4 = 0;
  unsigned int c5 = 0;
  unsigned int c6 = 0;

  c1 = result1 >> 3 & 0x1FFF;
  c2 = ((result1 & 0x7) << 10) | ((result2 >> 6) & 0x3FF);
  c3 = (result3 >> 6) & 0x3FF;
  c5 = ((result2 & 0x3F) << 6) | (result3 & 0x3F);
  c4 = (result4 >> 7) & 0x7FF;
  c6 = result4 & 0x7F;

  Serial.println(c1);
  Serial.println(c2);
  Serial.println(c3);
  Serial.println(c4);
  Serial.println(c5);
  Serial.println(c6);
 
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Temperature:
  unsigned int tempMSB = 0;
  unsigned int tempLSB = 0;
  SPI.transfer(0x0F);
  SPI.transfer(0x20);
  /*int ready = digitalRead (12);
  while (ready = 0) 
  {
  delay (10);
  }*/
  delay(50);
  SPI.setDataMode(SPI_MODE1); 
  tempMSB = SPI.transfer(0x00);
  tempMSB = tempMSB << 8;
  tempLSB = SPI.transfer(0x00);
  tempMSB = tempMSB | tempLSB;
  Serial.print("Temperature raw =");
  Serial.println(tempMSB);
  
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Pressure:
  unsigned int presMSB = 0;
  unsigned int presLSB =0;
  SPI.transfer(0x0F);
  SPI.transfer(0x40);
  delay(50);
  SPI.setDataMode(SPI_MODE1); 
  presMSB = SPI.transfer(0x00);
  presMSB = presMSB << 8;
  presLSB = SPI.transfer(0x00);
  presMSB = presMSB | presLSB;
  Serial.print("Pressure raw =");
  Serial.println(presMSB);
  
  
  delay(10000);
}

I threw out all the ballast like chip select and Set.Data.Set since it did not make a real difference. Of course, with a couple of loops it will be leaner in the last version.
In the //temperature paragraph I tried a while-loop to wait until the sensor indicates end of data conversion by pulling the Dout line down, but I still get all 1s. In the meantime I can not completely rule out any more that the sensor is working properly, although I connected a spare one and the values differ in strangeness a little, but are neither really better nor worse.
As a programing noob I really would appreciate every advice I can get. One doubt I have about the reset command is if it is really send as a 24bit block or if there are gaps between each byte. I suppose it is put together during compilation so three seperate command lines in the sketch are as good as on sequence of hex numbers in brackets? Thanks very much in advance
Have a nice weekend
Sebastian
PS I measured with my DSO Nano from Seeedstudio but I did not see movement on sckl nor dout, but I am sure I've choosen the wrong settings. What is the speed of the spi communication? In what resolution can I expect to see something?

PPS I replaced the code on Monday, 8/15, with a new version since I found myself a couple of errors during the weekend. Calibration values are now well in the expected range. Speed is adapted. Still, the temp and pressure values are 11111111 11111111, so still no satisfaction. Come on, people! A tiny pressure sensor for about 30€ is a fantastic peripheral we really should make accessible for Arduino! :wink:

Hi there,
it works - somehow. Here the current version of the code:

/*
  MS5541 Pressure Sensor Display
 
 Circuit:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9
 
 Voltage divider converts 5V to 3.3V on all lines except MISO
 
 created 4 August 2011
 by SMStrauch based on application note AN510 from www.intersema.ch
 */

// library:
#include <SPI.h>

// MCKL signal pin
const int clock = 9;

void setup() {
  Serial.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT);
  delay(100);
}

void loop() 
{
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite (clock, 128) ; 
  
  //RESET
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  delay(100);

  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x50);
  SPI.setDataMode(SPI_MODE1); 
  result1 = SPI.transfer(0x00);
  result1 = result1 << 8;
  inbyte1 = SPI.transfer(0x00);
  result1 = result1 | inbyte1;
  Serial.print("Calibration word 1 =");
  Serial.println(result1);
  
  //RESET
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Calibration word 2
  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);  
  
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Calibration word 3
  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);  

  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
   
  //Calibration word 4
  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);

  unsigned int c1 = result1 >> 3 & 0x1FFF;
  unsigned int c2 = ((result1 & 0x7) << 10) | ((result2 >> 6) & 0x3FF);
  unsigned int c3 = (result3 >> 6) & 0x3FF;
  unsigned int c5 = ((result2 & 0x3F) << 6) | (result3 & 0x3F);
  unsigned int c4 = (result4 >> 7) & 0x7FF;
  unsigned int c6 = result4 & 0x7F;

  Serial.println(c1);
  Serial.println(c2);
  Serial.println(c3);
  Serial.println(c4);
  Serial.println(c5);
  Serial.println(c6);
 
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Temperature:
  unsigned int tempMSB = 0;
  unsigned int tempLSB = 0;
  unsigned int D2 = 0;
  SPI.transfer(0x0F);
  SPI.transfer(0x20);
  delay(50);
  SPI.setDataMode(SPI_MODE1); 
  tempMSB = SPI.transfer(0x00);
  tempMSB = tempMSB << 8;
  tempLSB = SPI.transfer(0x00);
  D2 = tempMSB | tempLSB;
  Serial.print("Temperature raw =");
  Serial.println(D2);
  
  //RESET
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
  
  //Pressure:
  unsigned int presMSB = 0;
  unsigned int presLSB =0;
  unsigned int D1 = 0;
  SPI.transfer(0x0F);
  SPI.transfer(0x40);
  delay(50);
  SPI.setDataMode(SPI_MODE1); 
  presMSB = SPI.transfer(0x00);
  presMSB = presMSB << 8;
  presLSB = SPI.transfer(0x00);
  D1 = presMSB | presLSB;
  Serial.print("Pressure raw =");
  Serial.println(D1);
  
  //calculation of the real values
  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;
  const long PCOMP = (SENS * (D1 - OFF) >> 12) + 1000;
  const float TEMPREAL = TEMP/10;
 
  Serial.print("Real Temperature in °C=");
  Serial.println(TEMPREAL);
  
  Serial.print("Compensated pressure in mbar =");
  Serial.println(PCOMP);
  
  //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(10000);
}

I get this on the serial monitor:

Calibration word 1 =21788
Calibration word 2 =35364
Calibration word 3 =24837
Calibration word 4 =28726
2723
4648
388
224
2309
54
Temperature raw =28204
Pressure raw =14665
Real Temperature in °C=17.00
Compensated pressure in mbar =5561
2nd order compensated temperature in °C =17.00

Temperature is fine. Pressure is wrong and increases with every new measurement. Any thoughts?
Thank you.

You really should consider creating functions to reduce memory e.g. reset()

Pressure is wrong and increases with every new measurement. Any thoughts?

Can you post a sequence of values you got?
Is the difference between two consecutive readings (nearly) constant ?

Formulas in the code are "quite complex" but I see no reason in the code.
Can it be that the sensor does not reset properly?

Hi Rob,
once the code runs well I will make it slim.
In the annex is a graph of a 107 s measurement. I think my problem is in the wiring and not so much in the software, what o you think? I touched the sensor to generate some pressure at the point where the values drop. Even so they are quickly stable again, the compensated values climbs up to fall again...
I checked the formulas twice today, they are ok.
How could I check if the sensor resets?
Thanks

Found a datasheet at: - http://www.thaieasyelec.net/archives/Manual/MS5541-CM.pdf -
3,3Volt?

I checked your code with the datasheet especially the formulas for the 6 correction factors.

your code:

  unsigned int c1 = result1 >> 3 & 0x1FFF;
  unsigned int c2 = ((result1 & 0x7) << 10) | ((result2 >> 6) & 0x3FF);
  unsigned int c3 = (result3 >> 6) & 0x3FF;
  unsigned int c5 = ((result2 & 0x3F) << 6) | (result3 & 0x3F);
  unsigned int c4 = (result4 >> 7) & 0x7FF;
  unsigned int c6 = result4 & 0x7F;

If I read the datasheet correctly ( figure Page 12)
There is a small diff in c4 (TCO), it need another mask than in your code, but that cannot cause such a problem.
c4 is used to calculate the compensated pressure.

  long c1 = (result1 >> 3) & 0x1FFF;    //SENST1
  long c2 = ((result1 & 0x0007) << 10) | ((result2 >> 6) & 0x03FF);  // OFFT1
  long c3 = (result3 >> 6) & 0x03FF;  // TCS
  long c4 = (result4 >> 7) & 0x01FF;  // TCO  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  long c5 = (result2 & 0x003F) << 6  | (result 3 & 0x003F); // Tref
  long c6 = result4 & 0x007F;  // TEMPSENS

If I read the formulas correctly the math needs long (32 bits) for intermediate results, so I made the correction factors long so the CPU does the math with enough bits.
(Too few bits could cause overflow => strange results)

Please give it a try..

OMG, it works! Thanks man, thanks a lot!
It seems to have been the "long"-thing, because first I changed the "0x7FF" to "0x1FF" with no effect.
But now: joya! Pressing the sensor increased the value nicely, releasing it made it go back to 1007 mbar immediately.
OK; now I will try to create a library and some loops to make it a little more neat.
Again, thanks a lot!

And show us a new graph !!

If you want feedback on the library don't hesitate to ask (don't have such sensor but written/optimized a few small libs)

Hi,
here is the new graph. You see nicely when I touched and squeezed it and how the temperature rises and slowly falls again.

Hi all,
I wrapped up the code and commented it out. To close the case I will post a sketch to read out all calibration words and one which shows how to include the extracted calibration factors into a sketch to avoid reading these constants all the time while using the sensor in whatever application.
MS5541_read_all.pde

/*
 MS5541 Pressure Sensor calwords readout
 This program will read your MS5441 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:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9
 CS is not in use, but might be pin 10
 
 created August 2011
 by SMStrauch based on application note AN510 from www.intersema.ch (http://www.meas-spec.com/downloads/Using_SPI_Protocol_with_Pressure_Sensor_Modules.pdf), 
 and with help of robtillaart and ulrichard. Thanks!
 */

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

// generate a MCKL signal pin
const int clock = 9;

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.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);
}

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;

  Serial.print("Real Temperature in °C=");
  Serial.println(TEMPREAL);

  Serial.print("Compensated pressure in mbar =");
  Serial.println(PCOMP);

  //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(5000);
}

PS: Un-voided the resetsensor call as of today, Nov 25 2011.

.... and just because it was to much to put it in one post:

MS5541_demo.pde

/*
 MS5541 Pressure Sensor demonstration sketch
 To obtain the calibration factors run the read-calwords-sketch before.
 
 Circuit:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9
CS is not in use, but might be pin 10
  
 created August 2011
 by SMStrauch based on application note AN510 from www.intersema.ch (http://www.meas-spec.com/downloads/Using_SPI_Protocol_with_Pressure_Sensor_Modules.pdf), 
 and with help of robtillaart and ulrichard. Thanks!
 */

// include librariy:
#include <SPI.h>

// generate a MCKL signal 
const int clock = 9;

//include the calibration factors according to your individual sensor; they MUST be long for internal calculation of the compensated values
//intersema.ch provides a file with expected values
const long c1 = 2723;
const long c2 = 4648;
const long c3 = 388;
const long c4 = 224;
const long c5 = 2309;
const long c6 = 54;

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.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT); //sets clockpin on output
}

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

  void resetsensor(); //resets the sensor, be aware SPI remains in Mode 0 afterwards!

  //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á!

  void 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 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;
  //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("Real Temperature [°C]=");
  Serial.println(TEMPREAL);

  Serial.print("Compensated pressure [mbar] =");
  Serial.println(PCOMP);

  Serial.print("2nd order compensated temperature [°C] =");
  Serial.println(TEMPCOMP);  

  delay(5000);
}

Any comments are welcome, and please tell me about your applications with the sensor.

¡Bien hecho :wink:

Might include the link to the datasheet in the code

¡Muchas gracias!
Links are in.

Hi folks,
and on it goes: I have a new riddle to solve!
Since my project requires quite some memory I decided to upgrade and made myself a neat little Sanguino clone board. It works nicely, I downloaded and installed awesome stuff from here Alternate CORE files for Arduino and some Sanguino board data I do not remember from where. It runs both with the Ardu-Duino 644P and Sanguino board settings (but that's probably obvious).
Then I tested sketches I already used on my 2009 as this one... no wait, it is far to long. It is the AnalogLogger example from the SdFat-library which I adapted and added a DS18B20. Unfortunately I only figured out the code formally and adapted it without deep understanding. But it runs like a charm logging 4 analog inputs and digital temperature via SPI onto a µSD-Card. So far so good.
Now comes the riddle: I also adapted the code I displayed in this post but it won't work. There aren't even osci-spikes on the SCK line which I clearly saw running the SdFat-based code. So to me it looks like the sketch doesn't access the SPI-Bus at all, even though I adjusted the PINs to the right ones on the 644 (SS 4, MOSI 5, MISO 6, SCK 7). So - more of a general understanding question - where exactly does the SdFat library access the information about the PIN configuration? And where do I have to give the SPI library that information (I copied and included ArduinoPins.h from the SdFat diractory, but it didn't help)?
Can anybody tell me more about the compiling process, I mean, by selecting a specific board, do I already direct the compiler to a specific file in which the PIN configuration is given or do the respective libraries do that independently of the board I chose; it seems to me a valuable general info and a good point to look for the problem.
Thanks in advance, any comment is apreciated, greetings from Patagonia
Seb

PS: Problem solved with help from Nick. If you modify a .h-file NEVER copy-paste the code but type it. If copy-pasted the changes are visible, appear totally normal but the compiler does not read it properly.

Hey this is great I just bought the sensor and it is pretty small, how did you manage to solder it, any recommendations?

What did you use for the 32.768. khz clock? I bought t a DS32khz/ 14-dip .. Mixed-signal and digital signal processing ICs | Analog Devices
I will be using an arduino pro mini for the 3.3 volts that the sensor requires.

I will be use this a diving depth logger..

So I will keep you inform.

Thanks for the code I will try it, any more tips?