BMP180 Drucksensor Berechnung - wer macht denn sowas?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

Ich hab hier eine Berechnung für einen BMP180 Drucksensor von Bosch für den ATmega gebaut. Der Sensor beinhaltet seine Kalibrierdaten

Code: Alles auswählen

   bmp_ac1, bmp_ac2, bmp_ac3 : int16;  // Kalibrierung BMP180
   bmp_ac4, bmp_ac5, bmp_ac6 : uint16;
   bmp_b1, bmp_b2, bmp_mb, bmp_mc, bmp_md : int16;

und liefert 2 Messwerte,

Code: Alles auswählen

  uprss, utemp : uint16;  // Sensorwerte BMP180

aus denen Temperatur und Druck berechnet werden:

Code: Alles auswählen

procedure bmp180_calc();
var
  x1, x2, x3, b3, b5, b6 : int32;
  b4, b7 : uint32;
  pp : int32;
begin
  x1 := ((int32(utemp) - bmp_ac6) * bmp_ac5) div 32768;
   x2 := (int32(bmp_mc) * 2048) div (x1 + bmp_md);
   b5 := x1 + x2;
   ptemp := (b5 + 8) div 16;
    
   b6 := b5 - 4000;
   x1 := (int32(bmp_b2) * ((b6 * b6) div 4096)) div 2048;
   x2 := (int32(bmp_ac2) * b6) div 2048;
   x3 := x1 + x2;
   b3 := ((((int32(bmp_ac1) * 4) + x3) shl 0) + 2) div 4;
   x1 := (int32(bmp_ac3) * b6) div 8192;
   x2 := (int32(bmp_b1) * ((b6 * b6) div 4096)) div 65536;
   x3 := ((x1 + x2) + 2) div 4;
   b4 := (uint32(bmp_ac4) * uint32(x3 + 32768)) div 32768;
   b7 := (uint32(uprss) - b3) * (50000 shr 0);
   if b7 < $80000000 then begin
     pp := (b7 * 2) div b4;
   end else begin
     pp := (b7 div b4) * 2;
   end;
   x1 := (pp div 256) * (pp div 256);
   x1 := (x1 * 3038) div 65536;
   x2 := (-7357 * pp) div 65536;
   pp := pp + ((x1 + x2 + 3791) div 16);
   press := pp div 10// Pa in 0.1mbar
end;

Die Berechnung an sich funktioniert soweit und liefert sinnvolle Ergebnisse. Leider muss zwischendurch heftig rumgecastet und mit großen Zahlen gerechnet werden.

Das Kompilat ist dadurch entsprechend umfangreich und packt über 1kByte zusätzlichen Code dazu. Bei 8MHz dauert die Ausführung etwa 5msec, also 40.000 Zyklen. Die Zeit ist nicht das Problem, aber bekommt man das noch irgendwie speichersparender hin?

Ich mein, wer macht denn sowas, eine derart umständliche Berechnung zu verbocken? Das wäre doch sicher einfacher gegangen. Leider kann man die Formeln an sich nicht viel kürzen, sobald man mit 16bit versucht zu rechnen gibt es irgendwo Überläufe.

Die einzige Idee, die ich habe ist die Kalibrierdaten auszulesen und als feste Konstanten einzugeben, aber dann ist die Routine nur für diesen einen Sensor nutzbar - was möglicherweise reicht. Allerdings scheint mir das die Berechnung nicht merklich zu vereinfachen.

Btw: Gibt es eine Fold-Funktion für lange Listings?

Code: Alles auswählen

