Shop OBEX P1 Docs P2 Docs Learn Events
MS5607 Altimeter (Product ID: 29124) Testing and Data Processing — Parallax Forums

MS5607 Altimeter (Product ID: 29124) Testing and Data Processing

c07Brian.Kesterc07Brian.Kester Posts: 36
edited 2014-06-26 16:52 in Accessories
I've been working on getting the MS5607 Altimeter (Product ID: 29124) working for a while and I have finally gotten to the point where the data I'm getting is somewhat close to reality, but I still don't trust it. I am programming in Propeller C on a Propeller Activity Board using SPI and I am at the Air Force Academy in Colorado at approximately 7300 ft (2225 m). The temperature seems accurate enough, at least inside, but the pressure is off by ~(-300 mbars). When measuring temperature outside in direct sunlight, the temperature value was off by approximately 9 deg C, though inside, it appears to be accurate. My questions are:

1) The sensor is factory calibrated and already has offsets, so I am wondering if it is still standard practice to add an additional offset.
2) If I do add an offset, what is the best way to calibrate? Should I just take some measurements outside with known pressure/temperature values? I have access to a thermal vacuum chamber, but this seems excessive.
3) The nearest weather sensor gives pressure in "in Hg." I found a conversion on-line, but it converts from "in Hg (32F)" to mbar. Since it indicates "32 F," I assume the conversion might be different at our actual temperature around 70 deg. Is that significant?
4) I have run into issues with needing 64-bit variables for the conversion from digital counts to actual temp/pressure. 64-bit variables do not appear to be supported on the Propeller chip. Is there a way around this limitation?
5) Is there a reason why the temperature sensor would be accurate inside, but inaccurate outside?

Any insight into any of these issues would be appreciated!

