Translation of C math

for pressure sensor

Marco
Benutzer
Avatar
Gender: n/a
Location: Italy
Posts: 270
Registered: 10 / 2004
Subject:

Translation of C math

 · 
Posted: 24.12.2012 - 14:42  ·  #1
Hello,
I am working on the porting of some C source to control a BMP085 pressure sensor.
I have succesfully converted the I/O part, which use I2C interface.
But I have problems in translation of the math calculation which must be done
to adjust the raw data from sensor.
Can you help ?

Here is the original C code:
Code

// read temperature and pressure from sensor
void readSensor() {
  int  ut= readUT();
  long up = readUP();
  long x1, x2, x3, b3, b5, b6, p;
  unsigned long b4, b7;

//calculate true temperature
  x1 = ((long)ut - ac6) * ac5 >> 15;
  x2 = ((long) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  temperature = (b5 + 8) >> 4;

//calculate true pressure
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((int32_t) ac1 * 4 + x3)<<oversampling_setting + 2) >> 2;
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
  b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  pressure = p + ((x1 + x2 + 3791) >> 4);
}


and here my AVRco translation attempt of Temperature reading:

Code

var
    vAC1        : integer;
    vAC2        : integer;
    vAC3        : integer;
    vAC4        : word;
    vAC5        : word;
    vAC6        : word;
    vB1         : integer;
    vB2         : integer;
    vMB         : integer;
    vMC         : integer;
    vMD         : integer;
...

procedure BMP085_CalcTemperature;
var
     ctX1, ctX2, ctB5  : longint;
begin
    //calculate true temperature
    ctX1 := longint(UTemp - vAC6);
    ctX1 := (ctX1 * longint(vAC5)) shr 15;
    ctX2 := (longint(vMC shl 11)) / (ctX1 + longint(vMD));   // here error
    ctB5 := ctX1 + ctX2;
    vTemperature := integer((ctB5 + 8) shr 4);
end;



I am not sure about the casting to longint in first lines,
anyway I get "Float divide expected " on 3rd line...
chefe
Benutzer
Avatar
Gender: n/a
Age: 50
Posts: 5
Registered: 07 / 2010
Subject:

Re: Translation of C math

 · 
Posted: 24.12.2012 - 15:35  ·  #2
Hello Marco,
with C all types can be mixed regardless of a nonsense result.
Here the problem is that the expression consists o9f integer but you use the float divide "/"
which is illegal in Pascal. Use "DIV" instead and it works.
Marco
Benutzer
Avatar
Gender: n/a
Location: Italy
Posts: 270
Registered: 10 / 2004
Subject:

Re: Translation of C math

 · 
Posted: 25.12.2012 - 09:29  ·  #3
Thank you,
I was used to think that "/" where for any number type...
ERICH KATH
Benutzer
Avatar
Gender: n/a
Location: 61206 Wöllstadt
Homepage: ct-gmbh.de
Posts: 29
Registered: 04 / 2005
Subject:

BMP085

 · 
Posted: 09.04.2013 - 09:46  ·  #4
Hello Marco,

can you provide the complete code für the BMP085? Including the I2C part.

Thank you !

ERICH
Marco
Benutzer
Avatar
Gender: n/a
Location: Italy
Posts: 270
Registered: 10 / 2004
Subject:

Re: Translation of C math

 · 
Posted: 09.04.2013 - 10:46  ·  #5
Hi,
I can give you the unit I have developed, but not sure it's correct.
I have stopped dev because the chip I was using had the Temperature sensor broken...
Ordered a newone on Sparkfun; then I will verify if my translation from C routines is good.

Regards,
Marco

Code

Unit BMP085;

|||  library for Barometric sensor.  chip Bosch BMP085

(*
    Sensor on I2C bus as Slave.
    xMega su TWI_E  ovvero pins PE0, PE1
    Get pressure, altitude, and temperature from the BMP085.
*)


interface
// global part

Uses  Vars in 'Vars.pas';

{--------------------------------------------------------------}
{ Const Declarations }
const

