Go Down

Topic: SPI Communication with the SD library and a MS5535C Pressure Sensor (Read 3656 times) previous topic - next topic

drews256

Mar 19, 2014, 01:54 am Last Edit: Mar 19, 2014, 04:49 am by drews256 Reason: 1
I am having trouble making a pressure sensor work.

It's this guy;
http://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5535-CM.pdf

I can't seem to make it work with the Wi-Fi shields micro SD logger. I don't know much about SPI and I am pretty certain that is my problem. Basically I can log from just about any sensor besides ones that are SPI and I would really like to make the SPI work.

Here is my code for the pressure sensor. Let me know. I am pretty sure that it's pretty easy. I know that I have to send the SS for the SD card low and the SS for the pressure sensor high and then pull the data off the pressure sensor and then set the SS for the pressure sensor low and the SS for the SD card high and then write to the SD card. But it's not as easy as

Code: [Select]
SPI.end(SSpin) or as easy as
Code: [Select]
analogWrite(SSPin, LOW)

Here is the code that I am working on for just the pressure sensor.

Code: [Select]
include <SPI.h>
//for the SD logger//
#include <SD.h>
// generate a MCKL signal pin
const int PRCS = 9; //was called clock in a previous version
// for the chipselect on the SD card//
const int SDCS = 4; //This was ChipSelect in a previous version

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);
 Serial.print("Initializing SD card...");

 // see if the card is present and can be initialized:
 if (!SD.begin(SDCS)) {
   Serial.println("Card failed, or not present");
   // don't do anything more:
   return;
 }
 Serial.println("card initialized.");
 
 //This code starts the SPI with the diddling pressure sensor
 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(PRCS, OUTPUT);
}

void loop() {
 //need to talk to the pressure sensor....
 analogWrite(SDCS,LOW);
 analogWrite (PRCS,HIGH);

//For the pressure sensor now.
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
 analogWrite (PRCS, 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);  
 //now talk to the SD logger
 analogWrite(SDCS,HIGH);
 analogWrite (PRCS, LOW);
 
 File dataFile1 = SD.open("PressureData",FILE_WRITE);

 if (dataFile1) {
   dataFile1.println(PCOMP);
   dataFile1.println(",");
   dataFile1.close();
 }
 else {
   Serial.println("error opening PressureData.txt");
 }
 
delay(1000); //just here to slow down the output so it is easier to read
}/code]

The pressure sensor code came from this forum http://forum.arduino.cc/index.php/topic,90025.msg675730.html
and the SD code is from the Arduino Libraries.

PaulS

Quote
But it's not as easy as

No, that is not the way to stop communicating with a specific SPI device. You need to set that device's SS pin to the not-active state (I never remember whether HIGH or LOW means active).

Quote
or as easy as

Of course not. The analogWrite() function only works on the PWM pins. digitalWrite(), on the other hand, works on any pin.

The art of getting good answers lies in asking good questions.

Caltoa

Can you make a minimal setup ?
For example an Arduino board, some voltage level converter for 5V <-> 3.3V and the sensor ?
Can you try to make a minimal sketch that only collects the calibration data ?

Or do you use the 3.3V SPI bus from the shield somehow ?
For the SPI bus, all data-in and data-out and clock are shared. Only the chip-select is a seperate signal for each chip.
So you can disable everything else, by setting those chip-selects as 'OUTPUT' and 'HIGH'. After that you can try to make the sensor work.

If you tell us how it is connected, with a minimal sketch, it will be a lot easier for us to give hints how you can communicate with the sensor.
Be sure to show us how you have disabled the other things on the SPI bus.

drews256

I think that my bigger question is how do I switch from the talking to the SD logger on the Wi-Fi shield. Its SS is on pin 4 to talking to the pressure sensor which is on pin 9. Also pin 10 is set to an output. I think I can make it work if I know how to switch between the SD logger and the Wi-Fi shield.

Pins:
MS5535C sensor attached to pins 10 - 13:
DIN (MOSI): pin 11
DOUT (MISO): pin 12
SCLK: pin 13
MCLK: pin 9

The MOSI, MISO, and SCLK all have to be on pins 11-13 to make the SPI the same for the internal SD logger and the pressure sensor. Is it as easy as setting the SS pin for the SD logger higher, and the SS pin for the Pressure Sensor low?

Caltoa

Yes, very easy.

