Shop OBEX P1 Docs P2 Docs Learn Events
Help: MS5607 Altimeter using SPI, C Code, and Propeller Activity Board — Parallax Forums

Help: MS5607 Altimeter using SPI, C Code, and Propeller Activity Board

c07Brian.Kesterc07Brian.Kester Posts: 36
edited 2014-06-06 21:10 in Propeller 1
I am trying to get the MS5607 Altimeter to work using the SPI Mode in C code on the Propeller Activity Board. A picture of the setup and the current (messy) iteration of the code are attached. I also attached the datasheet (it is not currently available on the Parallax website), and a screenshot of the output. I am pulling in numbers from the PROM and ADC, but they do not appear to be reasonable. The math for the conversion is probably also off, because I was not sure of the best way to implement the exponentials, so I used the pow() function from math.h after testing its basic functionality and ability to give reasonable integer results for basic calculations. At the very least, the SENS variable calculation is wrong, but I am not sure where the problem is happening and it is hard to believe the D1 and D2 numbers being read from the sensor. I would appreciate any help in identifying what I may be doing wrong. I am including a stripped-down version of my code in text form below. I am using Simple IDE and the associated libraries for all my coding. I started with the SPI tutorial for the Accelerometer module and used that as the basic template for this project. The code below does not include any loops or writing to the SD card yet because I wanted to get data that made sense first before adding on those layers... the loops and SD card writing are commented out in the attached code.
#include "simpletools.h"                          // Include simpletools lib
const int SDI=3;   // Chip SDI/SDA pin
const int SDO=1;    // Chip SDO pin
const int SCL=5;    // Chip CLK pin
const int CS=0;     // Chip CS pin
const int PS=8;   // Chip PS pin
const int pt=500; // Pause time between data points
const int RESET  = 0x1E;        // Reset command
const int ADCread = 0x00;       // ADC Read command
const int PROMreadC1 = 0xA2;      // Prompt read PROM C1
const int PROMreadC2 = 0xA4;      // Prompt read PROM C2
const int PROMreadC3 = 0xA6;      // Prompt read PROM C3
const int PROMreadC4 = 0xA8;      // Prompt read PROM C4
const int PROMreadC5 = 0xAA;      // Prompt read PROM C5
const int PROMreadC6 = 0xAC;      // Prompt read PROM C6
const int ConvertD1 = 0x48;   // Convert D1 for ADC read (OSR=4096)
const int ConvertD2 = 0x58;   // Convert D2 for ADC read (OSR=4096)
unsigned int Cread(int READ);    //Function prototype
/* Initialize calculation values */
unsigned long int D1, D2;
signed long int dT, TEMP, P;
signed long long int OFF, SENS;
unsigned int c1, c2, c3, c4, c5, c6;
int main()                                        // Main function
{
  low(PS);                                 // Select SPI Protocol
  high(CS);   // CS high (inactive)
  low(CS);
  shift_out(SDI, SCL, MSBFIRST, 8, RESET);  // Reset to ensure coeff loaded into PROM
  high(CS);
  pause(500);
  c1 = Cread(PROMreadC1);   //Reads c1 value
  c2 = Cread(PROMreadC2);   //Reads c2 value
  c3 = Cread(PROMreadC3);   //Reads c3 value
  c4 = Cread(PROMreadC4);   //Reads c4 value
  c5 = Cread(PROMreadC5);   //Reads c5 value
  c6 = Cread(PROMreadC6);   //Reads c6 value
print("%cc1 = %d, c2 = %d, c3 = %d \n", HOME, c1, c2, c3);
print("c4 = %d, c5 = %d, c6 = %d\n", c4, c5, c6);
/* Read digital pressure and temperature value */      
      low(CS);                              // CS low selects chip   
      shift_out(SDI, SCL, MSBFIRST, 8, ConvertD1);  // Prompt D1 ADC conversion
      high(CS);
      pause(100);
      low(CS); 
      shift_out(SDI, SCL, MSBFIRST, 8, ADCread);  // Prompt D1 ADC read
      D1 = shift_in(SDO, SCL, MSBPOST, 24);   // Read D1 value
      high(CS);     
      low(CS);
      shift_out(SDI, SCL, MSBFIRST, 8, ConvertD2);  // Prompt D2 ADC conversion
      high(CS);
      pause(100);
      low(CS); 
      shift_out(SDI, SCL, MSBFIRST, 8, ADCread);  // Prompt D1 ADC read
      D2 = shift_in(SDO, SCL, MSBPOST, 24);   // Read D2 value
      high(CS);                                      // De-select chip
      print("D1=%d, D2=%d\n", D1, D2);
/* Calculate temperature */
      dT=D2-(c5*pow(2,8));    // Difference between actual and ref temp
      TEMP=2000+((dT*c6)/pow(2,23));    // Actual Temperature
      print("dT = %d, TEMP = %d\n", dT, TEMP);
/* Calculate temperature-compensated pressure */
      OFF=(c2*pow(2,17))+((c4*dT)/pow(2,6));
      SENS=c1*pow(2,16)+(c3*dT)/pow(2,7);
      P=(D1*SENS/pow(2,21)-OFF)/pow(2,15);
      print("OFF=%d, SENS=%d, P=%d\n", OFF, SENS, P);
}

