mikrocontroller.net

Forum: Compiler & IDEs BME680 etwas ATMega-freundlicher auslesen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich würde die Routinen, die zum Auslesen des BME680 von Bosch nötig 
sind, gerne etwas vereinfachen/optimieren. Wie ihr vielleicht wisst, 
gibt der Sensor aus irgendeinem Grund nur Rohdaten und eine Tabelle mit 
Kalibrierungsdaten raus und der arme µC muss damit klar kommen.

Das hier ist aus dem offiziellen Code von
https://github.com/BoschSensortec/BME680_driver/blob/master/bme680.c
/*!
 * @brief This internal API is used to calculate the temperature value.
 */
static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev)
{
  int64_t var1;
  int64_t var2;
  int64_t var3;
  int16_t calc_temp;

  var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib.par_t1 << 1);
  var2 = (var1 * (int32_t) dev->calib.par_t2) >> 11;
  var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
  var3 = ((var3) * ((int32_t) dev->calib.par_t3 << 4)) >> 14;
  dev->calib.t_fine = (int32_t) (var2 + var3);
  calc_temp = (int16_t) (((dev->calib.t_fine * 5) + 128) >> 8);

  return calc_temp;
}

/*!
 * @brief This internal API is used to calculate the pressure value.
 */
static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev)
{
  int32_t var1;
  int32_t var2;
  int32_t var3;
  int32_t pressure_comp;

  var1 = (((int32_t)dev->calib.t_fine) >> 1) - 64000;
  var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *
    (int32_t)dev->calib.par_p6) >> 2;
  var2 = var2 + ((var1 * (int32_t)dev->calib.par_p5) << 1);
  var2 = (var2 >> 2) + ((int32_t)dev->calib.par_p4 << 16);
  var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
    ((int32_t)dev->calib.par_p3 << 5)) >> 3) +
    (((int32_t)dev->calib.par_p2 * var1) >> 1);
  var1 = var1 >> 18;
  var1 = ((32768 + var1) * (int32_t)dev->calib.par_p1) >> 15;
  pressure_comp = 1048576 - pres_adc;
  pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));
  if (pressure_comp >= BME680_MAX_OVERFLOW_VAL)
    pressure_comp = ((pressure_comp / var1) << 1);
  else
    pressure_comp = ((pressure_comp << 1) / var1);
  var1 = ((int32_t)dev->calib.par_p9 * (int32_t)(((pressure_comp >> 3) *
    (pressure_comp >> 3)) >> 13)) >> 12;
  var2 = ((int32_t)(pressure_comp >> 2) *
    (int32_t)dev->calib.par_p8) >> 13;
  var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *
    (int32_t)(pressure_comp >> 8) *
    (int32_t)dev->calib.par_p10) >> 17;

  pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +
    ((int32_t)dev->calib.par_p7 << 7)) >> 4);

  return (uint32_t)pressure_comp;

}

/*!
 * @brief This internal API is used to calculate the humidity value.
 */
static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev)
{
  int32_t var1;
  int32_t var2;
  int32_t var3;
  int32_t var4;
  int32_t var5;
  int32_t var6;
  int32_t temp_scaled;
  int32_t calc_hum;

  temp_scaled = (((int32_t) dev->calib.t_fine * 5) + 128) >> 8;
  var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) dev->calib.par_h1 * 16)))
    - (((temp_scaled * (int32_t) dev->calib.par_h3) / ((int32_t) 100)) >> 1);
  var2 = ((int32_t) dev->calib.par_h2
    * (((temp_scaled * (int32_t) dev->calib.par_h4) / ((int32_t) 100))
      + (((temp_scaled * ((temp_scaled * (int32_t) dev->calib.par_h5) / ((int32_t) 100))) >> 6)
        / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10;
  var3 = var1 * var2;
  var4 = (int32_t) dev->calib.par_h6 << 7;
  var4 = ((var4) + ((temp_scaled * (int32_t) dev->calib.par_h7) / ((int32_t) 100))) >> 4;
  var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
  var6 = (var4 * var5) >> 1;
  calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12;

  if (calc_hum > 100000) /* Cap at 100%rH */
    calc_hum = 100000;
  else if (calc_hum < 0)
    calc_hum = 0;

  return (uint32_t) calc_hum;
}

/*!
 * @brief This internal API is used to calculate the Gas Resistance value.
 */
static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev)
{
  int64_t var1;
  uint64_t var2;
  int64_t var3;
  uint32_t calc_gas_res;
  /**Look up table 1 for the possible gas range values */
  uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647),
    UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777),
    UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228),
    UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) };
  /**Look up table 2 for the possible gas range values */
  uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000),
    UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016),
    UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000),
    UINT32_C(250000), UINT32_C(125000) };

  var1 = (int64_t) ((1340 + (5 * (int64_t) dev->calib.range_sw_err)) *
    ((int64_t) lookupTable1[gas_range])) >> 16;
  var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1);
  var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9);
  calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2);

  return calc_gas_res;
}

