Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 Dec 2016 10:11:04 +0000
From:      Nick Hibma <Nick@ip-knowhow.com>
To:        =?Windows-1252?Q?=93FreeBSD_Embedded_Mailing_List=94?= <freebsd-embedded@FreeBSD.org>
Subject:   Questions about i2c.c (TMP102 temperature sensor)
Message-ID:  <9424D7FD-C4B6-43D5-A0C5-76D5BE9ED1DE@ip-knowhow.com>

next in thread | raw e-mail | index | archive | help
Gents,

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

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

The device expects continuous reads and no stop/start in between the 2 byte=
s. 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 s=
eems to somehow fiddle with start/stop to get it right because of the -m sw=
itch, but uses read() in the end to get the data, not I2CREAD.

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

I would have expected:

        fd =3D open(dev, O_RDWR);
        if (i2c_opt.width) {
                error =3D ioctl(fd, I2CSTART, &cmd);
                error =3D ioctl(fd, I2CWRITE, &cmd);
                if (i2c_opt.mode =3D=3D I2C_MODE_STOP_START) {
                        error =3D ioctl(fd, I2CSTOP, &cmd);
                error =3D ioctl(fd, I2CSTART, &cmd);
        } else if (i2c_opt.mode =3D=3D I2C_MODE_REPEATED_START) {
                error =3D ioctl(fd, I2CRPTSTART, &cmd);
                }
        } else {
/***** Use START/STOP to set the slave address for the read() below ***/
                error =3D ioctl(fd, I2CSTART, &cmd);
        error =3D ioctl(fd, I2CSTOP, &cmd);
        }
        error =3D ioctl(fd, I2CREAD, &cmd); // read all bytes in one go
        error =3D 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 I=
2CREAD to work. It keeps returning EIO. Some other web pages claim that the=
re is an implementation problem with that. Using read() on the fd works fin=
e, so do get a valid temperature out of the device now.


Cheers,

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9424D7FD-C4B6-43D5-A0C5-76D5BE9ED1DE>