Integer array in eeprom eines sensors über i2c schreiben und lesen

Hallo!

Ich habe folgendes Problem: Ich muss 16 integer-Werte in den eeprom (ab 0x8000) eines Wärmebildsensors (i2c adresse = 0x33) schreiben.

Zuerst lese ich die bestehenden Werte aus, gebe dann die zu schreibenden Werte aus und zuletzt sollten diese neuen Werte auch wieder gelesen werden.

Das Problem ist nun, dass ich die alten Werte zwar schön lesen kann, diese aber nicht durch die neuen ersetzt werden.

Die Vorlage für den sketch, den ich hierfür verwende ist hier zu finden:

#include <Wire.h>
#define I2C_EEPROM_ADRESSE 0x33
#define EEPROM_SPEICHER_ADR 0x8000

const uint16_t Anzahl_Rezepte = 16;  // anzahl Rezepte
uint16_t Zaehler[Anzahl_Rezepte] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool oneshot = true;



void setup()
   {
    Wire.begin();
    Serial.begin(9600);
    Serial.println("Programmanfang");

    i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));       // Liest die alten Werte aus dem EEPROM
  
    Serial.print("Zaehlerfeld vor dem Schreiben: \t");
    
    for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
       {
        Serial.print(Zaehler[j]);
        Serial.print(" ");
       }
    
    Serial.println();
   }



void loop()
   {
    //oneshot = false;
    
    if (oneshot)
       {
        Zaehler[0] = 9;
        Zaehler[1] = 171;      // = HEX AB
        Zaehler[2] = 18843;    // = HEX 499B
        Zaehler[3] = 0;
        Zaehler[4] = 8289;     // = HEX 2061
        Zaehler[5] = 5;
        Zaehler[6] = 800;      // = HEX 320
        Zaehler[7] = 992;      // = HEX 3E0
        Zaehler[8] = 6694;     // = HEX 1A26
        Zaehler[9] = 41512;    // = HEX A228
        Zaehler[10] = 389;     // = HEX 185
        Zaehler[11] = 1177;    // = HEX 499
        Zaehler[12] = 0;
        Zaehler[13] = 6401;    // = HEX 1901
        Zaehler[14] = 0;
        Zaehler[15] = 0;

        Serial.print("neu zu schreibende Werte: \t");

        for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
           {
            Serial.print(Zaehler[j]);
            Serial.print(" ");
           }
        
        i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));     // Schreibt die neuen Werte in den EEPROM


        i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));       // Liest die neuen Werte aus dem EEPROM
        
        Serial.println();
        Serial.print("Zaehlerfeld nach dem Schreiben: \t");
        
        for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
           {
            Serial.print(Zaehler[j]);
            Serial.print(" ");
           }
        
        Serial.println();
        
        oneshot = false;
       }
   }



void i2c_eeprom_updateUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t buf[anzahlElemente];
    i2c_eeprom_readUIntArray(deviceaddress, eeaddress, buf, sizeof(buf) / sizeof(buf[0]));
    uint16_t eadr=eeaddress;
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        if ((ptr[j] >> 8) != (buf[j] >> 8))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] >> 8);
            Wire.endTransmission();
            delay(10);
           }
       
        eadr++;
    
        if ((ptr[j] & 0xFF) != (buf[j] & 0xFF))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] & 0xFF);
            Wire.endTransmission();
            delay(10);
           }
        eadr++;
       }
   }



void i2c_eeprom_readUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t data = 0xFF;
    delay(2);
    
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress, anzahlElemente << 1);
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        delay(5);
        data = Wire.read() << 8;
        delay(5);
        data = data | Wire.read();
        ptr[j] = data;
       }
   }

Ergebnis:
Programmanfang
Zaehlerfeld vor dem Schreiben: 9 172 27039 0 8289 5 800 992 2571 24488 390 1177 0 6657 0 0
neu zu schreibende Werte: 9 171 18843 0 8289 5 800 992 6694 41512 389 1177 0 6401 0 0
Zaehlerfeld nach dem Schreiben: 9 172 27039 0 8289 5 800 992 2571 24488 390 1177 0 6657 0 0

