Questions about i2c.c (TMP102 temperature sensor)

Nick Hibma Nick at ip-knowhow.com
Thu Dec 1 10:11:19 UTC 2016


Gents,

I am not quite sure who to owner of i2c.c is, so perhaps some I2C enthousiast could help me with the following problem.

I was trying to access a TMP102 I2C temperature sensor. It kind of works with the default i2c utility. But it returns twice the high byte instead of the high and low byte for the temperature. Probably because it does 1 byte reads on the I2C bus, sending a stop condition after every byte. This was verified with a logic analyser.

The device expects continuous reads and no stop/start in between the 2 bytes. Trying all options i2c, most notably the -m mode switch, yields the same results all the time. Looking at the code in i2c.c  I get confused as it seems to somehow fiddle with start/stop to get it right because of the -m switch, but uses read() in the end to get the data, not I2CREAD.

        fd = open(dev, O_RDWR);
        if (i2c_opt.width) {
                error = ioctl(fd, I2CSTART, &cmd);
                error = ioctl(fd, I2CWRITE, &cmd);
                if (i2c_opt.mode == I2C_MODE_STOP_START) {
                        error = ioctl(fd, I2CSTOP, &cmd);
                }
        }
        if (i2c_opt.mode == I2C_MODE_STOP_START) {
                error = ioctl(fd, I2CSTART, &cmd);
        } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
                error = ioctl(fd, I2CRPTSTART, &cmd);
        }
/******** Without i2c_opt.width set there is no START condition either to set the slave address for the read() ****/
/******** Why this stop? ***/
        error = ioctl(fd, I2CSTOP, &cmd);
        for (i = 0; i < i2c_opt.count; i++) {
                error = read(fd, &i2c_buf[i], 1);
        }
        close(fd);

I would have expected:

        fd = open(dev, O_RDWR);
        if (i2c_opt.width) {
                error = ioctl(fd, I2CSTART, &cmd);
                error = ioctl(fd, I2CWRITE, &cmd);
                if (i2c_opt.mode == I2C_MODE_STOP_START) {
                        error = ioctl(fd, I2CSTOP, &cmd);
                error = ioctl(fd, I2CSTART, &cmd);
        } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
                error = ioctl(fd, I2CRPTSTART, &cmd);
                }
        } else {
/***** Use START/STOP to set the slave address for the read() below ***/
                error = ioctl(fd, I2CSTART, &cmd);
        error = ioctl(fd, I2CSTOP, &cmd);
        }
        error = ioctl(fd, I2CREAD, &cmd); // read all bytes in one go
        error = ioctl(fd, I2CSTOP, &cmd);
        close(fd);

Any opinions on where I am wrong?


Second question:

Rolling my own little program with this change fails because I cannot get I2CREAD to work. It keeps returning EIO. Some other web pages claim that there is an implementation problem with that. Using read() on the fd works fine, so do get a valid temperature out of the device now.


Cheers,

Nick Hibma
--
ip-knowhow
E: nick at ip-knowhow.com<mailto:nick at ip-knowhow.com>
T: +31 (0)85 2010923
M: +31 (0)6 14433161


More information about the freebsd-embedded mailing list