Comments

  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-04 15:06
    So I have an update: I figured out I needed to convert my pressure to sea-level pressure with the following formula: P_0=P*(1-(0.0065*h/(T+0.0065*h+273.15)))^(-5.257), which can be found at the following link: http://keisan.casio.com/exec/system/1224575267. This is basically the formula listed in the data sheet solved for P_0 instead of h. My pressure values are still somewhat off by ~20mbar (0.6 in Hg) and my altitude is off by about 85 m, which seems high in looking at the datasheet. Also, I noticed on another forum that the sensor is sensitive to direct sunlight, which is what likely caused my earlier problem with the temperature spike. I am going to continue messing round with this, but would still appreciate any insight into the 64-bit variable problem using propeller C and into what the best way to test its accuracy might be.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-06-04 17:26
    For calibration, compare the MS5607 with the station pressure while standing next to a reliable nearby weather station or airport. That is the absolute air pressure, not corrected for altitude. Absolute pressure is what the MS5607 should be reading and it should be quite close. Here is a NWS page that has pressure readings side by side for station pressure, altimeter setting, and the extrapolated mean sea level pressure at Colorado Springs. I bet the Air Force has a pretty nice station of their own up there!

    There are several different algorithms that can be used to extrapolate to sea level, using the standard atmosphere formulas with/without standard/special corrections for lapse rate (temperature vs altitude). Discrepancies are not unheard of.

    For the math, I suppose you have looked at the Spin version? It's pretty easy to try the well vetted demo to compare with your own code. Phil made good use of his umath.spin methods, 64 bit unsigned. I have no idea how much work it would take to convert that to C (but don't ask Phil to C it!!)
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-04 17:51
    Thanks, Tracy. I'll go look at the spin code. I haven't ever worked with spin, so I didn't really consider checking out the code, but I will take a look at it.
  • GenetixGenetix Posts: 1,754
    edited 2014-06-04 19:14
    Brian,

    I think link has the information you need.
    http://forums.parallax.com/showthread.php/134753-Parallax-s-New-Altimeter-Barometer-Module?highlight=MS5607

    This is from #37
    Here's a chart you can use to adjust your pressure readings (approximately) to sea level:
    http://www.novalynx.com/manuals/bp-e...ion-tables.pdf
    Find your altitude on the chart, then add the deviation from zero to your pressure reading to get the adjusted reading.

    This is from #68
    How to get sea level pressure (SLP) at your location. Find the nearest airport and it's identifier for example KLAX = Los Angeles.
    Look it up here - http://www.aviationweather.gov/adds/metars/ you can switch to 'translated' weather by the search box to make reading easier.
    The drop down box should be set to past 1 hour. Hit Submit. If you're between two airports, put them both in and interpolate

    I hope that helps.
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-05 08:15
    Thanks, Genetix. I'm not sure if I'm having weird browser behavior, but the second link appears to redirect me to the root website for the pdf and I cannot find the pdf table from there. I had actually looked at that post, which is partially where my update had come from. They also mentioned the direct sunlight causing sensor issues. Thank you for gathering the information, though!
  • GenetixGenetix Posts: 1,754
    edited 2014-06-05 15:40
    Sorry about that Brian. It's a long thread and I didn't think you wanted to read.

    I checked and I have a copy of that table on my hard drive so here you are.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-06-05 15:50
    The original thread concerning the MS5607 and #29124 is highly informative,
    Parallax-s-New-Altimeter-Barometer-Module
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-06 16:21
    Thanks, Tracy... I think that's the thread Genetix was referencing and you're right, it definitely started me off on the right track. Following your advice for the 64 bit problem, I checked out the SPIN code and found the following section:
    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
    

    My first problem is that there does not appear to be a comparable operator to "**" in C, so I started down the path of creating my own function to accomplish this that can work with Propeller C. I THINK I came up with a viable solution and would appreciate any feedback. The test script is below. I plan to turn this into a function called mult_high to return the same result as the "**" operator in SPIN and then try to follow along the logic from the SPIN code above. I figure there are probably a couple more hurdles to overcome in implementing the "_dadd" "_umult" and "~>" functions above, but it seems doable. I'll post the final result once I'm done in case anyone is interested.
    #include "simpletools.h"                      // Include simple tools
    
    int A=-2147483405, B=-2147482751;
    int mask_low=0x0000FFFF;
    char sign=1;
    unsigned int AH,AL,BH,BL;
    unsigned int BLAL,BLAH,BLA,BLA1,BLA2,BHAL,BHAL1,BHAL2,BLA_BHAL1,BLA_BHAL,BHAH;
    
    int main()                                    // Main function
    {
      unsigned int Result_Low=A*B;
    
    /*First check for and store sign of result*/
      char signA=((unsigned int) A&1<<31)>>31;
      char signB=((unsigned int) B&1<<31)>>31;
    
      if (signA!=0)
        A=-A;
    
      if (signB!=0)
        B=-B;
    
      if ((signA==0&&signB==0)||(signA!=0&&signB!=0))
        sign=0;
    
      print("signA=%d, signB=%d, sign=%d\n",signA, signB, sign);
        
    /*Break numbers into halves*/
      AH=(unsigned int) A>>16; 
      AL=A&mask_low;
      BH=(unsigned int) B>>16;
      BL=B&mask_low;
    print("A=%d\nB=%d\nAH=%d, AL=%d\nBH=%d, BL=%d\n\n",A,B,AH,AL,BH,BL);
    
      BLAL=(BL*AL)>>16; //Shifted to the right to line up with BLAH
      BLAH=(BL*AH);
      BLA=BLAL+BLAH;
      BLA1=BLA&mask_low;
      BLA2=BLA>>16;
    //  print("BLAL=%b\n BLAH=%b\n BLA=%b\n BLA1=%b\n BLA2=%b\n",BLAL,BLAH,BLA,BLA1,BLA2);
      BHAL=(BH*AL);
      BHAL1=BHAL&mask_low;
      BHAL2=BHAL>>16;
    //  print("BHAL=%b\n BHAL1=%b\n BHAL2=%b\n",BHAL,BHAL1,BHAL2);
      BLA_BHAL1=(BLA1+BHAL1)>>16;
      BLA_BHAL=BLA2+BHAL2+BLA_BHAL1;
      BHAH=(BH*AH);
    //  print("BLA_BHAL1=%b\n BLAH_BHAL=%b\n BLA=%b\n BHAH=%b\n",BLA_BHAL1,BLA_BHAL,BHAH);
      signed int Result_High=BLA_BHAL+BHAH;
      if(sign==1)
        Result_High=~Result_High;
      print("Result_High = %x\n",Result_High);
      print("Result_Low  = %x",Result_Low);
    }
    

    The code above was written with the logic of doing binary multiplication by hand, accounting for all carries and truncating off the lower 32 bits of the final answer without ever using a variable or intermediate result of larger than 32 bits. The inputs A and B could be any signed 32-bit int. Again, any feedback would be welcome... I am certainly a novice programmer and there's probably a more efficient way to do this... that, and I just learned how to do binary arithmetic yesterday... :)
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-06 16:22
    Awesome, thanks for the table, Genetix! You're right, I didn't want to read it, but I figured it was good for me :)
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-06 22:25
    Had to modify the bottom section to deal with special cases with a negative result. It needs the following "if" statement:
    if(sign==1)
        Result_High=~Result_High;
        if ((A*B)==0x00000000)
          Result_High+=1;
      print("Result_High = %x\n",Result_High);
      print("Result_Low  = %x",Result_Low);
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-06-07 13:11
    I'm a bit shocked that C does not include the ** operator. It is so useful for double precision and for quick fractional multiplication.

    I wrote firmware for the MS5606/MS5803 for the BASIC Stamp. The Stamp has only 16 bit integers, so the formulas as given would have required triple or quad precision. I found it possible to refactor the math so that the intermediate results fit in 32 bits. I'm attaching an exploratory spreadsheet--Oh, but I'm hazy on how it worked now. The Stamp program does make heavy use of its ** operator.
  • SRLMSRLM Posts: 5,045
    edited 2014-06-07 21:23
    libpropeller has C++ code for the MS5611, which IIRC is code and hardware compatible with the MS5607. It uses int64_t for the math.

    https://github.com/libpropeller/libpropeller/blob/master/libpropeller/ms5611/ms5611.h
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-09 15:27
    SRLM wrote: »
    libpropeller has C++ code for the MS5611, which IIRC is code and hardware compatible with the MS5607. It uses int64_t for the math.
    Thanks, SLRM! Do you happen to know if the same approach might be used in C, or will it only work in C++? I'm hesitant to learn another programming language just to solve this problem...
  • SRLMSRLM Posts: 5,045
    edited 2014-06-09 16:47
    Thanks, SLRM! Do you happen to know if the same approach might be used in C, or will it only work in C++? I'm hesitant to learn another programming language just to solve this problem...

    It shouldn't be very difficult to convert from C++ to C, if that's what you want. C++ is really a few things bolted onto C so it's pretty easy to pick up. And, in any case, the math part should be pretty much cut and paste if you so wish.
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-10 10:02
    SRLM wrote: »
    It shouldn't be very difficult to convert from C++ to C, if that's what you want. C++ is really a few things bolted onto C so it's pretty easy to pick up. And, in any case, the math part should be pretty much cut and paste if you so wish.

    The C++ code looks rather foreign to me. It seems to be an entirely different way/style of coding, which is rather daunting to a novice programmer such as myself.

    Regardless, the C code appears to need more than cut and paste in the math. I tried that and I'm getting out gibberish for everything after the temperature. Although, the code for the temperature DID work and that saved me a few lines of code, so that was good at least. C just doesn't seem to handle the int64_t data type the same. SIDE did not give me an error, but it DID color the int64_t the same color as it does the word "include" in the statement "#include" if that makes sense. Normally data types are colored blue, but it colored int64_t the puke yellow color. I also noticed some of the shifts (specifically for c1_ and c2_) are slightly off. My data sheet says to shift them 16 and 17 respectively while the code on libpropeller shifts them only 15 and 16.

    Is there something I may be missing?

    In the meantime, I'm back to using my custom functions. I've created functions to return the upper 32 bits when adding and multiplying and have been able to calculate up through SENS. The last thing to figure out is the final calculation of pressure.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-06-10 12:39
    The MS5611 is a higher resolution version of the '5607, 10cm vs 20cm. That accounts for the difference in shifts. Note that the Start method in Phil's spin code allows you to choose either. He separated the low level routines,
    _cur_temp_press_5611
    and
    _cur_temp_press_5607

    Parallax subsequently settled on using the '5607 in the product #29124.
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-10 14:14
    Thanks for the additional info, Tracy! Quick update: I am now able to calculate the pressure and temperature on the chip itself. Took a lot of juggling and a number of custom functions to handle to 64-bit math, but it appears to be working. Next step is getting the thing to actually spit out altitude...
  • c07Brian.Kesterc07Brian.Kester Posts: 36
    edited 2014-06-16 10:57
    I think I can report full success. I now have a working sensor that reports and records the raw D1, D2 values (for bug detection more than anything right now), temperature, pressure, and altitude. The code is set up to do 2nd order temperature correction and calculate an altitude.

    Differences (that I know of) compared to the SPIN code:
    1) Not as user-friendly... no options to report avg, median values or do unit conversions
    2) Only uses linear interpolation between points on the altitude table
    3) Uses the stratosphere pressure/altitude model for altitudes above 11,000m (the SPIN code appears to use only the troposphere model)
    4) Used excel to generate the altitude table which resulted in slightly different values even when using the same model
    5) User can only enter a local sea-level pressure correction to the altitude model rather than the option to enter starting altitude and compute the local sea-level correction.
    6) No user interface. All user-selected values (such as local sea-level pressure correction) would have to be manually entered into the code, though I did try to make this easy by having those values one might want to change at the top with comments.

    There are probably a number of other differences, but those are the main ones I can think of. Most of them could probably be easily modified, but the code appears to work for my uses and it did not seem to be worth my time to make it more robust. I can attach the latest version of the C code, but it relies on a small personal library for the 64-bit integer math and I wasn't sure what I would need to do to include that.
  • FrannyFranny Posts: 127
    edited 2014-06-26 16:42
    What pins are you using?
  • FrannyFranny Posts: 127
    edited 2014-06-26 16:52
    Hi, Does anybody have SimpleIDE C code for the MS5607 Altimeter Module? I just need to be able to get a variable integer out of it that goes up and down accordingly.
    PS> There's some links here but they don't work any more.
Sign In or Register to comment.