Vielleicht kann mir ja jemand von den Profis helfen. Danke im voraus, lg stoppi

Schön wäre auch noch zu wissen welchen Wärmebildsensor Du verwendest damit man das Speicherprotokoll mal in Datenblatt nachschauen kann. Grüße Uwe

Ich mag EEPROMs, siehe hier , hier und natürlich auch dieses

Leider hast du vergessen, zu sagen, um welches EEProm es sich dreht. Und auch vergessen zu sagen, wie du es angeschlossen hast.

Vielleicht kann mir ja jemand von den Profis helfen.

Ich weiß ja nicht genau wer Profi ist.... (Sind das sie dicken Frauen, mit den Warzen auf der Nase, die man auf dem Jahrmarkt findet, die mit der hochglanz polierten Kristallkugel?)

Hallo!

Danke für die Rückmeldung. Kann das Datenblatt wegen der Größe (2.8 MB) nicht anhängen.

https://www.google.at/search?source=hp&ei=gs5SXIeFFdHRwAKt25LACQ&q=mlx90640+datasheet&btnK=Google-Suche&oq=mlx90640+data&gs_l=psy-ab.3.0.0i19.1262.6889..8087...0.0..0.540.2610.7j5j4-2j1......0....1..gws-wiz.....0..0i131j0j0i22i30i19.v1Qa4Z5FY5I

Gleich der erste Link vom Hersteller Melexis...

Angeschlossen habe ich den Sensor an einen Arduino Due über SCL/SDA.

Es handelt sich um diesen Sensor: https://www.aliexpress.com/item/GY-MCU90640-MLX90640-IR-32-24-Infrared-Thermometric-Dot-Matrix-Sensor-Camera-Module/32958277975.html?spm=a2g0s.9042311.0.0.25dc4c4ditbkBP

in den eeprom (ab 0x8000)

Liegt das EEPROM nicht eher bei 0x2400

Die Speicheradresse 0x8000 habe ich von einen anderen Leser, der folgendes zum MLX90640 geschrieben hat:

Hallo Christoph,

vor einiger Zeit habe ich auch mit dem Sensor und einem ESP32 herum probiert. Es ging ewig lange nichts und ich habe schon geglaubt, es liegt am Sensor. Dann habe ich einen zweiten bekommen, da ging auch nichts.

Irgendwann hatte ich aber ein Lösung gefunden: Der Sensor hat ein EEPROM eingebaut und es ist vermutlich so, dass die meiste Open-Source-Software nur mit den vor eingestellten Werten funktioniert ( ich weiß nicht mehr, ob es Adafruit war, die den Sensor mit vor eingestellten Werten ausliefern ). Die anderen gehen dann nicht mit der Software. Ich habe die dann rein geschrieben, und siehe da, beide Sensoren gingen. Leider weiß ich schon nicht mehr, welche es waren.

Das hier sind die Werte ab Adresse 0x8000, mit dem der Sensor geht. Vielleicht hilft Dir das weiter:

// Sparkfun sensor Device found @ 0x33 0: 9 1: AB 2: 499B 3: 0 4: 2061 5: 5 6: 320 7: 3E0 8: 1A26 9: A228 10: 185 11: 499 12: 0 13: 1901 14: 0 15: 0

Ich glaube du verwechselst da was....

z.B.: Es ist relevant, was im Datenblatt steht. Nicht die unüberprüfbaren Erkenntnisse, von irgendwelchen Leuten, die evtl. sogar weniger Durchblick haben, als du und ich.

1) laut Datenblatt ist die EEPROM-Adresse ab 0x2400. Die Registeradresse ist ab 0x8000. 2) die meisten dieser Register kann der User gar nicht schreiben.

Grüße Uwe

Danke für eure Antworten.

Das eigenartige ist nur, dass die neuen gelisteten Werte ab 0x8000 nachvollziehbar sind, da viele mit den Werten meines Sensors übereinstimmen...

Problem ist auch, dass ich die betreffende Person in einem anderen Forum nicht dazu befragen kann (ist dort als Gast angemeldet).

Mein Hauptproblem ist, dass ich das Arduino-Programm https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example