{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
type

{--------------------------------------------------------------}
{ Var Declarations }
var

    vTemperature  : integer;
    vPressure     : longint;
    vAltitude     : float;

    fTemperature:             float;
    Pressure:                 integer;
    vertSpeed:                integer;


{--------------------------------------------------------------}
{ functions }

// Public API
procedure BMP085_init;                  // configura accel settings
procedure BMP085_calibration;
procedure BMP085_ReadUT;    // read uncompensated Temperature value
procedure BMP085_ReadUP;

procedure BMP085_CalcTemperature;
procedure BMP085_CalcPressure;
procedure BMP085_CalcAltitude;

// Local functions



implementation
// local part

{--------------------------------------------------------------}
{ Type Declarations }
type
  st14           = string[14];
  TPtext         = pointer to st14;

{--------------------------------------------------------------}
{ Const Declarations }
const

    // -- BMP085 addresses --
    BMP085_ADDRESS   : byte = $77;  // I2C address of BMP085

    BMP085_R     : byte = $EF;
    BMP085_W     : byte = $EE;

    oversampling_setting     : byte = 0;
    pressure_conversiontime  : array [ 0..3 ] of byte = ( 5, 8, 14, 26 );      // delays for oversampling settings 0, 1, 2 and 3
    

    // ------- Calibration Register names -------
    addr_AC1        : byte = $AA;
    addr_AC2        : byte = $AC;
    addr_AC3        : byte = $AE;
    addr_AC4        : byte = $B0;
    addr_AC5        : byte = $B2;
    addr_AC6        : byte = $B4;
    addr_B1         : byte = $B6;
    addr_B2         : byte = $B8;
    addr_MB         : byte = $BA;
    addr_MC         : byte = $BC;
    addr_MD         : byte = $BE;

   BMP085_OK        : byte = 1; // no error
   BMP085_ERROR     : byte = 0; // indicates error is predent

   BMP085_NO_ERROR     : byte = 2; // initial state


{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var

    dev_address     : integer;
    error_code : byte;                    // Initial state

    UTemp           : integer;
    
    arrUP           : array [ 0..3 ] of byte;
    intUP  [@arrUP] : longint;                   // 4bytes, used max 3.
    
    UncompPress            : longint;
    mswUP [@UncompPress+2] : word;
    lswUP [@UncompPress]   : word;

    vAC1        : integer;
    vAC2        : integer;
    vAC3        : integer;
    vAC4        : word;
    vAC5        : word;
    vAC6        : word;
    vB1         : integer;
    vB2         : integer;
    vMB         : integer;
    vMC         : integer;
    vMD         : integer;

    altA      : float;
    altB      : float;
    altC      : float;
    

{--------------------------------------------------------------}
{ functions }


procedure BMP085_init;
begin
    // BMP085 r/w address $EF,$EE diventano $77 BMP085_ADDRESS !
    if TWIstatE(BMP085_ADDRESS) then
        Writeln(SerOutF0, 'Sensor OK !');
        Cmd_Result := True;
    else
        Writeln(SerOutF0, 'no response...');
    endif;
end;

procedure BMP085_CalcTemperature;   //calculate true temperature
var
     ctX1, ctX2, ctB5  : longint;
begin
    ctX1 := longint(UTemp - vAC6);
    ctX1 := (ctX1 * longint(vAC5)) shr 15;
    ctX2 := (longint(vMC shl 11)) div (ctX1 + longint(vMD));
    ctB5 := ctX1 + ctX2;
    vTemperature := integer((ctB5 + 8) shr 4);
(*
  int  ut= readUT();
  long up = readUP();
  
  long x1, x2, x3, b3, b5, b6, p;
  unsigned long b4, b7;

  //calculate true temperature
  x1 = ((long)ut - ac6) * ac5 >> 15;
  x2 = ((long) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  vTemperature = (b5 + 8) >> 4;
*)
end;

procedure BMP085_CalcPressure;    //calculate true pressure
var
     cpX1, cpX2, cpX3, cpB3, cpB5, cpB6, p : longint;
     cpB4, cpB7 : longword;
begin
    cpB6 := cpB5 - 4000;
    // Calculate cpB3
    cpX1 := (longint(vB2) * (cpB6 * cpB6 shr 12)) shr 11;
    cpX2 := longint(vAC2) * cpB6 shr 11;
    cpX3 := cpX1 + cpX2;
    cpB3 := ((longint(vAC1) * 4 + cpX3) shl oversampling_setting + 2) shr 2;
    
    // Calculate cpB4
    cpX1 := longint(vAC3) * cpB6 shr 13;
    cpX2 := (longint(vB1) * (cpB6 * cpB6 shr 12)) shr 16;
    cpX3 := ((cpX1 + cpX2) + 2) shr 2;
    cpB4 := (longword(vAC4) * longword(cpX3 + 32768)) shr 15;
    cpB7 := (longword(UncompPress) - cpB3) * (50000 shr oversampling_setting);
    if cpB7 < $80000000 then
        p := longint((cpB7 shl 1) div cpB4);
    else
        p := longint((cpB7 div cpB4) shl 1);
    endif;

    cpX1 := (p shr 8) * (p shr 8);
    cpX1 := (cpX1 * 3038) shr 16;
    cpX2 := (-7357 * p) shr 16;
    vPressure := p + ((cpX1 + cpX2 + 3791) shr 4);
(*
  int  ut= readUT();
  long up = readUP();

  long x1, x2, x3, b3, b5, b6, p;
  unsigned long b4, b7;

  //calculate true pressure
  b6 = b5 - 4000;
  // Calculate B3
  x1 = (b2 * (b6 * b6 >> 12)) >> 11;
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((int32_t) ac1 * 4 + x3)<<oversampling_setting + 2) >> 2;
  // Calculate B4
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
  b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  pressure = p + ((x1 + x2 + 3791) >> 4);
*)
end;

procedure BMP085_CalcAltitude;
begin
    altA := float(vPressure) / 101325;
    altB := 1 / 5.25588;
    altC := pow(altA, altB);
    altC := 1 - altC;
    vAltitude := altC / 0.0000225577;
(*
float calcAltitude(float pressure){
  float A = pressure/101325;
  float B = 1/5.25588;
  float C = pow(A,B);
  C = 1 - C;
  C = C / 0.0000225577;
  return C;
*)
end;

procedure BMP085_ReadUT;    // read Uncompensated Temperature value
begin
    TWIOutE(BMP085_ADDRESS, $F4, $2E );     // read temper reg.
    
    mDelay( 5 );
    
    TWIOutE(BMP085_ADDRESS, $F6);           // $F6, F7
    TWIinpE(BMP085_ADDRESS, iTmp);          // 2 bytes only:  msb, lsb
    array2consolle(ptrB(@iTmp), 2);         // input recFrame 1:2 output su consolle  $C0+$B4 -> 'C0B4'
    UTemp := swap(iTmp);                    // serve ?
    Writeln(SerOutF0, 'uncomp. Temper = '+ IntToHex(UTemp)+'    '+ IntToStr(UTemp));
end;

procedure BMP085_ReadUP;  // read Uncompensated Pressure value
begin
    TWIOutE(BMP085_ADDRESS, $F4, $34 + (oversampling_setting shl 6));       // var Res
//  TWIOutE(BMP085_ADDRESS, $F4, $F4 );                                     // fixed HiRes
//  TWIOutE(BMP085_ADDRESS, $F4, $34 );                                     // fixed LowRes

    mDelay( word(pressure_conversiontime[oversampling_setting]) );
    
    TWIOutE(BMP085_ADDRESS, $F6);                                           // $F6, F7, F8
    TWIinpPE(BMP085_ADDRESS, @arrUP, 3);                                    // 3 bytes sample:  msb, lsb, xlsb
    //array2consolle(ptrB(@arrUP), 4);                                        // x debug - input recFrame 1:2 output su consolle  $C0+$B4 -> 'C0B4'
    //Writeln(SerOutF0, 'uncomp. Pressure = '+ longToHex(intUP)+'    '+ longToStr(intUP));     // no, map diretto di array su longint non converte correttamente !
    HI( mswUP ) := 0;
    LO( mswUP ) := arrUP[0];
    HI( lswUP ) := arrUP[1];
    LO( lswUP ) := arrUP[2];
    //Writeln(SerOutF0, 'uncomp. Press2   = '+ longToHex(UncompPress)+'    '+ longToStr(UncompPress));  // x debug
    UncompPress := UncompPress shr (8 - oversampling_setting);
    Writeln(SerOutF0, 'uncomp. Pressure = '+ longToHex(UncompPress)+'    '+ longToStr(UncompPress));
end;

procedure BMP085_calibration;
begin
    if TWIstatE(BMP085_ADDRESS) then
        TWIOutE(BMP085_ADDRESS, addr_AC1);
        tBool := TWIinpE (BMP085_ADDRESS, iTmp);
        if tBool then
            vAC1 := swap(iTmp);
            Writeln(SerOutF0, 'word AC1 = '+ IntToHex(vAC1) +'    '+ IntToStr(vAC1));
            Cmd_Result := True;
        else
            Writeln(SerOutF0, 'RD error.');
        endif;
        TWIOutE(BMP085_ADDRESS, addr_AC2);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vAC2 := swap(iTmp);
            Writeln(SerOutF0, 'word AC2 = '+ IntToHex(vAC2)+'    '+ IntToStr(vAC2));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_AC3);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vAC3 := swap(iTmp);
            Writeln(SerOutF0, 'word AC3 = '+ IntToHex(vAC3)+'    '+ IntToStr(vAC3));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_AC4);
        if TWIinpE (BMP085_ADDRESS, wTmp) then
            vAC4 := swap(wTmp);
            Writeln(SerOutF0, 'word AC4 = '+ IntToHex(vAC4)+'    '+ IntToStr(vAC4));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_AC5);
        if TWIinpE (BMP085_ADDRESS, wTmp) then
            vAC5 := swap(wTmp);
            Writeln(SerOutF0, 'word AC5 = '+ IntToHex(vAC5)+'    '+ IntToStr(vAC5));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_AC6);
        if TWIinpE (BMP085_ADDRESS, wTmp) then
            vAC6 := swap(wTmp);
            Writeln(SerOutF0, 'word AC6 = '+ IntToHex(vAC6)+'    '+ IntToStr(vAC6));
        endif;

        TWIOutE(BMP085_ADDRESS, addr_B1);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vB1 := swap(iTmp);
            Writeln(SerOutF0, 'word B1 = '+ IntToHex(vB1)+'    '+ IntToStr(vB1));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_B2);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vB2 := swap(iTmp);
            Writeln(SerOutF0, 'word B2 = '+ IntToHex(vB2)+'    '+ IntToStr(vB2));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_MB);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vMB := swap(iTmp);
            Writeln(SerOutF0, 'word MB = '+ IntToHex(vMB)+'    '+ IntToStr(vMB));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_MC);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vMC := swap(iTmp);
            Writeln(SerOutF0, 'word MC = '+ IntToHex(vMC)+'    '+ IntToStr(vMC));
        endif;
        TWIOutE(BMP085_ADDRESS, addr_MD);
        if TWIinpE (BMP085_ADDRESS, iTmp) then
            vMD := swap(iTmp);
            Writeln(SerOutF0, 'word MD = '+ IntToHex(vMD)+'    '+ IntToStr(vMD));
        endif;
    endif;
end;



initialization  // at StartUp
    error_code := BMP085_NO_ERROR;
    

// finalization          // optional
// at System_ShutDown

end BMP085.
Harald_K
 
Avatar
 
Subject:

Re: Translation of C math

 · 
Posted: 09.04.2013 - 18:18  ·  #6
at this point here:

ctX2 := (longint(vMC shl 11)) / (ctX1 + longint(vMD)); // here error

you should also first convert vMC to longint and then shift it leftwards ...

..otherwise the integer-leftshift will only see the lowest 5 (or 6?) bits before conversion to longint ... maybe this will result in loss of accuracy

so
ctX2 := (longint(vMC) shl 11)) div ...
would be the better choice

(depends on how many digits your vMC variable uses ... )
Marco
Benutzer
Avatar
Gender: n/a
Location: Italy
Posts: 270
Registered: 10 / 2004
Subject:

Re: Translation of C math

 · 
Posted: 10.04.2013 - 11:57  ·  #7
Thank you for the hint !
I'll verify as soon as I get the new chip.

Best regards,
Marco
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   125   139 · Page-Gen-Time: 0.045276s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI