Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 Dec 2016 13:11:34 -0800
From:      Oleksandr Tymoshenko <gonzo@bluezbox.com>
To:        Nick Hibma <Nick@ip-knowhow.com>
Cc:        freebsd-arm@freebsd.org
Subject:   Re: Questions about i2c.c (TMP102 temperature sensor)
Message-ID:  <58B43D61-0B46-4310-868F-D7336585731B@bluezbox.com>
In-Reply-To: <9424D7FD-C4B6-43D5-A0C5-76D5BE9ED1DE@ip-knowhow.com>
References:  <9424D7FD-C4B6-43D5-A0C5-76D5BE9ED1DE@ip-knowhow.com>

next in thread | previous in thread | raw e-mail | index | archive | help
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@ip-knowhow.com> wrote:
>=20
> Gents,
>=20
> I am not quite sure who to owner of i2c.c is, so perhaps some I2C =
enthousiast could help me with the following problem.
>=20
> 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.
>=20
> 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.
>=20
>        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 set 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);
>=20
> I would have expected:
>=20
>        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);
>=20
> 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:
>=20
> 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=E2=80=99m 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.=20

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?58B43D61-0B46-4310-868F-D7336585731B>