GH_SENSOR_ss_BMP180_CALC:
   push   r17
   push   r16
   push   r15
   push   r14
   push   r12
   push   r11
   push   r10
   push   r9
   push   r8
   push   r7
   push   r6
   push   r5
   push   r4
   push   r3
   push   r2
   sbi   11,5
   lds   r22,(U_sGH_DEFINE_ss_UTEMP)
   lds   r23,(U_sGH_DEFINE_ss_UTEMP+1)
   mov   r24,r1
   mov   r25,r1
   lds   r20,(U_sGH_DEFINE_ss_BMP_AC6)
   lds   r21,(U_sGH_DEFINE_ss_BMP_AC6+1)
   sub   r22,r20
   sbc   r23,r21
   sbc   r24,r1
   sbc   r25,r1
   lds   r18,(U_sGH_DEFINE_ss_BMP_AC5)
   lds   r19,(U_sGH_DEFINE_ss_BMP_AC5+1)
   mov   r20,r1
   mov   r21,r1
   call   fpc_mul_longint
   mov   r4,r22
   mov   r3,r23
   mov   r2,r24
   mov   r5,r25
   mov   r19,r4
   mov   r20,r3
   mov   r21,r2
   mov   r18,r5
   tst   r18
   mov   r18,r1
   brpl   .Lj53
   dec   r18
.Lj53:
   mov   r21,r18
   mov   r20,r18
   mov   r19,r18
   andi   r19,-1
   andi   r20,127
   add   r4,r19
   adc   r3,r20
   adc   r2,r1
   adc   r5,r1
   ldi   r19,15
   mov   r18,r1
   tst   r19
   breq   .Lj55
.Lj54:
   asr   r5
   ror   r2
   ror   r3
   ror   r4
   dec   r19
   brne   .Lj54
.Lj55:
   lds   r21,(U_sGH_DEFINE_ss_BMP_MD)
   lds   r20,(U_sGH_DEFINE_ss_BMP_MD+1)
   mov   r18,r1
   sbrc   r20,7
   com   r18
   mov   r22,r4
   mov   r23,r3
   mov   r24,r2
   mov   r25,r5
   add   r22,r21
   adc   r23,r20
   adc   r24,r18
   adc   r25,r18
   lds   r18,(U_sGH_DEFINE_ss_BMP_MC)
   lds   r19,(U_sGH_DEFINE_ss_BMP_MC+1)
   mov   r20,r1
   sbrc   r19,7
   com   r20
   mov   r21,r20
   ldi   r26,11
   mov   r7,r26
   mov   r6,r1
   tst   r7
   breq   .Lj57
.Lj56:
   lsl   r18
   rol   r19
   rol   r20
   rol   r21
   dec   r7
   brne   .Lj56
.Lj57:
   call   fpc_div_longint
   add   r22,r4
   adc   r23,r3
   adc   r24,r2
   adc   r25,r5
   mov   r19,r22
   mov   r20,r23
   movw   r2,r24
   ldi   r18,8
   add   r19,r18
   adc   r20,r1
   adc   r2,r1
   adc   r3,r1
   mov   r21,r19
   mov   r4,r20
   mov   r5,r2
   mov   r18,r3
   tst   r18
   mov   r18,r1
   brpl   .Lj58
   dec   r18
.Lj58:
   mov   r5,r18
   mov   r4,r18
   mov   r21,r18
   andi   r21,15
   add   r19,r21
   adc   r20,r1
   adc   r2,r1
   adc   r3,r1
   ldi   r21,4
   mov   r18,r1
   tst   r21
   breq   .Lj60
.Lj59:
   asr   r3
   ror   r2
   ror   r20
   ror   r19
   dec   r21
   brne   .Lj59
.Lj60:
   sts   (U_sGH_DEFINE_ss_PTEMP),r19
   sts   (U_sGH_DEFINE_ss_PTEMP+1),r20
   subi   r22,-96
   sbci   r23,15
   sbc   r24,r1
   sbc   r25,r1
   movw   r18,r22
   movw   r20,r24
   movw   r4,r22
   movw   r6,r24
   movw   r22,r4
   movw   r24,r6
   call   fpc_mul_longint
   movw   r18,r22
   movw   r20,r24
   mov   r23,r18
   mov   r22,r19
   mov   r25,r20
   mov   r24,r21
   tst   r24
   mov   r24,r1
   brpl   .Lj61
   dec   r24