Der Gaswiderstand wird in sage und schreibe 64 Bit gerechnet...

Vielleicht hat ja von euch schon jemand die Routinen schon etwas 
abgespeckt?

Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Temperatur auch...
Was auf jeden Fall schonmal geht, ist, diese Konstanten in der unteren 
Funktion ins Flash zu packen.

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiner schrieb:
> Wie ihr vielleicht wisst, gibt der Sensor aus irgendeinem Grund nur
> Rohdaten und eine Tabelle mit Kalibrierungsdaten raus und der arme µC
> muss damit klar kommen.

Der Grund wird sein, dass der Sensor aus Kostengründen keinen passenden 
Rechenkern enthält.

Lass den armen µC doch rechnen, oder was meinst du, wie das Verhältnis 
von Sensorzeitkonstanten zu Rechenzeit ist.

Es kann durchaus sein, dass die Kalibrierdaten genau auf diese von Bosch 
veröffentlichte Umrechnungsroutine angepasst sind. Bei Änderungen am 
Algorithmus und Abweichungen in der Rechengenauigkeit solltest du also 
genau gucken, wie empfindlich das Ergebnis darauf reagiert.

Vielleicht hatten aber auch die Betriebswirtschaftler bei der 
Entwicklung des Algorithmus die Oberhand, i.e. Auswerteroutine 
funktioniert, nicht mehr dran drehen, keine Zeit mehr reinstecken - 
fertig und raus damit ;-)

