Questions about i2c.c (TMP102 temperature sensor)

Emmanuel Vadot manu at bidouilliste.com
Mon Dec 5 08:56:00 UTC 2016


On Fri, 2 Dec 2016 13:11:34 -0800
Oleksandr Tymoshenko <gonzo at bluezbox.com> wrote:

> 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
> _______________________________________________
> freebsd-arm at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-arm
> To unsubscribe, send any mail to "freebsd-arm-unsubscribe at freebsd.org"

 I have an updated version of i2c(8) which support I2CRDWR here :
https://github.com/evadot/freebsd/tree/i2c_rdrw/usr.sbin/i2c

 I didn't commit it just because I want to make I2CRDWR the default
since there is iicbus_transfer_gen. I just need to make sure that it
works almost everwhere (it does on allwinner board where the driver
doesn't support I2CRDWR at least).

 Can you test using i2c(8) from my branch with your device ?

-- 
Emmanuel Vadot <manu at bidouilliste.com> <manu at freebsd.org>


More information about the freebsd-arm mailing list