.Lj61:
   mov   r25,r24
   mov   r22,r24
   mov   r23,r24
   andi   r23,-1
   andi   r22,15
   add   r18,r23
   adc   r19,r22
   adc   r20,r1
   adc   r21,r1
   ldi   r23,12
   mov   r22,r1
   tst   r23
   breq   .Lj63
.Lj62:
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   dec   r23
   brne   .Lj62
.Lj63:
   lds   r22,(U_sGH_DEFINE_ss_BMP_B2)
   lds   r23,(U_sGH_DEFINE_ss_BMP_B2+1)
   mov   r24,r1
   sbrc   r23,7
   com   r24
   mov   r25,r24
   call   fpc_mul_longint
   movw   r18,r22
   mov   r21,r24
   mov   r20,r25
   tst   r20
   mov   r20,r1
   brpl   .Lj64
   dec   r20
.Lj64:
   mov   r21,r20
   mov   r19,r20
   mov   r18,r20
   andi   r18,-1
   andi   r19,7
   add   r22,r18
   adc   r23,r19
   adc   r24,r1
   adc   r25,r1
   ldi   r19,11
   mov   r18,r1
   tst   r19
   breq   .Lj66
.Lj65:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj65
.Lj66:
   mov   r9,r22
   mov   r2,r23
   mov   r3,r24
   mov   r8,r25
   lds   r22,(U_sGH_DEFINE_ss_BMP_AC2)
   lds   r23,(U_sGH_DEFINE_ss_BMP_AC2+1)
   mov   r24,r1
   sbrc   r23,7
   com   r24
   mov   r25,r24
   movw   r18,r4
   movw   r20,r6
   call   fpc_mul_longint
   movw   r18,r22
   mov   r21,r24
   mov   r20,r25
   tst   r20
   mov   r20,r1
   brpl   .Lj67
   dec   r20
.Lj67:
   mov   r21,r20
   mov   r19,r20
   mov   r18,r20
   andi   r18,-1
   andi   r19,7
   add   r22,r18
   adc   r23,r19
   adc   r24,r1
   adc   r25,r1
   ldi   r19,11
   mov   r18,r1
   tst   r19
   breq   .Lj69
.Lj68:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj68
.Lj69:
   add   r22,r9
   adc   r23,r2
   adc   r24,r3
   adc   r25,r8
   lds   r20,(U_sGH_DEFINE_ss_BMP_AC1)
   lds   r21,(U_sGH_DEFINE_ss_BMP_AC1+1)
   mov   r18,r1
   sbrc   r21,7
   com   r18
   mov   r19,r18
   lsl   r20
   rol   r21
   rol   r18
   rol   r19
   lsl   r20
   rol   r21
   rol   r18
   rol   r19
   add   r22,r20
   adc   r23,r21
   adc   r24,r18
   adc   r25,r19
   ldi   r18,2
   add   r22,r18
   adc   r23,r1
   adc   r24,r1
   adc   r25,r1
   mov   r18,r22
   mov   r20,r23
   mov   r21,r24
   mov   r19,r25
   tst   r19
   mov   r19,r1
   brpl   .Lj70
   dec   r19
.Lj70:
   mov   r21,r19
   mov   r20,r19
   mov   r18,r19
   andi   r18,3
   add   r22,r18
   adc   r23,r1
   adc   r24,r1
   adc   r25,r1
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   mov   r17,r22
   mov   r16,r23
   mov   r15,r24
   mov   r10,r25
   lds   r22,(U_sGH_DEFINE_ss_BMP_AC3)
   lds   r23,(U_sGH_DEFINE_ss_BMP_AC3+1)
   mov   r24,r1
   sbrc   r23,7
   com   r24
   mov   r25,r24
   movw   r2,r4
   movw   r8,r6
   movw   r18,r2
   movw   r20,r8
   call   fpc_mul_longint
   mov   r18,r22
   mov   r21,r23
   mov   r4,r24
   mov   r20,r25
   tst   r20
   mov   r20,r1
   brpl   .Lj71
   dec   r20
