i2c on RPI-B not working

Bernd Walter ticso at cicely7.cicely.de
Thu May 1 13:53:13 UTC 2014


On Wed, Apr 30, 2014 at 06:13:08PM -0600, Ian Lepore wrote:
> On Wed, 2014-04-30 at 19:49 -0400, Winston Smith wrote:
> > On Tue, Apr 29, 2014 at 1:07 PM, Rui Paulo <rpaulo at freebsd.org> wrote:
> > > This is because the controller doesn't support scanning.  You need to write your own C program to issue iic ioctls for reading / writing to the i2c bus.
> > 
> > I'm in the same process except on a BeagleBone Black (currently
> > running 11-CURRENT).  Running `i2c -sv` under `ktrace -t+`, it's
> > returning:
> > 
> >    956 i2c      CALL  ioctl(0x3,I2CRSTCARD,0xbffffcc8)
> >    956 i2c      RET   ioctl 0
> >    956 i2c      CALL  ioctl(0x3,I2CSTART,0xbffffcc8)
> >    956 i2c      RET   ioctl -1 errno 6 Device not configured
> >    956 i2c      CALL  ioctl(0x3,I2CSTOP,0xbffffcc8)
> >    956 i2c      RET   ioctl -1 errno 22 Invalid argument
> > 
> > 
> > I know from Linux on the BBB, that when you run `i2cdetect`, you need
> > to specify the `-r` to use "read byte" commands to probe the i2c bus
> > and indeed I've written i2c code previously using ioctl() with
> > I2CRDWR.
> > 
> > So I cobbled together a I2C bus scanner, i2cscan.c:
> > http://pastebin.com/RxpRCyJU
> > 
> > root at beaglebone:~ # ./i2cscan /dev/iic0
> > Checking device: /dev/iic0
> >      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
> > 00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
> > 
> > 
> > Hmmm ... on the BBB it's still not detecting anything; in fact
> > according to `ktrace`, it seems to still return ENXIO (Device not
> > configured):
> > 
> >    988 i2cscan  CALL  ioctl(0x3,I2CRDWR,0xbffffc58)
> >    988 i2cscan  RET   ioctl -1 errno 6 Device not configured
> > 
> > 
> > Not entirely sure why it's not detecting anything since I *know* the
> > BBB has an EEPROM at 0x50 on bus 0 (I2C0 @ 44e0b000), which according
> > to ofwdump should be iic0:
> > 
> > root at beaglebone:~ # ofwdump -a
> > Node 0x38:
> >   Node 0xc4: am335x
> >     ...
> >     Node 0x1504: i2c at 44e0b000
> >       Node 0x1590: pmic at 24
> >     ...
> > 
> > So:
> > 
> > 1) Hopefully, you'll have more luck with the i2cscan.c tool I wrote than I did!
> > 2) Does anyone know why I'm not detecting any i2c devices on the BBB?
> > 
> > Thanks!
> > 
> > -W
> 
> I saw it mentioned on irc the other day that i2c(8) isn't very
> functional on most of our ARM systems.  It's expecting a different
> interface to the i2c hardware in which it sees all the low-level
> protocol events.  Most modern hardware has more of a "do this whole
> transaction for me" type interface.  We probably need to enhance i2c(8)
> to work (as much as it can) in such a mode.

Warner already changed the /dev/iic interface years ago.
Don't know about i2c(8) however.
For example I access a DS1672 attached to my RM9200 board from userland with:

int
main(int argc, char *argv[]) {
        int i, error;
        struct iic_rdwr_data cmd;
        struct iic_msg msg[2];
        char buf1[16];
        char buf2[16];

        if (argc == 3 && strcmp(argv[1], "-r") == 0) {
                int bus = open(argv[2], O_RDWR | O_EXCL);
                if (bus < 0) {
                        printf("opening I2C bus device %s failed\n", argv[1]);
                        exit(1);
                }
                cmd.nmsgs = 2;
                cmd.msgs = msg;
                buf1[0] = 0x00;
                msg[0].slave = 0xd0;
                msg[0].flags = IIC_M_WR;
                msg[0].len = 1;
                msg[0].buf = buf1;
                msg[1].slave = 0xd0;
                msg[1].flags = IIC_M_RD;
                msg[1].len = 6;
                msg[1].buf = buf2;
                error = ioctl(bus, I2CRDWR, &cmd);
                if (error) {
                        printf("device %i error %i\n", i, errno);
                }
                uint32_t time = buf2[0] | buf2[1] << 8 | buf2[2] << 16 | buf2[3] << 24;
                printf ("RTC time = %i\n", time);
                printf ("RTC control = %i\n", buf2[4]);
                printf ("RTC charger = %i\n", buf2[5]);
                //printf ("%i %i %i %i %i %i\n", buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5]);
                return (0);
...

This is doing a read of previously written register address in one go.
However the TWI controller Atmel use on ARMs has no support for empty
writes used in write probing - this would have to be done bit banging.
Empty reads are technically not possible with IIC.
So the only thing you can do beside bit banging is doing real reads.
IIC is not really designed for probing anyway - you better know what
to address in advance.

-- 
B.Walter <bernd at bwct.de> http://www.bwct.de
Modbus/TCP Ethernet I/O Baugruppen, ARM basierte FreeBSD Rechner uvm.


More information about the freebsd-arm mailing list