partout mit dem Arduino Due zum Laufen bringe. Das geht aber nicht nur mir so. Empfohlen wird auf sparkfun ein Teensy...

Wenn ich das Programm https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example/tree/master/Firmware/Example1_BasicReadings auf dem Due laufen lassen, erhalte ich anstelle der Temperaturen nur "nan" (not a number).

Und wie die betreffende Person geschrieben hat, wäre dafür eben der andere eeprom Inhalt bei sparkfun-boards verantwortlich.

Offensichtlich ließt du das Datenblatt nicht.
Auch/Oder hast es hier, mit dem logischen Denken, da scheint es gerade zu klemmen

Also ein kleiner Lehrgang:
(Folge 1)

Das eigenartige ist nur, dass die neuen gelisteten Werte ab 0x8000 nachvollziehbar sind, da viele mit den Werten meines Sensors übereinstimmen…

Du schaust in die Registerbank und findest ähnliche Werte…
Das ist schön.
Ist aber doch nicht dein unmittelbares Ziel.
Kann es gar nicht sein.
Denn laut Doku kannst/darfst du den Bereich nicht beschreiben

Noch ein KO Kriterium:
Laut Doku ist da kein EEPROM.

Also:
Später, kannst du diese wichtige Informationseinheit(0x8000) gerne wieder einsetzen, aber jetzt ist die Adresse 0x8000 eher ein Hemmnis in deinem Kopf.

Soweit klar?
Klar, dass dich die 0x8000 nicht unmittelbar weiter bringt?
Dass du sie erst mal aus dem Hirn streichen solltest?

Möglicherweise interessante Texte aus dem Datenblatt:

NOTE 2: When a data in EEPROM cell to be changed an erase (write 0x0000) must be done prior to writing the new value. After each write at least 5ms delay is needed in order to writing process to take place.

After POR the device read dedicated EEPROM cells and transfers their content to into the control and configuration register of the device. This way the device is configured and prepared for operation. The relation between EEPROM and register address is shown here after (explanation of the bit meaning can be found in section 10.7.1 Internal registers):

Vielen Dank für eure Hilfe. Ich hatte halt gehofft, dass durch Abänderung einzelner Parameter der Sensor sich problemlos vom Arduino auslesen lässt. ;)

....dass durch Abänderung einzelner Parameter der Sensor sich problemlos vom Arduino auslesen lässt.

Das kann ich dir nicht versprechen, da ja nicht klar ist, wo dort deine Probleme sind.

Ich hatte halt gehofft, dass durch Abänderung einzelner Parameter...

Hat das denn mittlerweile geklappt? Und, wenn nein, wo ist das Problem?

Sparkfun verkauft ein Board mit dem MLX90640 und liefert auch gleich neben der Melexis-library eine Arduino-Software (SparkFun_MLX90640_Arduino_Example/Example1_BasicReadings.ino at master · sparkfun/SparkFun_MLX90640_Arduino_Example · GitHub)

Verwendet man einen Teensy, so scheint es keine Probleme mit dem Auslesen zu geben. Aber bei Verwendung eines Arduino Due habe ich im Internet noch keine Erfolgsmeldungen vernehmen können. Einschränkender Faktor den MC betreffend scheint ja nur der notwendige Speicher zu sein (>20kB). Von daher käme eben der Arduino Due in Frage.

Was mich interessiert ist der Grund, warum das Programm mit einem MC (Teeny, ESP32, Raspberry) ohne Probleme läuft, mit einem anderen aber nicht. Da heißt es immer wieder im Internet, dass das I²C beim Arduino Due Probleme macht.

Im Forum mikrocontroller.net hat dann eben besagter Leser mir dahingehend einen Tipp gegeben, das eeprom des MLX90640 abzuändern. Er hätte damit und einem ESP32 den Sensor auslesen können (ich vermute mit dem Sparkfun-Programm von oben).

Bis jetzt waren meine Versuche die Speicherstellen abzuändern nicht erfolgreich. Und den Antworten hier im Forum folgend kann ich die Register um 0x8000 auch gar nicht ändern. Das ist jetzt der aktuelle Stand der Dinge.