.Lj71:
   mov   r4,r20
   mov   r19,r20
   mov   r18,r20
   andi   r19,-1
   andi   r18,31
   add   r22,r19
   adc   r23,r18
   adc   r24,r1
   adc   r25,r1
   ldi   r19,13
   mov   r18,r1
   tst   r19
   breq   .Lj73
.Lj72:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj72
.Lj73:
   movw   r4,r22
   movw   r6,r24
   movw   r22,r2
   movw   r24,r8
   movw   r18,r22
   movw   r20,r24
   call   fpc_mul_longint
   movw   r18,r22
   movw   r20,r24
   movw   r22,r18
   mov   r25,r20
   mov   r24,r21
   tst   r24
   mov   r24,r1
   brpl   .Lj74
   dec   r24
.Lj74:
   mov   r25,r24
   mov   r23,r24
   mov   r22,r24
   andi   r22,-1
   andi   r23,15
   add   r18,r22
   adc   r19,r23
   adc   r20,r1
   adc   r21,r1
   ldi   r23,12
   mov   r22,r1
   tst   r23
   breq   .Lj76
.Lj75:
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   dec   r23
   brne   .Lj75
.Lj76:
   lds   r22,(U_sGH_DEFINE_ss_BMP_B1)
   lds   r23,(U_sGH_DEFINE_ss_BMP_B1+1)
   mov   r24,r1
   sbrc   r23,7
   com   r24
   mov   r25,r24
   call   fpc_mul_longint
   movw   r18,r22
   movw   r20,r24
   movw   r22,r18
   mov   r25,r20
   mov   r24,r21
   tst   r24
   mov   r24,r1
   brpl   .Lj77
   dec   r24
.Lj77:
   mov   r25,r24
   mov   r23,r24
   mov   r22,r24
   andi   r22,-1
   andi   r23,-1
   add   r18,r22
   adc   r19,r23
   adc   r20,r1
   adc   r21,r1
   ldi   r23,16
   mov   r22,r1
   tst   r23
   breq   .Lj79
.Lj78:
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   dec   r23
   brne   .Lj78
.Lj79:
   add   r18,r4
   adc   r19,r5
   adc   r20,r6
   adc   r21,r7
   ldi   r22,2
   add   r18,r22
   adc   r19,r1
   adc   r20,r1
   adc   r21,r1
   mov   r22,r18
   mov   r24,r19
   mov   r25,r20
   mov   r23,r21
   tst   r23
   mov   r23,r1
   brpl   .Lj80
   dec   r23
.Lj80:
   mov   r25,r23
   mov   r24,r23
   mov   r22,r23
   andi   r22,3
   add   r18,r22
   adc   r19,r1
   adc   r20,r1
   adc   r21,r1
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   add   r18,r1
   ldi   r22,-128
   adc   r19,r22
   adc   r20,r1
   adc   r21,r1
   lds   r22,(U_sGH_DEFINE_ss_BMP_AC4)
   lds   r23,(U_sGH_DEFINE_ss_BMP_AC4+1)
   mov   r24,r1
   mov   r25,r1
   call   fpc_mul_dword
   ldi   r19,15
   mov   r18,r1
   tst   r19
   breq   .Lj82
.Lj81:
   lsr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj81
.Lj82:
   mov   r14,r22
   mov   r12,r23
   mov   r11,r24
   mov   r2,r25
   lds   r22,(U_sGH_DEFINE_ss_UPRSS)
   lds   r23,(U_sGH_DEFINE_ss_UPRSS+1)
   mov   r24,r1
   mov   r25,r1
   sub   r22,r17
   sbc   r23,r16
   sbc   r24,r15
   sbc   r25,r10
   ldi   r18,80
   ldi   r19,-61
   mov   r20,r1
   mov   r21,r1
   call   fpc_mul_longint
   mov   r3,r22
   mov   r4,r23
   mov   r5,r24
   mov   r6,r25
   cp   r3,r1
   cpc   r4,r1
   cpc   r5,r1
   ldi   r18,-128
   cpc   r6,r18
   brsh   .Lj84
   mov   r18,r3
   mov   r19,r4
   mov   r20,r5
   mov   r21,r6
   lsl   r18
   rol   r19
   rol   r20
   rol   r21
   mov   r22,r14
   mov   r23,r12
   mov   r24,r11
   mov   r25,r2
   call   fpc_div_dword
   mov   r7,r22
   mov   r8,r23
   mov   r9,r24
   mov   r10,r25
   rjmp   .Lj85
