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: 761
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: 5175
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: 6943
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: 761
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: 761
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: 436
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- ... 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: 436
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