I2C-Adressierung nach Geräteadresse ist bekannt

Ich habe ein I2C-Gerät, von dem ich weiß, dass die Adresse 0x70 ist (geprüft, wenn es mit i2cdetect -y 1 an Raspberry Pi angeschlossen ist). Mein Problem ist, dass die Bytes, die ich mir ansehen möchte, in WiringPi aufgerufen werden müssen. Der Ausgabe-String ist sieben Byte lang und WiringPi schaut auf die Geräteadresse und dann auf die Byte-Adresse, die ich lesen möchte.Würde die Adressierung wie folgt aussehen:

Device Adr.= 0x70: First Byte Adr.= 0x01 ----oder---- First Byte Adr.=0x71

Benötigt die Adresse eine 'neue' Adressidentifikation (beginnend bei 1) oder wird die Adressnummer an die Geräteadresse 'angehängt' (ja, ich verwende das locker)?


Neue Informationen: Ich habe diese Dokumentation gefunden, nachdem ich sie gründlicher durchsucht hatte: Upgrade Guide und Short Communication Guide

Es scheint, dass aus dem Upgrade-Blatt die interne Adresse des Slaves für das Adressbyte 0xE0 für das Schreiben lautet . Das Befehlsbyte, das ich verwenden möchte, ist der Befehl (#3.5): 0b000001100 (was ich in Hex annehme: 0x0C ). Es scheint dann, dass das Adressbyte zum Lesen 0xE1 ist . Wie würde ich von diesem Punkt an aus den Datenbytes lesen, da ihre Register nicht explizit angezeigt werden (siehe Upgrade Guide)?

Hier ist mein aktueller Code in WiringPi (C++):

#include <iostream>
#include <errno.h>
#include <wiringPiI2C.h>

using namespace std;

#define SLAVE_ADDR 0x70
#define DEV_ADDR_W 0XE0
#define DEV_ADDR_R 0XE1
#define DEV_COMMAND 0X0C //GET STATUS


int main(){
    int fd,writeRes,comm_res,readRes;
    fd=wiringPiI2CSetup(SLAVE_ADDR);
    cout<<"Initial Result: "<<fd<<endl;

    for(int i=0;i<1;i++){
        writeRes=wiringPiI2CWriteReg8(fd,DEV_ADDR_W,0);
        cout<<"Write to Address(write): "<<writeRes<<endl;
        comm_res=wiringPiI2CWriteReg8(fd,DEV_COMMAND,0);
        cout<<"Slave Command Acknowledge: "<<comm_res<<endl;
        readRes=wiringPiI2CWriteReg8(fd,DEV_ADDR_R,0);
        cout<<"Write to Recieve Data: "<<readRes<<endl;
        int readD_1=wiringPiI2CReadReg8(fd,0x0D);
        cout<<"Data 1, VOC= "<<readD_1<<endl;
    }

    return 0;
}

0x70? Ist es ein I²C-Mux?
@Janka, Wenn Raspberry Pi nicht explizit einen Multiplexer verwendet, lautet die Antwort nein. Ich bin hardwareseitig noch unerfahren mit I2C.
Wie lautet die Teilenummer des Geräts, auf das Sie zugreifen möchten?
Es wird von SPEC Technologies, MiCS-VZ-89TE hergestellt. Verknüpfung
Leider sagt dieses Blatt nichts über die I²C-Schnittstelle dieses Boards aus. Wenn ich diese Informationen hätte, könnte ich Ihnen den richtigen C-Quellcode (ca. 10 Zeilen) geben, den Sie verwenden müssten. Warum möchten Sie WiringPi verwenden? Linux hat eine eingebaute I²C-Unterstützung.
@Brandon Das Datenblatt für Ihr Sensorboard lässt zu wünschen übrig - zum Beispiel eine Tabelle mit I2C-Registern. Ich würde kein Teil mit einem so schlechten Datenblatt entwerfen.
Hier pocketmagic.net/mics-vz-89-air-quality-sensor ist ein Link mit etwas Code, um auf das Board zuzugreifen. Es sieht so aus, als ob es wiederholte Starts verwendet, was zu Verwirrung führen könnte.
Danke euch allen. Ich weiß, dass das Datenblatt für die Adressierung schrecklich ist, aber das ist, was ich habe. Ich habe mir das Pocketmagic-Blatt angesehen und fange an, mir ein paar Gedanken darüber zu machen, was los ist.
Dieser Quellcode ist sehr einfach und klar. Wiederholter Start ist Standard, wenn Sie von Schreiben auf Lesen umschalten müssen. Sie müssen zuerst die Adresse im Schreibmodus schreiben, dann die Registernummer, dann erneut starten, die Adresse im Lesemodus schreiben, dann alle Daten lesen. So funktionieren die meisten I²C-Sensoren.
Außerdem, @Janka, verwende ich WiringPi, weil es mir mehr Flexibilität gibt, wenn ich mehr Module in mein System integriere. Ich muss zuerst sicherstellen, dass der Code mit jedem Modul gut funktioniert, und dann sehen, ob es funktioniert, wenn sie alle zusammen sind.
Ich empfehle Pigpio gegenüber WiringPi. Schauen Sie sich meine Antwort hier an raspberrypi.stackexchange.com/questions/3627/… für ein Beispiel dafür, wie einfach es ist, wiederholte Starts durchzuführen
@BrandonWilliams - Ich kann bei Ihrer Frage zu WiringPi nicht helfen, da ich es nicht verwende (also schreibe ich dies nicht als Antwort), aber es gibt ein Dokument für Ihr Gerät, das speziell sein I2C-Kommunikationsprotokoll beschreibt (und die Tatsache, dass dort ist eine erforderliche Verzögerung). Wenn Sie es also noch nicht gesehen haben, lesen Sie dies: SGX VZ89TE I2C-Kommunikation .
@Brandon Auf Ihrer Sensorplatine befindet sich ein IC. Was ist das Modell des IC? Ist das ein Standard-IC? Oder ist das ein ASIC?
@NickAlexeev, ich kann diese Informationen nicht finden. Auch die Schrift ist zu klein zum lesen.

Antworten (2)

Bitte sehen Sie sich den folgenden C-Quellcode an, der den Standard-Linux-I²C-Treiber verwendet. Der Schlüssel liegt im Verständnis der Parametervorbereitung von ioctl(). Der komplette I²C-Transfer wird vom Kernel-Treiber automatisch abgewickelt.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

int main(int argc, char* argv[]) {
    struct i2c_msg i2c_msgs[2];
    struct i2c_rdwr_ioctl_data i2c_transfer;
    uint8_t rdata[6];
    int fd;

    /* Open I2C device. */
    fd = open("/dev/i2c-1", O_RDWR);
    if (fd < 0) {
        perror("i2c device open");
        return 2;
    }

    /* Select and read CO2 register. */
    i2c_msgs[0].addr   = 0x70;
    i2c_msgs[0].flags  = 0;
    i2c_msgs[0].len    = 1;
    i2c_msgs[0].buf    = "\x08";

    i2c_msgs[1].addr   = 0x70;
    i2c_msgs[1].flags  = I2C_M_RD;
    i2c_msgs[1].len    = 6;
    i2c_msgs[1].buf    = (char*)&rdata;

    i2c_transfer.msgs  = i2c_msgs;
    i2c_transfer.nmsgs = 2;

    if (ioctl(fd, I2C_RDWR, &i2c_transfer) < 0) {
        perror("i2c CO2 read");
        return 2;
    };

    /* Print result. */
    printf("%02x %02x %02x %02x %02x %02x\n", rdata[0], rdata[1], rdata[2], rdata[3], rdata[4], rdata[5]);

    /* Finish. */
    close(fd);
    return 0;
}
Ignorieren wir das 7. Byte, da Sie die Länge des rdata-Arrays als 6 definiert haben?
Der Code auf dieser Seite pocketmagic.net/mics-vz-89-air-quality-sensor sagt, dass es 6 Bytes zu lesen sind.
Wenn Sie verwirrt sind, macht der Kernel-Treiber S,0x70WR, 0x08,S,0x70RD,xx,xx,xx,xx,xx,xx,P
Im Code bekomme ich mehrere Fehler. Die erste ist die struct i2c_msg i2c_msgs[2];Fehlermeldung, die besagt, dass der Array-Typ einen unvollständigen Elementtyp hat. Und zweitens, meintest du etwas anderes als I2C_M_RDwie etwas von hier
Bitte fügen Sie #include <sys/ioctl.h>und #include <linux/i2c.h>zur Liste der Einschließungen hinzu. Leider enthält die explizite erforderliche Änderung mit jeder API-Version.
Nach der Kompilierung ./i2ctest2(benannt mit gcc -o) ergibt sich aSegmentation Fault
Hmm, das ist schade, denn bei mir funktioniert es (mit einem anderen Chip bei 0x50). Versuchen Sie, es mit einem Debugger auszuführen, um den Übeltäter zu finden: gdb ./i2ctest2, dann runan der gdb-Eingabeaufforderung.
Es gab mir ursprünglich während der Kompilierung Warnungen über "Zuweisung von inkompatiblem Zeigertyp" für i2c_transfer.msgs =i2c_msgs;, könnte das das Problem sein?
Wenn Sie es mit den zusätzlichen Includes neu kompiliert haben, sollte es überhaupt ohne Warnungen kompiliert werden. Manchmal ist -std=c99 erforderlich, dies hängt vom verwendeten Compiler ab. Du hast das auf dem Raspi gcc gemacht, oder? Denn ein x86-Binary läuft nicht auf dem Raspi.
Gcc Dateiname.c -o exDateiname
Vielleicht fehlen Ihnen diese Include-Dateien in Ihrer Installation? Sie gehören zum Paket linux-libc-dev in Raspbian.

[Gelöst] Dieses Modul ist ein nützliches Werkzeug, sobald Sie gelernt haben, wie man damit arbeitet. Nachdem ich Gordon (von wiringPi) eine E-Mail geschickt hatte, wurde darauf hingewiesen, dass ich versuchte, zu tief zu schauen. Raspberry Pi kümmerte sich um das, worüber ich mir Sorgen machte. In dem Wissen, dass es einige Versuche und Irrtümer bedurfte, um Adressen und Befehle korrekt zu erhalten, aber mein folgender Code scheint zu funktionieren, bevor die Kalibrierung und das Testen der CO2-Empfindlichkeit abgeschlossen sind (Hinweis: Der 'cout'-Ausgang, der den Datenpuffer ausliest, ist ausgeschaltet. Aber das ist es nicht zu jetzt wichtig):

#include <iostream>
#include <unistd.h>
#include <cstdint>
#include <wiringPiI2C.h>
#include <cerrno>

using namespace std;

const uint8_t dev_id = 0x70;
const uint8_t dev_addr = 0b000001100;
const uint8_t dev_comm = 0x0C;
const uint8_t dev_data = 0x00;

uint8_t getCRC(uint8_t bytes_to_send[6]){
    uint8_t byte_sum = 0x00;
    uint8_t crc;
    for(int i=0; i<6 ; i++){
        byte_sum += bytes_to_send[i];
    }
    crc = byte_sum;
    crc += (byte_sum/(0x0100));
    crc = 0xFF - crc;
    return crc;
}

int main(){
    int fd;
    int write_res;
    uint8_t sensor_data[8];
    int read_res;
    uint8_t crc;
    uint8_t out_buff[6]{dev_addr, dev_comm, dev_data, dev_data, 
        dev_data, dev_data};
    crc = getCRC(out_buff);
    cout<<"CRC: "<<(int)crc<<endl;
    uint8_t out_buff_full[7]{dev_addr, dev_comm, dev_data, dev_data, 
        dev_data, dev_data, 0xFF /*crc*/};
    if((fd=wiringPiI2CSetup(0x70)) < 0){
        cout<<"Error Occured in setting up Dev_ID: 0x70"<<endl;
        return 0;
    }
    else{
        cout<<"FD= "<<fd<<endl;
        cout<<"-------------Before Writing, Check Sensor Array---------------"<<endl;
        read_res = read(fd, sensor_data, 8);
        cout<<"1: "<<(int)sensor_data[0]<<endl;
        cout<<"2: "<<(int)sensor_data[1]<<endl;
        cout<<"3: "<<(int)sensor_data[2]<<endl;
        cout<<"4: "<<(int)sensor_data[3]<<endl;
        cout<<"5: "<<(int)sensor_data[4]<<endl;
        cout<<"6: "<<(int)sensor_data[5]<<endl;
        cout<<"7: "<<(int)sensor_data[6]<<endl;
        cout<<"8: "<<(int)sensor_data[7]<<endl;
        cout<<"-------------End Test Before Write---------------"<<endl;
        if((write_res = write(fd, out_buff_full, 7)) != 7){
            cout<<"There could be an issue writing to the file."<<endl;
            cout<<"Write returned: "<<write_res<<endl;
            return 0;
        }
        else{
            sleep(5);
            if((read_res = read(fd, sensor_data, 8)) != 8){
                cout<<"There could be an issue reading from the file."<<endl;
                cout<<"Read returned: "<<read_res<<endl;
                return 0;
            }
            else{
                cout<<"Returned Data {Address}: "<<(int)sensor_data[0]<<endl;
                cout<<"Returned Data {VOC}: "<<(int)sensor_data[1]<<endl;
                cout<<"Returned Data {CO2}: "<<(int)sensor_data[2]<<endl;
                cout<<"Returned Data {Raw Sensor Value[MSB]}: "<<(int)sensor_data[3]<<endl;
                cout<<"Returned Data {Raw Sensor Value}: "<<(int)sensor_data[4]<<endl;
                cout<<"Returned Data {Raw Sensor Value[LSB]}: "<<(int)sensor_data[5]<<endl;
                cout<<"Returned Data {Error Byte}: "<<(int)sensor_data[6]<<endl;
                cout<<"Returned Data {CRC}: "<<(int)sensor_data[7]<<endl;
            }
        close(fd);
        }
    }
    return 0;
}

Dieser Code wurde verifiziert und löst mein Problem.

Lektion: Raspberry Pi ist ein vollwertiger Computer (sogar für Kommunikationsprotokolle) und Sie können nicht zu weit in den Kaninchenbau gehen, Sie werden sich verlaufen.

Ich hoffe nur, dass dies jedem hilft, der es braucht.