.Lj84:
   mov   r18,r3
   mov   r19,r4
   mov   r20,r5
   mov   r21,r6
   mov   r22,r14
   mov   r23,r12
   mov   r24,r11
   mov   r25,r2
   call   fpc_div_dword
   lsl   r22
   rol   r23
   rol   r24
   rol   r25
   mov   r7,r22
   mov   r8,r23
   mov   r9,r24
   mov   r10,r25
.Lj85:
   mov   r2,r7
   mov   r3,r8
   mov   r24,r9
   mov   r23,r10
   movw   r18,r2
   mov   r20,r24
   mov   r21,r23
   mov   r25,r18
   mov   r4,r19
   mov   r5,r20
   mov   r22,r21
   tst   r22
   mov   r22,r1
   brpl   .Lj86
   dec   r22
.Lj86:
   mov   r5,r22
   mov   r4,r22
   mov   r25,r22
   andi   r25,-1
   add   r18,r25
   adc   r19,r1
   adc   r20,r1
   adc   r21,r1
   ldi   r25,8
   mov   r22,r1
   tst   r25
   breq   .Lj88
.Lj87:
   asr   r21
   ror   r20
   ror   r19
   ror   r18
   dec   r25
   brne   .Lj87
.Lj88:
   movw   r4,r2
   mov   r6,r24
   mov   r7,r23
   movw   r22,r4
   movw   r24,r6
   mov   r3,r22
   mov   r8,r23
   mov   r9,r24
   mov   r2,r25
   tst   r2
   mov   r2,r1
   brpl   .Lj89
   dec   r2
.Lj89:
   mov   r9,r2
   mov   r8,r2
   mov   r16,r2
   andi   r16,-1
   add   r22,r16
   adc   r23,r1
   adc   r24,r1
   adc   r25,r1
   ldi   r26,8
   mov   r3,r26
   mov   r2,r1
   tst   r3
   breq   .Lj91
.Lj90:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r3
   brne   .Lj90
.Lj91:
   call   fpc_mul_longint
   ldi   r18,-34
   ldi   r19,11
   mov   r20,r1
   mov   r21,r1
   call   fpc_mul_longint
   mov   r19,r22
   mov   r18,r23
   mov   r21,r24
   mov   r20,r25
   tst   r20
   mov   r20,r1
   brpl   .Lj92
   dec   r20
.Lj92:
   mov   r21,r20
   mov   r18,r20
   mov   r19,r20
   andi   r19,-1
   andi   r18,-1
   add   r22,r19
   adc   r23,r18
   adc   r24,r1
   adc   r25,r1
   ldi   r19,16
   mov   r18,r1
   tst   r19
   breq   .Lj94
.Lj93:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj93
.Lj94:
   mov   r9,r22
   mov   r2,r23
   mov   r3,r24
   mov   r8,r25
   movw   r18,r4
   movw   r20,r6
   ldi   r22,67
   ldi   r23,-29
   ldi   r24,-1
   ldi   r26,-1
   mov   r25,r26
   call   fpc_mul_longint
   movw   r18,r22
   mov   r21,r24
   mov   r20,r25
   tst   r20
   mov   r20,r1
   brpl   .Lj95
   dec   r20
.Lj95:
   mov   r21,r20
   mov   r19,r20
   mov   r18,r20
   andi   r18,-1
   andi   r19,-1
   add   r22,r18
   adc   r23,r19
   adc   r24,r1
   adc   r25,r1
   ldi   r19,16
   mov   r18,r1
   tst   r19
   breq   .Lj97