unsigned int Cread(int READ)
{
    unsigned int C;
    low(CS);
    shift_out(SDI, SCL, MSBFIRST, 8, READ);  // Prompt Coeff PROM read
    C = shift_in(SDO, SCL, MSBPOST, 16);   // Read coeff value
    high(CS);
    return C;
}
Personal notes: I am pretty new to this community, only having been working on this for the last couple weeks. The purpose of this project is to make sensors available for students for launching high altitude balloons. I don't necessarily need the altitude calculations to work because I could have the students do that as part of the post-processing, but ideally, I would like to do the altitude calculations on-board so the students could compare them to post-processing. So far, I have successfully implemented the 3-axis gyroscope (L3G4200D) and 3-axis accelerometer (MMA7455) sensor modules.

Comments

  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-05-15 11:42
    I am continuing to trouble-shoot the math portion and I think I understand at least part of my problem. I wrote a simplified version of the code to just do the math portion and hard-code in values for the coefficients and digital values. I've tried to use "long long int" for a couple of the variables because the datasheet suggests using 64-bit variables. When I use simple "int" variables, the variable OFF becomes 2147483647, which is (2^32)/2, so it seems obvious I am reaching the limit of the ability to store the value. But when I use "long long int" variables, my program gives even weirder results where OFF is negative and SENS=0. I assume the Propeller, as a 32-bit processor, is not capable of processing 64-bit variables. Is there any way around this limitation, or do I need to just record the raw digital counts and do post-processing. Either way, after checking the calculations, I am still not obtaining reasonable values from the sensor. I am getting a pressure of 2230.05 mBar and a temperature of 39.49 C. I am in Colorado Springs, CO in a climate controlled building, so I was expecting a pressure around 1100 mBars and temperature about 20.5 C.
  • BasilBasil Posts: 380
    edited 2014-05-17 12:24
    Following, I have this sensor on a board also but have not yet tried to tackle the 64bit issue.
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-05-21 05:13
    Thanks, Basil. Are you getting values from the ADC that actually make sense? How does your code compare to mine? I assume you're also programming in C and using SPI protocol?
  • BasilBasil Posts: 380
    edited 2014-05-21 13:06
    I will be using Spin and i2c, so things will be a little different. Following this thread incase I run into 64bit issues :)

    Board not yet assembled
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-05-27 16:27
    I have re-written a portion of the code because I suspected I was having a problem with variable lengths since the coefficients should be a max of 2^16 (65536) and I was seeing higher values than that. Now that I re-wrote it, all my values are suspiciously close together, all around 65000, which is also close to the max value. The example values in the datasheet are more spread out than this. I suspect I must be doing something wrong with the shift_in command, but I cannot imagine for the life of me what it might be. I would really appreciate any feedback. I am including the modified version of my code below.
    unsigned short int Cread(int READ)
    {
        unsigned short int C;
        low(CS);
        shift_out(SDI, SCL, MSBFIRST, 8, READ);  // Prompt Coeff PROM read
        high(CS);
     
        low(CS);
        C = shift_in(SDO, SCL, MSBPRE, 16);   // Read coeff value
        high(CS);
        return C;
    }
    
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-06 16:28
    @Basil: Update on the 64-bit issue in case you're interested. You're using SPIN, so this should be easy. The developers of the example code already took care of it. It appears to be a little more complicated in C because of the lack of the ** operator among other things. Here's how they did it in SPIN in case you're interested:
    PRI _cur_temp_press_5607 | d1, d2, dt, offh, offl, sensh, sensl, ph, pl
    
      d1 := _read_adc(RSLT_D1)
      d2 := _read_adc(RSLT_D2)
      
      dt := d2 - c5 << 8
      cur_temp := 2000 + ((dt ** c6) << 9 + (dt * c6) >> 23)
    
      offh := c4 ** dt
      offl := (c4 * dt) >> 6 | offh << 26
      offh ~>= 6
      _dadd(@offh, c2 >> 15, c2 << 17)
    
      sensh := c3 ** dt
      sensl := (c3 * dt) >> 7 | sensh << 25
      sensh ~>= 7
      _dadd(@sensh, c1 >> 16, c1 << 16)
    
      _umult(@ph, d1, sensl)
      ph += d1 * sensh
      pl := pl >> 21 | ph << 11
      ph ~>= 21
      _dsub(@ph, offh, offl)
      cur_press := ph << 17 | pl >> 15
    
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-06 16:30
    For anyone who may be interested in getting this to work in Propeller C with SPI, I will have a code update soon-ish with basic functionality. One of the most significant issues I was running into was with the shift_in function, which apparently had a bug in it. I am now getting reasonable values and am currently working on doing the on-board calculations and tackling the 64-bit issue.
  • BasilBasil Posts: 380
    edited 2014-06-06 21:10
    Thanks Brian for your work :) I haven't had a chance to work on it yet but this will save a lot of headache!
Sign In or Register to comment.