The SS (chip-select) is hardware defined on pin 10.
http://arduino.cc/en/Hacking/PinMapping168
But you don't have to use pin 10 at all.
However, the SPI hardware requires that pin 10 is set as output, or it won't work.

So you set pin 10 to output. You may use pin 10 for chip-select for a device or not.
Use any other pin for the chip-select pins of the SPI devices.
All libraries for SPI devices are able to set the chip-select to a certain pin, you have to change that to match the wiring.
When you don't use a certain chip-select, make it output and set it high. That way that device is disabled and won't mess up the SPI bus.

You have not answered my question about the 5V Arduino Uno and the 3.3V sensor. If you don't care about that, you should stop what you are doing, and solve that first.

drews256

Yep. I am on the pin 10 as an output. I have used SPI before just not two at the same time. I do care about the 3.3 V but I am pulling 3.3 V from the Arduino.  Is there something terribly wrong with that? Does the SPI not work if I am using 5V to the SD card and then 3.3 V to the pressure sensor?

Caltoa

You can not connect 5V SPI output signals like MOSI, chip-select and CLK to a 3.3V SPI device.
The Wifi shield uses the TXB0108 for that.

The signals from the Arduino Uno are still 5V signals, you can not connect them to your 3.3V SPI sensor. Perhaps a few resistors will be enough.

drews256

Alright so I can't use the 5V. Now I am running the pressure sensor into a logic converter. And I can get pressure and temperature data when the SD card is plugged in. Or I can unplug the pressure sensor and get the SD card to work. Is it the SD library that is making it not possible to see the SD card when the pressure sensor is plugged in?

Caltoa

No, the SD library can work along other things on the SPI bus.
The SPI has only one Master, that is the Arduino. And the Arduino selects which device is made active to communicate with.
But as I wrote, you have to be sure that the chip-select of everything else is high so those devices are disabled.

drews256

I get what you're saying. My code is pretty long I don't want to post the whole thing. There are many things going on than just this and it's not perfect by any stretch of the imagination. And so if I set all the SPI pins high and then when I want to talk to the SD card I set it low to write to the SD card. Then set the SD card high and set the pressure sensor low and  talk to the pressure sensor. Is that the idea? Because I feel like that is what I am doing. I am communicating to the pressure sensor and the SD card separately. So everything is wired correctly. Would you be willing to look at the whole code?

Caltoa

I might have a glance at the code.

I hope you are talking about all the chip-select pins.

Every library is like this:
1 ) chip-select pin low
2 ) SPI.transfer
3 ) chip-select pin high.

You can make a function for the pressure sensor in the same way.


drews256

The whole code is to long to fit in a forum post. It is attached. Thank you! I feel like it is something relatively simple.

Thanks again!

Caltoa

Is all the changing of the SPI data mode necessary ? That makes it complicated !

You have one long block of code in the loop() function. Can you make a few functions ?
You don't have to make the SDCS low, the SD library will do that. That is how SPI works, every library makes its own device temporary active.
You never make PRCS low, so the sensor communication is never activated.

There is a better way to do this.
For example the function to reset the sensor, can you make PRCS low and high in that function. So the SPI bus is ready after that function.
Can you make another function to communicate with the sensor, that also makes the PRCS low and high again.
For example the code to get the calibration words is repeated a few times, that is something to put into a function.
I have not studied the datasheet of the sensor very well, so I don't know if the code will work.

If you request 10 times data from the sensor, the chip-select migh go ten times low and high. That is normal. Keeping the chip-select low is never done, only when the sensor datasheet tells to do so.

drews256

I was hoping to get the code out and then start making functions of things that needed to get repeated. Maybe thats not the way to go about it.  :smiley-eek-blue:

But I will keep working on it. I do send the PRCS low right before I try to communicate with it. But it is in the loop() function. Here:

Code: [Select]
//For the pressure sensor now.
  digitalWrite (PRCS, LOW) ;
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
 
  resetsensor();//resets the sensor - caution: afterwards mode = SPI_MODE0!


Either way I will work on simplifying. Thanks!

Caltoa

Sorry, I missed that 'LOW'  :smiley-red:

You can have a look at the functions for the SD card.
https://github.com/arduino/Arduino/blob/master/libraries/SD/utility/Sd2Card.cpp
Search for : "chipselect".
The chipselect is made low when something has to be done, and when ready (or an error occurs) it is made high.
However, they don't make it high after every command. Sometimes a number of cardCommand() is done and the chipselect is kept low.

What has to be done now to make the sensor work ?

Go Up