.Lj96:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj96
.Lj97:
   add   r22,r9
   adc   r23,r2
   adc   r24,r3
   adc   r25,r8
   ldi   r18,-49
   add   r22,r18
   ldi   r18,14
   adc   r23,r18
   adc   r24,r1
   adc   r25,r1
   mov   r18,r22
   mov   r20,r23
   mov   r21,r24
   mov   r19,r25
   tst   r19
   mov   r19,r1
   brpl   .Lj98
   dec   r19
.Lj98:
   mov   r21,r19
   mov   r20,r19
   mov   r18,r19
   andi   r18,15
   add   r22,r18
   adc   r23,r1
   adc   r24,r1
   adc   r25,r1
   ldi   r19,4
   mov   r18,r1
   tst   r19
   breq   .Lj100
.Lj99:
   asr   r25
   ror   r24
   ror   r23
   ror   r22
   dec   r19
   brne   .Lj99
.Lj100:
   add   r4,r22
   adc   r5,r23
   adc   r6,r24
   adc   r7,r25
   movw   r18,r4
   movw   r20,r6
   ldi   r22,10
   mov   r23,r1
   mov   r24,r1
   mov   r25,r1
   call   fpc_div_longint
   sts   (U_sGH_DEFINE_ss_PRESS),r22
   sts   (U_sGH_DEFINE_ss_PRESS+1),r23
   cbi   11,5
   pop   r2
   pop   r3
   pop   r4
   pop   r5
   pop   r6
   pop   r7
   pop   r8
   pop   r9
   pop   r10
   pop   r11
   pop   r12
   pop   r14
   pop   r15
   pop   r16
   pop   r17
   ret
 

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von siro »

Ich hatte mir auch schon mal diesen Sensor angesehen und traute meinen Augen nicht als ich die komplexe Umrechnung sah. :shock:
Da hätte man doch gleich einen Controller reinbauen können, der die umgerechneten Werte liefert.
Mein Idee warsofort in die eigene Schaltung einen 8 Pinnigen zusätzlichen Controller einzubauen der nix weiter tut als

a) I2C rein
b) Umrechnen
c) Seriell TXD raus

Den könnte man dann theoretisch als BMP180 Coprozessor verkaufen... :mrgreen:
Mit einem kleinem PIC von Microchip könnte ich mir sowas vorstellen.
Die 12F1840 zum Beispiel hat 8 Beine und alles drin. Der tackert intern mit 32MHz und hat I2C und RS232

RA0 TXD
RA5 RXD
RA1 I2C Clock
RA2 I2C Data
RA3 MCLR Reset

Das wäre doch mal ein hübsches Winterprojekt..

Kann man eigentlich in das Assembler Listing die entsprechende Source Code Zeile mit einblenden ? dann lässt sich der erzeugte Code besser verfolgen.
Im Prinzip macht der Pascal Compiler ja gar nicht Sooo schlechten Code, die Divisionen sind schon in den Berechnugnen auf 2er Potenzen optimiert und diese werden mittels Shift ausgeführt.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von wp_xyz »

Ich spekuliere, dass hier mit Integer-Arithmetik ein Polynom berechnet wird, aber nachdem ich den zu berechnenden Ausdruck nicht kenne, kann ich konkret nur Mikro-Optimierungen vorschlagen:

"shr 0" und "shl 0" - was soll das denn? Wenn man das Bitmuster einer Integer-Zahl um 0 Bits nach rechts bzw. links verschiebt, ändert sich gar nichts. Diesen Code zumindest kannst du dir sparen.

Der Term "(b6*b6) div 4096" kommt an zwei Stellen vor. Wenn du das Ergebnis in einer Zwischenvariablen abspeichert, kannst du dir den Code für die zweite Berechnung sparen.

Ich weiß nicht, ob "div 4" oder "shr 2" gleich viel Maschinencode produziert. Falls, wie ich vermute, die Shift-Operation günstiger ist, könntest du diese mehrfach einsetzen, denn es wird immer wieder durch Zweier-Potenzen dividiert (32768 = $8000 --> shr 15; 2048 = $800 --> shr 11, etc).

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

