Questions about i2c.c (TMP102 temperature sensor)

Oleksandr Tymoshenko gonzo at bluezbox.com
Fri Dec 2 21:12:12 UTC 2016


Switching freebsd-embedded@ to freebsd-arm@ since the former does not get as much attention as the latter.

> On Dec 1, 2016, at 2:11 AM, Nick Hibma <Nick at ip-knowhow.com> wrote:
> 
> 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?

There is no need for I2CSTART/I2CSTOP sequence, there is I2CSADDR
ioctl for that purpose. I agree that i2c tool looks broken from quick
glance, but someone with more knowledge should take a look.

> 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.


I picked up TMP102 as a device to test I2C drivers for new boards and
wrote C application to talk to it. I used RPi as a reference
platform. The problem with I2C driver on RPi is that it does not
support sending explicit START/STOP conditions. So all ioctl(I2CSTART)
and ioctl(I2CSTOP). And READ/WRITE does not work without explicit
START. So I ended up working around it using I2CRDWR. For some
other boards it probably can be written with START/WRITE/READ/STOP,
or with read/write. I’m going to spend some time and get this app
working on all boards I have to get a general feeling of what bits of
I2C are supported on them what are not. 

Source code: https://people.freebsd.org/~gonzo/tmp102.c


More information about the freebsd-arm mailing list