I2C - muss man fd reseten?



  • Hallo Zusammen,

    ich hab ein Problem mit meinem BeagleBoard.
    Ich habe über I2C einen BMP Drucksensor angeschlossen.
    Soweit funktioniert alles recht gut.

    Ich lasse das Programm in einer while(1) Schleife laufen.

    Dort ist mir aufgefallen das fd hochzählt und das Programm nach 1023 durchläufen abbricht.
    Um das zählen zu beobachten habe ich einen printf für fd eingebaut.

    Leider weiß ich nicht wie ich das ändern kann, bzw ob ich fd zurücksetzen muss.
    Ich denke es liegt an einem Speicherüberlauf, aber ich komm nicht weiter.

    Ich hoffe Ihr könnt mir weiterhelfen.

    Vielen Dank schon mal

    Bernd

    Hier noch wie meine Ausgabe aussieht:
    ...
    Pressure 960.95 hPa
    Altitude 1584.6 Feet
    FD 1022
    FD 1022
    FD 1022
    Temperature 100.0 *F
    Pressure 960.99 hPa
    Altitude 1581.4 Feet
    FD 1023
    FD 1023
    FD 1023
    Temperature 100.0 *F
    Pressure 960.97 hPa
    Altitude 1584.6 Feet
    -> ABBRUCH

    #include <stdio.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include "../math.h"
    #include <unistd.h>
    #include <linux/i2c-dev.h>
    #include <sys/ioctl.h>
    
    #define BMP085_I2C_ADDRESS 0x77
    
    const unsigned char BMP085_OVERSAMPLING_SETTING = 3;
    
    // Calibration values - These are stored in the BMP085
    short int ac1;
    short int ac2;
    short int ac3;
    unsigned short int ac4;
    unsigned short int ac5;
    unsigned short int ac6;
    short int b1;
    short int b2;
    short int mb;
    short int mc;
    short int md;
    
    int b5;
    
    unsigned int temperature, pressure, altitude;
    
    // Open a connection to the bmp085
    // Returns a file id
    
    int bmp085_i2c_Begin() {
        int fd;
    
        // Open port for reading and writing
        if ((fd = open("/dev/i2c-2", O_RDWR)) < 0)
            exit(1);
    
        // Set the port options and set the address of the device
        if (ioctl(fd, I2C_SLAVE, BMP085_I2C_ADDRESS) < 0) {
            close(fd);
            exit(1);
        }
        printf("FD \t%i \n", ((int) fd));
        return fd;
    }
    
    // Read two words from the BMP085 and supply it as a 16 bit integer
    
    __s32 bmp085_i2c_Read_Int(int fd, __u8 address) {
        __s32 res = i2c_smbus_read_word_data(fd, address);
        if (res < 0) {
            close(fd);
            exit(1);
        }
    
        // Convert result to 16 bits and swap bytes
        res = ((res << 8) & 0xFF00) | ((res >> 8) & 0xFF);
    
        return res;
    }
    
    //Write a byte to the BMP085
    
    void bmp085_i2c_Write_Byte(int fd, __u8 address, __u8 value) {
        if (i2c_smbus_write_byte_data(fd, address, value) < 0) {
            close(fd);
            exit(1);
        }
    }
    
    // Read a block of data BMP085
    
    void bmp085_i2c_Read_Block(int fd, __u8 address, __u8 length, __u8 *values) {
        if (i2c_smbus_read_i2c_block_data(fd, address, length, values) < 0) {
            close(fd);
            exit(1);
        }
    }
    
    void bmp085_Calibration() {
        int fd = bmp085_i2c_Begin();
        ac1 = bmp085_i2c_Read_Int(fd, 0xAA);
        ac2 = bmp085_i2c_Read_Int(fd, 0xAC);
        ac3 = bmp085_i2c_Read_Int(fd, 0xAE);
        ac4 = bmp085_i2c_Read_Int(fd, 0xB0);
        ac5 = bmp085_i2c_Read_Int(fd, 0xB2);
        ac6 = bmp085_i2c_Read_Int(fd, 0xB4);
        b1 = bmp085_i2c_Read_Int(fd, 0xB6);
        b2 = bmp085_i2c_Read_Int(fd, 0xB8);
        mb = bmp085_i2c_Read_Int(fd, 0xBA);
        mc = bmp085_i2c_Read_Int(fd, 0xBC);
        md = bmp085_i2c_Read_Int(fd, 0xBE);
        close(fd);
    }
    
    // Read the uncompensated temperature value
    
    unsigned int bmp085_ReadUT() {
        unsigned int ut = 0;
        int fd = bmp085_i2c_Begin();
    
        // Write 0x2E into Register 0xF4
        // This requests a temperature reading
        bmp085_i2c_Write_Byte(fd, 0xF4, 0x2E);
    
        // Wait at least 4.5ms
        usleep(5000);
    
        // Read the two byte result from address 0xF6
        ut = bmp085_i2c_Read_Int(fd, 0xF6);
    
        // Close the i2c file
        close(fd);
    
        return ut;
    }
    
    // Read the uncompensated pressure value
    
    unsigned int bmp085_ReadUP() {
        unsigned int up = 0;
        int fd = bmp085_i2c_Begin();
    
        // Write 0x34+(BMP085_OVERSAMPLING_SETTING<<6) into register 0xF4
        // Request a pressure reading w/ oversampling setting
        bmp085_i2c_Write_Byte(fd, 0xF4, 0x34 + (BMP085_OVERSAMPLING_SETTING << 6));
    
        // Wait for conversion, delay time dependent on oversampling setting
        usleep((2 + (3 << BMP085_OVERSAMPLING_SETTING)) * 1000);
    
        // Read the three byte result from 0xF6
        // 0xF6 = MSB, 0xF7 = LSB and 0xF8 = XLSB
        __u8 values[3];
        bmp085_i2c_Read_Block(fd, 0xF6, 3, values);
    
        up = (((unsigned int) values[0] << 16) | ((unsigned int) values[1] << 8) | (unsigned int) values[2]) >> (8 - BMP085_OVERSAMPLING_SETTING);
    
        return up;
    }
    
    // Calculate pressure given uncalibrated pressure
    // Value returned will be in units of XXXXX
    
    unsigned int bmp085_GetPressure(unsigned int up) {
        int x1, x2, x3, b3, b6, p;
        unsigned int b4, b7;
    
        b6 = b5 - 4000;
        // Calculate B3
        x1 = (b2 * (b6 * b6) >> 12) >> 11;
        x2 = (ac2 * b6) >> 11;
        x3 = x1 + x2;
        b3 = (((((int) ac1)*4 + x3) << BMP085_OVERSAMPLING_SETTING) + 2) >> 2;
    
        // Calculate B4
        x1 = (ac3 * b6) >> 13;
        x2 = (b1 * ((b6 * b6) >> 12)) >> 16;
        x3 = ((x1 + x2) + 2) >> 2;
        b4 = (ac4 * (unsigned int) (x3 + 32768)) >> 15;
    
        b7 = ((unsigned int) (up - b3) * (50000 >> BMP085_OVERSAMPLING_SETTING));
        if (b7 < 0x80000000)
            p = (b7 << 1) / b4;
        else
            p = (b7 / b4) << 1;
    
        x1 = (p >> 8) * (p >> 8);
        x1 = (x1 * 3038) >> 16;
        x2 = (-7357 * p) >> 16;
        p += (x1 + x2 + 3791) >> 4;
    
        return p;
    }
    
    // Calculate temperature given uncalibrated temperature
    // Value returned will be in units of 0.1 deg C
    
    unsigned int bmp085_GetTemperature(unsigned int ut) {
        int x1, x2;
    
        x1 = (((int) ut - (int) ac6)*(int) ac5) >> 15;
        x2 = ((int) mc << 11) / (x1 + md);
        b5 = x1 + x2;
    
        unsigned int result = ((b5 + 8) >> 4);
    
        return result;
    }
    
    // This Altitude part is stolen from some some unknown
    // Arduino library.  The number divided into pressure for
    // float A is derived from the local pressure as explained
    // at http://learn.adafruit.com/bmp085/using-the-bmp085.
    
    unsigned int bmp085_Altitude(float pressure) {
        float A = pressure / 101794.58;
        float B = 1 / 5.25588;
        float C = pow(A, B);
        C = 1 - C;
        C = C / 0.0000225577;
    
        return C;
    }
    
    int main(int argc, char **argv)
     {
        while (1) {
    
            bmp085_Calibration();
    
            temperature = bmp085_GetTemperature(bmp085_ReadUT());
            pressure = bmp085_GetPressure(bmp085_ReadUP());
            altitude = bmp085_Altitude(pressure);
    
            printf("Temperature\t%0.1f *F\n", ((double) temperature) / 10 * 1.8 + 32);
            printf("Pressure\t%0.2f hPa\n", ((double) pressure) / 100);
            printf("Altitude\t%0.1f Feet\n", ((double) altitude)*3.280839895);
        }
        return 0;
    }
    


  • In bmp085_ReadUP sehe ich kein close .

    Ansonsten das open einmal vor dem while(1) machen und den anderen Funktionen das fd mitgeben.



  • Hallo Dirk,

    vielen Dank für die schnelle Antwort.

    Genau das war der Fehler, ich habs nicht gesehen.

    DANKE

    Gruß
    Bernd


Log in to reply