siro hat geschrieben:Im Prinzip macht der Pascal Compiler ja gar nicht Sooo schlechten Code, die Divisionen sind schon in den Berechnugnen auf 2er Potenzen optimiert und diese werden mittels Shift ausgeführt.


Ich hab das Ganze schonmal in C umgesetzt, und der Pascal Compiler macht hier VIEL besseren Code als der GCC. Zum Beispiel muss man dem GCC die Shifts direkt vorgeben, sonst kommen da mehrere Software-Divisionen dazu. Pascal macht hier gleich die richtigen Shifts draus und setzt Software-Division nur dort ein wo wirklich Variable durch Variable geteilt wird.

Und mit den Shifts muss man auch aufpassen, da sind einige signed integer dabei, wo man eventuell asr statt shr nehmen muss, bei div beachtet das der Compiler automatisch.

wp_xyz hat geschrieben:"shr 0" und "shl 0" - was soll das denn? Wenn man das Bitmuster einer Integer-Zahl um 0 Bits nach rechts bzw. links verschiebt, ändert sich gar nichts. Diesen Code zumindest kannst du dir sparen.


Es gibt vier Oversampling Settings 0..3 für die Druckmessung, die in die Berechnung mit einfließen, wenn ich ein höheres Oversampling nutze muss, taucht das in der Funktion hier auf. Macht auch nichts, sofern ich das richtig sehe optimiert der Compiler das weg.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

Was mir auch aufgefallen ist: Es gibt mehrere Stellen, wo 16bit * 16bit zu 32bit multipliziert werden. Hier muss ich aber die 16bit VORHER in 32bit umwandeln und dann wird fpc_mul_longint aufgerufen, sonst wird das Ergebnis falsch.

Direkt in Assembler kann ich aber durchaus 16bit * 16 bit zu 32bit multiplizieren, dafür gibt es Appnotes. Um Pascal zu einem 16bit * 16bit zu 32bit zu bringen muss ich aber anscheinend eine eigene Funktion schreiben...

Oder zum Schluss, da wird ein 32bit-Wert durch 10 geteilt. Daraus macht der Compiler eine 32bit / 32bit Division, obwohl eine 32bit / 8bit Division völlig reichen würde. Und wer schonmal Software-Division gemacht hat weiss, dass das richtig heftig zuschlägt.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Mathias »

Btw: Gibt es eine Fold-Funktion für lange Listings?

Dies gibt es nicht, aber für so langer Code verwende ich den Anhang.

Leider muss zwischendurch heftig rumgecastet und mit großen Zahlen gerechnet werden.

Das ist der Tot der ATmegas, da dies nur mit 8Bit multiplizieren können. Mit Divisionen sieht es noch schlimmer aus, das können die gar nicht, es muss alles per Software laufen.
Aus diesem Grund wird der ASM-Code unendlich lange.
Zum Glück sind deine Divisionen in der 2er Potenz, somit geht das mit shl und shr.
Wenigsten hast du keinen ATtiny, der kann nicht mal multiplizieren.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von siro »

wp_xyz hat geschrieben:Ich spekuliere, dass hier mit Integer-Arithmetik ein Polynom berechnet wird.


Ja, das ist mit Sicherheit die "barometrische Höhenformel" und die ist äußerst "KRUM"...
und wird nun mit den vielen Kalibrierwerten an den jeweiligen Sensor angepasst.

Schiebeoperation mit Signed, also Vorzeichenbefteten Werten" sind SEHR gefährlich und gehen eigentlich immer schief....
Ich habe eine komplette 32 Bit Arithmetik für 8 Bitter von Microchip programmiert, inklusive Wurzelfunktion und kann da ein Lied von singen.
Die Dinger können nichtmal multiplizieren, also reine Bitschieber. Ähnlich scheint es mit dem AVR zu sein.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