Autor: Mw E. (Firma: fritzler-avr.de) (fritzler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zumindest beim BME280 gabs dann ganz hinten im DB noch Rechenfunktionen 
in 32Bit.
Sind die beim 680er verschwunden?

Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne, glaube nicht. Es gibt aber float-Versionen. Ist dann auch nur 32 
Bit, aber naja, ob das schneller geht oder weniger Flash braucht?

Was mich stutzig macht, ist das ständige Casten in Bitbreiten, die 
offensichtlich schon da sind. Und dann wird einfach mal nach signed 
gecastet. Und dann werden signed Variablen bitweise verschoben!? 
Programmiert Bosch alles so? Bauen die auch Komponenten für 
Flugzeuge.....?

Aber das nur am Rande.

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiner schrieb:
> Es gibt aber float-Versionen. Ist dann auch nur 32 Bit

Bei Float gehen von den 32 Bit bereits 8 für den Exponenten drauf.

Autor: Max (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Warum bieten solche Sensoren ihre Messwerte nicht schon fix und fertig 
an???

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiner schrieb:
> ich würde die Routinen, die zum Auslesen des BME680 von Bosch nötig
> sind, gerne etwas vereinfachen/optimieren

Dann mach das doch (möglichst natürlich unter Beibehaltung der 
Genauigkeit).

Oder wolltest du schreiben: "Ich kann es nicht, und suche jemanden der 
es für mich macht".

Da stellt sich die Frage: Wozu ? Kann dein C Compiler es nicht 
übersetzen oder ist dein Restprogramm schon so umfangreich dass diese 
Routine nicht mehr in den uC passt ? Warum dann nicht das Restprogramm 
optimieren.

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max schrieb:
> Warum bieten solche Sensoren ihre Messwerte nicht schon fix und fertig
> an???

Wolfgang schrieb:
> Der Grund wird sein, dass der Sensor aus Kostengründen keinen passenden
> Rechenkern enthält.

Autor: Bert (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Wolfgang schrieb:
> Max schrieb:
> Warum bieten solche Sensoren ihre Messwerte nicht schon fix und fertig
> an???
>
> Wolfgang schrieb:
> Der Grund wird sein, dass der Sensor aus Kostengründen keinen passenden
> Rechenkern enthält.

Wieviel Leute würden wohl einen geringen Mehrpreis bezahlen um sich 
diesen aufwendigen Berechnungs-Hickhack zu sparen? Ich tippe mal das 
tendiert gegen 100%...

Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich ist das Ganze sowieso ein Witz. Der Sensor wird beworben mit 
"Messung der Luftqualität", liefert aber dafür nur einen elektrischen 
Luftwiderstandswert (neben Temperatur, Feuchte und Druck). Den 
beworbenen IAQ-Wert (indoor air quality), der sich aus diesen ableitet, 
kriegt man aber nicht, bzw. nur, wenn man die (closed source) Binaries 
verwendet. Zumindest habe ich das so verstanden. Die Binaries für ATMega 
(8 Bit) benötigen 25kB ROM und 1kB RAM...

Autor: Irgend W. (Firma: egal) (irgendwer)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Bert schrieb:
> Wieviel Leute würden wohl einen geringen Mehrpreis bezahlen um sich
> diesen aufwendigen Berechnungs-Hickhack zu sparen? Ich tippe mal das
> tendiert gegen 100%..

Ich tippe eher mal gegen 0%.
Die paar Krümel die von Privatpersonen gekauft werden interessieren 
keinen Hersteller. Für die zählen die Kunden die die Dinger 
Millionenfach kaufen und für die geht es um jeden 1/10 Cent.

Autor: E. Zellner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Irgend W. schrieb:
> Für die zählen die Kunden die die Dinger
> Millionenfach kaufen und für die geht es um jeden 1/10 Zent.

Nö. Wenn es um jeden 1/10 Cent geht wählt man eher eine andere Lösung. 
Dafür sind die Teile zu teuer. Auch dafür, "millionenfach" verwendet zu 
werden. Ich finde, die Anwrndungs- "Simplicity" wird von den Herstellern 
chronisch unterbewertet!

Autor: Christoph db1uq K. (christoph_kessler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich versuche, in den Unterlagen irgendwo eine vernünftige Beschreibung 
zu finden, wie die Rohdaten in korrigierte Werte umgerechnet werden. Ein 
echter Fall von Code-Obfuscation. Anscheinend ist ein Programmteil 
namens "bsec_do_steps()" zuständig, den ich aber noch nicht gefunden 
habe.

Von Bosch gibt es die ZIP-Datei "BSEC_1.4.7.4_Generic_Release.zip" für 
mehrere Controller. ATMEGA2560 oder Arduino oder diverse andere, sind 
das die richtigen Quelltexte?
https://ae-bst.resource.bosch.com/media/_tech/media/bsec/BSEC_1.4.7.4_Generic_Release.zip

Autor: Christoph db1uq K. (christoph_kessler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
https://forum.fhem.de/index.php/topic,78619.msg706435.html#msg706435
"bsec_do_steps()  scheint nur in den precompiled libs zu existieren....
Die scheinen Angst vor den Chinesen zu haben "

Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Werte erhält man durch o.g. Berechnungen. Bosch bietet zusätzlich 
(optional) die BSEC-Software an, welche noch etwas mehr Korrektur 
anbietet. Rausrechnen von Wärmequellen usw. Beispielsweise kriegt man so 
wohl Temperatur und Feuchte außerhalb des Gerätes und auch den ominösen 
IAQ-Wert etc.
BSEC ist closed-source! Man kann nur die API runterladen und 
verschiedene Binaries. Ich habe es nicht probiert, da es für mein 
Projekt auch Overkill ist. Außerdem passt es wohl kaum in meinen 
ATMega328. ;)

Autor: Heiner (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Ein chinesischer Chip würde die Werte wahrscheinlich direkt ausspucken, 
wie jeder andere vernünftige Sensor, ohne aufwändige externe Rechnerei. 
Wenn ich die Wahl hätte, würde ich das auch bevorzugen.

Autor: Veit D. (devil-elec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wenn ich lesen muss das Bosch möchte für die Arduino IDE den arduino 
builder auszutauschen, dann weiß ich nicht was Bosch falsch gemacht hat. 
Ich würde sagen probiere erstmal diese Lib 
https://github.com/adafruit/Adafruit_BME680

Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist derselbe Code wie bei Bosch. Auch 64bit bzw. float.

Autor: Veit D. (devil-elec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schade.

Autor: Michael U. (amiga)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Hallo,

ich habe mit dem BME680 jetzt mal etwas rumgespielt und auch mit der 
BSEC-Software, allerdings auf einem ESP32.
Diese Version habe ich zumindest zu Laufen bekommen:
https://github.com/BoschSensortec/BSEC-Arduino-library

ArduionoIDE 1.8.10 und ESP32-Boardmanagerversion 1.04.
Allerdings hat es da ein anderes Problem gegeben: nach der Änderung der 
plattform.txt compiliert nichts anderes mehr für den ESP32.......

Die Version ist auch für 8Bit AVR dabei, aber:
Platform Type Compiler ROM size of
API in bytes                            7814            
ROM(.text+.data) in bytes Normal/lite   43291 / 26085
RAM(.data+.bss) in bytes Normal/lite    1064 / 1048
File Size* In bytes Normal/lite         141k / 85k  
Daten aus BSEC Binary Size Information.pdf.
Es kämen also nur Mega644/1284/2560 in Frage.

Mein Problem ist aber eher der Sensor selbst: das Ding misst die 
relative Luftgüte. Er muß durchlaufen und liefert erst nach mehreren 
Tagen sinnvolle Werte, auch nur dann, wenn es ausreichend gro0e 
Änderungen der Luftgüte gab.

Wenn das Ding z.B. in einer Werkstatt hängt, wo Staub, Dämpfe o.ä. 
auftreten, hat mach der Einlaufzeit einen Wert für "beste Luft" skaliert 
auf 25 des IAQ und eine "schlechte Luft" skaliert auf 250.
Abweichungen nach untern bzw. nach oben geben dann an, daß sich die 
Luftqualität am Ort verbessert oder verschlechtert hat.
Ob man ohne die BSEC-Lib ausgegebenen Wert des "Gas-Widerstandes" 
überhaupt irgendwie nutzen kann, ist mir im Moment völlig unklar.

Ich habe also keine Ahnung, was ich mit dem Ding nun eigentlich mache, 
aber zum Glück habe ich ihn ja nur aus reinem Spaß und Interesse 
gakauft.

Gruß aus Berlin
Michael

: Bearbeitet durch User
Autor: Heiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu kommt, dass der zurück gegebene Widerstand davon abhängt, wie oft 
man misst. Wenn man seltener misst, ist der Wert kleiner. Ich nehme an, 
dass sich die Substanzen aus der Luft im Sensor anlagern und man das 
Messen gleichzeitig als "Freibrennen" betrachten kann. Wenn man öfter 
freibrennt, sind eben weniger flüchtige Stoffe im Sensor...

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Michael U. schrieb:
> Diese Version habe ich zumindest zu Laufen bekommen:
> https://github.com/BoschSensortec/BSEC-Arduino-library
>
> ArduionoIDE 1.8.10 und ESP32-Boardmanagerversion 1.04.
> Allerdings hat es da ein anderes Problem gegeben: nach der Änderung der
> plattform.txt compiliert nichts anderes mehr für den ESP32.......

ich zitiere mich mal selbst, man sollte nicht eine Ergänzung in der 
platform.txt vergessen, dann klappt es alles ohne Probleme.

Ich werde das mal an einem Odroid Go dran lassen, die Ausgabe auf dem 
Display noch einbauen und den Kram mal längere Zeit beobachten. Bekommt 
dereine Odroid Go wenigstens mal eine Verwendung. ;)

Gruß aus Berlin
Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.