Meinen MLX90640 von aliexpress habe ich über den am board integrierten MC (STM32F103) seriell (RX/TX) mit einigen Problemen aber immerhin auslesen können. Doch dann war aus unbekannter Ursache plötzlich die Kommunikation tot. Jetzt hoffe ich, dass nur der STM32F103 defekt ist und der MLX90640 noch lebt und über I²C ansprechbar ist.

Falls das aber nicht zum Erfolg führen https://forum.arduino.cc/index.php?action=post;topic=594703.0;last_msg=4041062#sollte, habe ich bereits ein zweites board bei aliexpress geordert. Dann lese ich die Daten halt wieder über RX/TX aus. Das hat allerdings den Nachteil, dass die Bildrate sehr gering ist (rund 1 fps).

Bis jetzt waren meine Versuche die Speicherstellen abzuändern nicht erfolgreich. Und den Antworten hier im Forum folgend kann ich die Register um 0x8000 auch gar nicht ändern. Das ist jetzt der aktuelle Stand der Dinge.

Genau! Denn da ist kein EEPROM. (aber das sachte ich schon, und steht so auch im Datenblatt)

Du willst aber die Daten im EEPROM ändern. Dann solltest du das auch tun. Das Datenblatt ist da völlig eindeutig, mit den Anweisungen und Angaben. Ich kann leider nicht erkennen, wo da dein Problem ist.

Ob das deine anderen Probleme löst, kannst nur du in Erfahrung bringen.

stoppi: Verwendet man einen Teensy, so scheint es keine Probleme mit dem Auslesen zu geben.

Hier im Forum scheint niemand Deinen Sensor zu haben. Auch der Due ist wohl nicht arg verbreitet. Das sind keine optimalen Voraussetzungen für eine praxisbezogene Hilfe.

Daher überlege ich, ob es nicht eine gute Idee wäre, wenn Du Dir einen Teensy zulegen würdest. Dann könntest Du die Aussagen überprüfen und ggf. von einem funktionierendem System aus Schlüsse ziehen.

Mein Teensy 3.2 animiert LEDs in der Bar, der ist also immer zu was zu gebrauchen.

Hallo!

Ich habe mit anstelle des Teensy einen ESP32 bestellt, damit müsste es laut Recherche auch klappen. Den Arduino Due hätte ich nur gerne, da ich dafür ein 320x480 display habe und ich die graphische Ausgabe des Wärmebilds bereits programmiert habe...

Was den EEPROM betrifft, werde ich da nichts weiter ändern da ich auch nicht wüsste, welche Änderungen sinnvoll wären, um das Sparkfun-Arduino-Programm zum Laufen zu bringen. Ich habe ja nur den einzigen (scheinbar falschen) Hinweis mit Werten ab 0x8000...

Ich habe ja nur den einzigen (scheinbar falschen) Hinweis mit Werten ab 0x8000...

Hach... Der Hinweis ist nur "scheinbar falsch", weil du ihn nicht verstehst. Und auch das Datenblatt nicht.

Richtig ist: Die Werte haben sich "hinterher" bei Adresse 0x8000 einzufinden.

Richtig ist: Du musst die Werte ins EEPROM schreiben, ohne dem werden sie sich nie nicht bei 0x8000 einfinden.

Diese beiden Groschen müssen bei dir fallen. Beide.


Hmmm... Teil meines Namens, meiner Präsentation hier, ist "DokuVorLeseVerweigerer". Diesen Teil habe ich nicht ohne Grund so benannt. Denn selber Doku lesen, macht selber schlau.

Vielen Dank, jetzt wird es für mich schon klarer. Wenn ich das Datenblatt richtig verstehe, kann ich aber nur die Adressen 0x240C bis 0x240F verändern, was wiederum zu Änderungen in den Registeradressen 0x800D bis 0x8010 führt.

Demnach sind für mich die Adressen 0x8000 bis 0x800C tabu oder?

Die Adressen 0x800C, 0x800E und 0x800F sind aber bei mir und dem Leser ident. Bleibt also nur noch 0x800D, wo ich den Wert 6657 und er den Wert 6401 = 0x1901 hat.

Ist das soweit richtig?