Mathias hat geschrieben:
Das ist der Tot der ATmegas, da dies nur mit 8Bit multiplizieren können.


Naja, so schlimm ist das nicht. Eine 16bit-Multiplikation sind auch nur 4 8bit Muls und ein bißchen Addiererei.

Anscheinend arbeitet hier der Compiler suboptimal. Normalerweise brauche ich für 16bit x 16bit = 32bit nur zwei 16bit Eingangswerte. Der Compiler rechnet aber nur richtig, wenn ich die 16bit vorher in 32bit umwandle, dementsprechend werden erstmal unnötig Register mit Nullen belegt und verschoben.

Genauso bei der Division durch 10, da reicht eigentlich ein 32bit / 8bit, aber der Compiler macht halt ein 32bit durch 32bit draus. Und das bedeutet bei Software-Division ganz klar 4fache Rechenzeit, weil er nicht durch 8bit sondern durch 32bit schiften muss.

Ich hab schon Echtzeit Motorregelung mit PID in Assembler gerechnet, da kann man durchaus was rausholen. Ich dachte mir halt, eh ich das hier selbst in Assembler mache, lass mal den Compiler machen.

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von siro »

Bei "C" gibt es ja verschiedene Optimierungen
auf Größe(size) oder Geschwindeigkeit (speed), kann man das in FPC steuern.
Auch hier wird nochmal viel von den Compilern herausgekitzelt.

Generell würde ich auch den Compiler den Code erzeugen lassen.
Assembler Optimierungen nur wenns absolut sein muss.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von kupferstecher »

siro hat geschrieben:Kann man eigentlich in das Assembler Listing die entsprechende Source Code Zeile mit einblenden ? dann lässt sich der erzeugte Code besser verfolgen.

Das tät mich auch ziemlich interessieren!

Timm Thaler hat geschrieben:Direkt in Assembler [...]

DAS in Assembler wöllte ich nicht programmieren müssen :)

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

kupferstecher hat geschrieben:DAS in Assembler wöllte ich nicht programmieren müssen :)


Das ist total simpel: Binomische Formeln.

Wie rechnest Du schnell im Kopf 13 x 14?

10x10 = 100
10x4 = 40
3x10 = 30
3x4 = 12
= 182*

Genauso macht das der AVR, nur mit Bytes statt der Dezimalstellen. Du brauchst aber verschiedene MULs für signed und unsigned.

http://www.atmel.com/images/Atmel-1631-Using-the-AVR-Hardware-Multiplier_ApplicationNote_AVR201.pdf

Und Du kannst Dir Deine Multiplikation optimieren: 24bit x 8bit = 32bit, kein Problem, der Pascal-Compiler wandelt dafür erstmal alles in 32bit um.

*) Ja, ok, das Kleverle weiss natürlich: 14^2 = 196, minus 14 = 182. Sowas kann aber der Compiler nicht. ;-)

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von kupferstecher »

Den BMP180 hab ich auch mal verwendet, allerdings in C programmiert. Apropos Kleverle: Ich dachte mir ich könnte mir ein paar der Casts sparen...
Aber stimmt schon, in Assembler schaut man noch eher auf die Wertebereiche usw. Aber eine Zeile falsch und das Ergebnis stimmt nicht. Dann lieber 50 Zeilen wie ein paar hundert.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: BMP180 Drucksensor Berechnung - wer macht denn sowas?

Beitrag von Timm Thaler »

Hab die halbe Nacht zugebracht um das Ganze auf dem PC zu simulieren. Pascal-Code läßt sich ja so schön übertragen.

Dabei konnte ich wunderbar die Variablen auf int16 und uint16 reduzieren und es funktionierte immer noch. Auf dem AVR verwendet der Compiler dann aber auch 16bit-Multiplikation und die shifts werden auch nur für 16bit ausgeführt. Geht nicht.

Anscheinend rechnet der Compiler auf dem PC immer mit 32 / 64 bit, auch wenn uint16 und int16 angegeben sind.

Mist!

Antworten