python i2c ioctl

Tim Roberts timr at probo.com
Fri Jun 15 08:39:39 CEST 2007


luca <sanluca78 at gmail.com> wrote:
>
> I was trying to make to work directly l i2c with python with the
>calls ioctl. But I have of the problems and I do not succeed to go
>ahead.
>
>[root at axis-00408c000001 /usr/local/wrap]129# python pcf8591_ioctl.py
>Reading from 4 ch 8 bit A/D converter PCF8591
>Traceback (most recent call last):
>  File "pcf8591_ioctl.py", line 269, in ?
>    main()
>  File "pcf8591_ioctl.py", line 229, in main
>    if i2c_open () < 0:
>  File "pcf8591_ioctl.py", line 168, in i2c_open
>    fcntl.ioctl(i2c_fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_OUTPUT), 0,
>iomask)
>TypeError: ioctl requires a file or file descriptor, an integer and
>optionally a integer or buffer argument

The error message pretty much tells you the problem.  One of the parameters
is not correct.  Notice this:

>def IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask):
>	( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) &
>0xFF) )
>def IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask):
>	( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) &
>0xFF) )

Key question: what do these functions return?

Answer: nothing.  You compute a value and then throw it away.  Thus:
    print IO_CFG_WRITE_MODE_VALUE( 15, 0xfff, 0x0f0 )
This will print "None".  Add a "return" before the expression.

The same thing is true of all of these functions.  You are thinking that a
Python "def" is like a C "#define".  It's not.  It's like a C function.
Nothing is returned unless you return it.

>def _IOC(dir,type,nr,size):
>	(((dir)  << _IOC_DIRSHIFT) |
>	((type) << _IOC_TYPESHIFT) |
>	((nr)   << _IOC_NRSHIFT) |
>	((size) << _IOC_SIZESHIFT))
>
>def _IO(type,nr):
>	_IOC(_IOC_NONE,(type),(nr),0)
>
>def _IOR(type,nr,size):
>	_IOC(_IOC_READ,(type),(nr),sizeof(size))
>
>def _IOW(type,nr,size):
>	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
>
>def _IOWR(type,nr,size):
>	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
>
>def _IOC_DIR(nr):
>	(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
>def _IOC_TYPE(nr):
>	(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
>def _IOC_NR(nr):
>	(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
>def _IOC_SIZE(nr):
>	(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
>def IOC_IN():
>	(_IOC_WRITE << _IOC_DIRSHIFT)
>
>def IOC_OUT():
>	(_IOC_READ << _IOC_DIRSHIFT)
>def IOC_INOUT():
>	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
>def IOCSIZE_MASK():
>	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
>def IOCSIZE_SHIFT():
>	(_IOC_SIZESHIFT)

However, there are more problems with this script.  Example:

>#Get the SDA line state
>def i2c_getbit():
>	value=fcntl.ioctl(i2c_fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS))
>	if ((value&(I2C_DATA_LINE))==0):
>		return 0
>	else:
>		return 1

This will produce a runtime error, because the name "i2c_fd" is not
defined.  Notice this:

>#Open the GPIOB dev
>def i2c_open():
>	i2c_fd = os.open("/dev/gpiog", os.O_RDWR)
>	iomask = I2C_CLOCK_LINE
>	fcntl.ioctl(i2c_fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_OUTPUT), iomask)
>	iomask = I2C_DATA_LINE
>	fcntl.ioctl(i2c_fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_INPUT), iomask)
>	fcntl.ioctl(i2c_fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS),
>I2C_DATA_LINE)
>	i2c_dir_in()
>	i2c_clk(1)
>	return i2c_fd

The result of the open is bound in a LOCAL variable called "i2c_fd".  As
soon as the function returns, that variable goes away.  You do RETURN the
value, but you don't store it anywhere:

>#PCF8591 address scheme
>#|  1 |  0 |  0 |  1 | A2 | A1 | A0 | R/W |
>#| i2c_fixed         | i2c_addr     | 1/0 |
>def main ():
>        i2c_fixed = 0x09
>        i2c_addr  = 0x01
>
>        print "Reading from 4 ch 8 bit A/D converter PCF8591"
>
>        if i2c_open () < 0:
>                print "i2c open error"
>                return 1

You should probably make this:

        i2c_fd = i2c_open()
        if i2c_fd < 0:
            print "i2c open error"
            return 1

But, of course, that's not enough either; i2c_fd is a local variable in
THIS function as well.  You should change ALL of the functions so that they
accept an fd as the first parameter, and then pass i2c_fd into the
functions here.

Alternatively, you could create a wrapper class to hold the fd and make the
function methods on that class.

>        while "azz":
>                i2c_start ()

I'm curious.  What do you think "while" statement is doing?  The answer is
that it is an infinite loop; the string "azz" will always be true, so the
while statement will always loop.  I can't guess what you really wanted
here.
-- 
Tim Roberts, timr at probo.com
Providenza & Boekelheide, Inc.



More information about the Python-list mailing list