Register von Attiny2313 via I2C lesen



  • Hallo,

    ich versuche schon seit mehreren Tagen, Werte aus den Registern eines Attiny auszulesen und bekomme es einfach nicht hin. (Master ist ein Raspberry Pi)

    Habe schon diverse Beispielcodes aus dem Internet ausprobiert, jedoch bekomme ich nicht die Werte zurück, welche in den Registern stehen.

    Vom Ablauf muss es ja folgendermaßen ablaufen:

    Gerät ansprechen
    Register ansprechen
    Lesen

    Oder liege ich da falsch?

    Das passende Gerät wähle ich folgendermaßen aus:

    void I2C_SelectDevice(uint8_t addr, char * name) {
    
        if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0) {
            printf("%s nicht verfuegbar...\n", name);
            return(0);
        }
    }
    

    Gelesen wird so:

    if (read(i2c_fd, ret, len) == -1) {
            printf("Lesen fehlgeschlagen...\n");
            return(0);
        }
    

    Nur das Register ansprechen bekomme ich einfach nicht hin. Über den Write-Befehl ja, aber dann überschriebe ich mir den Wert, den ich auslesen möchte.

    Gedacht war das von mir etwa so:

    void I2C_ReadFromRegister(uint8_t reg, uint8_t len, char ret[]) {
    
        // Register ansprechen
        // ...
        if (read(i2c_fd, ret, len) == -1) {
            printf("Lesen fehlgeschlagen...\n");
            return(0);
        }
    }
    

    Mit den I2C-Tools erhalte ich die richtigen Werte der Register.

    Ich denke ihr könnt mir hierbei auf die Sprünge helfen.



  • T1g0r schrieb:

    void I2C_SelectDevice(uint8_t addr, char * name) {
       //...
       return(0);
    }
    
    void I2C_ReadFromRegister(uint8_t reg, uint8_t len, char ret[]) {
        // ...
        return(0);
    }
    

    Mit I2C kenne ich mich nicht aus. Aber: Ist es korrekt, daß eine void-Prozedur über return einen Wert (0) zurückgibt? Falls das falsch ist, aber trotzdem ohne Fehlermeldung compiliert wird, dann ist zu bedenken, daß Funktionsargumente, Rückgabewert u.a in einer von Konventionen bestimmten Reihenfolge auf dem Stack abgelegt werden und diese Reihenfolge im Fehlerfall mögl.weise nicht mehr gegeben ist. LG



  • Und wie (d.h. mit welchen Parametern) rufst du die Funktion "I2C_ReadFromRegister" auf?



  • Hi,

    also mittlerweile habe ich den Code soweit, dass ich vom Register 0 eine bestimmt Anzahl an Bytes auslesen und mir dann das raussuche, welches ich benötige.

    Hier mal der Gesamte Code:

    Aufruf im in der main-Prozedur:

    I2C_SelectDevice(TinyAdr, "ATTiny2313"); // Tiny auswählen
    
    I2C_ReadFromRegister(atoi(Arr_Befehle[1]), 1, zuruck); // Die Parameter werden noch nicht genutzt
    

    SelectDevice-Prozedur:

    uint8_t I2C_SelectDevice(uint8_t addr, char * name) {
    
        if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0) {
            printf("%s nicht verfuegbar...\n", name);
            return(EXIT_FAILURE);
        }
        return(EXIT_SUCCESS);
    }
    

    ReadFromRegister-Prozedur:

    uint8_t I2C_ReadFromRegister(uint8_t reg, uint8_t len, char ret[]) {
    
        buffer[0] = 0;
        buffer[1] = 0;
        buffer[2] = 0;
        buffer[3] = 0;
    
        I2C_WriteToRegister(0, 0);                      // In Register 0 Wert 0 schreiben
        I2C_SelectDevice(0x10, "Tiny");
    
        length = sizeof(buffer);                        //<<< Number of  bytes to read
    
        if (read(i2c_fd, buffer, length) != length){           //read()  returns the number of bytes actually read, if it doesn't match then an  error oc$
            //ERROR HANDLING: i2c transaction failed
            printf("Failed to read from the i2c bus.\n");
            return(EXIT_FAILURE);
    
        }
        else {
            for(i = 0; i <= length; i++)
            {
                printf("Data read %hhu: %hhx - %hhu\n", i,  buffer[i], buffer[i]);
            }
            return(EXIT_SUCCESS);
        }
    }
    

    WriteToRegister-Prozedur:

    int length;
    
    uint8_t buffer[40] = {0};
    
    uint8_t I2C_WriteToRegister(uint8_t reg, uint8_t val) {
    
        u_int8_t buf[2];
        buf[0] = reg; // Register
        buf[1] = val; // Wert
    
        if (write(i2c_fd, buf, 2) == -1) {
            printf("Schreiben in Register fehlgeschlagen...\n");
            return(EXIT_FAILURE);
        }
        return(EXIT_SUCCESS);
    }
    

    Schöner wäre natürlich, wenn ich das Register direkt ansprechen könnte, welches ich auslesen möchte. Ich weiß aber nicht wie ich auf das Register zeige, ohne dessen Wert zu ändern.



  • Schau dir mal i2c-read-register.c (Funktion "read_register") an - so wie ich verstehe, schreibst du vorher mittels write() die Registernummer raus, von der du dann lesen willst.

    Edit: Hier noch mal explizit (und mit Bildchen): I2C access examples



  • Ich kapiers nicht.
    Ich habe den Code auf den in dem Link (https://github.com/bentiss/i2c-read-register/blob/master/i2c-read-register.c) gezeigten Code angepasst. Wenn ich nun aber aus Register 1 lesen, wird auf Register 1 der Wert 0 geschrieben...

    reg_buf[0] = (reg >> 0) & 0xFF ; = 1 wenn reg = 1
    reg_buf[1] = (reg >> 😎 & 0xFF ; = 0 wenn reg = 1

    //Edit:

    ich hatte uint16_t anstelle __uint16_t angegeben. Was ist da der Unterschied?

    Hier der Code der nun funktioniert:

    uint16_t I2C_ReadFromRegister(uint16_t reg, uint8_t *buf, uint16_t bufsize) {
    
        uint16_t reg_buf[1];
        uint16_t ret;
        reg_buf[0] = (reg >> 0) & 0xFF;
    
        ret = write(i2c_fd, reg_buf, 1);
        if (ret < 0) {
                printf("Failed to write [0x%02x 0x%02x] (reg: %04x).\n", reg_buf[0], reg_buf[1], reg);
                return ret;
        }
    
        printf("wrote %d bytes\n", ret);
        return read(i2c_fd, buf, bufsize);
    }
    

Log in to reply