zoukankan      html  css  js  c++  java
  • Linux I2C驱动--用户态驱动简单示例

    1. Linux内核支持I2C通用设备驱动(用户态驱动:由应用层实现对硬件的控制可以称之为用户态驱动),实现文件位于drivers/i2c/i2c-dev.c,设备文件为/dev/i2c-0

    2. I2C通用设备驱动以字符设备注册进内核的

    static const struct file_operations i2cdev_fops = {
        .owner        = THIS_MODULE,
        .llseek        = no_llseek,
        .read        = i2cdev_read,
        .write        = i2cdev_write,
        .unlocked_ioctl    = i2cdev_ioctl,
        .open        = i2cdev_open,
        .release    = i2cdev_release,
    };
    
    res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);

    3. 对设备文件进行读写时,可以调用read、write或者ioctl等方法,他们都是通过调用函数i2c_transfer来实现对I2C设备的操作的

    int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
    {
        int ret;
    
        /* REVISIT the fault reporting model here is weak:
         *
         *  - When we get an error after receiving N bytes from a slave,
         *    there is no way to report "N".
         *
         *  - When we get a NAK after transmitting N bytes to a slave,
         *    there is no way to report "N" ... or to let the master
         *    continue executing the rest of this combined message, if
         *    that's the appropriate response.
         *
         *  - When for example "num" is two and we successfully complete
         *    the first message but get an error part way through the
         *    second, it's unclear whether that should be reported as
         *    one (discarding status on the second message) or errno
         *    (discarding status on the first one).
         */
    
        if (adap->algo->master_xfer) {
    #ifdef DEBUG
            for (ret = 0; ret < num; ret++) {
                dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
                    "len=%d%s
    ", ret, (msgs[ret].flags & I2C_M_RD)
                    ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
                    (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
            }
    #endif
    
            if (in_atomic() || irqs_disabled()) {
                ret = mutex_trylock(&adap->bus_lock);
                if (!ret)
                    /* I2C activity is ongoing. */
                    return -EAGAIN;
            } else {
                mutex_lock_nested(&adap->bus_lock, adap->level);
            }
    
            ret = adap->algo->master_xfer(adap,msgs,num);
            mutex_unlock(&adap->bus_lock);
    
            return ret;
        } else {
            dev_dbg(&adap->dev, "I2C level transfers not supported
    ");
            return -EOPNOTSUPP;
        }
    }

    4. i2c_transfer通过代码可以看出,i2c_transfer 通过调用相应的 adapter 的 master_xfer 方法实现的,而 master_xfer 主要是根据 struct i2c_msg 类型的msgs来进行处理的。

    struct i2c_msg {
        __u16 addr;    /* slave address            */
        __u16 flags;
    #define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
    #define I2C_M_RD        0x0001    /* read data, from slave to master */
    #define I2C_M_NOSTART        0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_REV_DIR_ADDR    0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_NO_RD_ACK        0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
        __u16 len;        /* msg length                */
        __u8 *buf;        /* pointer to msg data            */
    };

    5. I2C用户态驱动简单示例

    (1)通过read、write实现对I2C设备的操作

    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <malloc.h>
    #include <sys/ioctl.h>
    #include <string.h>
    #include <linux/i2c.h>
    #include <linux/i2c-dev.h>
    
    #define SLAVE_ADDRESS 0x50
    #define I2C_WRITE_FLAG 0x00
    #define I2C_READ_FLAG 0x01
    
    #define USAGE "xxx -r address length
    xxx -w address data1 data2...
    "
    
    void i2c_write_bytes(int fd, unsigned char address, unsigned char* data, unsigned short len)
    {    
        unsigned char* write_data = malloc(len + 1);
        
        write_data[0] = address;
        memcpy(&write_data[1], data, len);
        
        ioctl(fd, I2C_SLAVE, SLAVE_ADDRESS);
        ioctl(fd, I2C_TIMEOUT, 1);
        ioctl(fd, I2C_RETRIES, 1);
        
        write(fd, write_data, len + 1);
        
        printf("Write data success
    ");
        
        if(write_data != NULL)
        {
            free(write_data);
            write_data = NULL;
        }
    }
    
    void i2c_read_bytes(int fd, unsigned char address, unsigned char* buf, unsigned short len)
    {    
        ioctl(fd, I2C_SLAVE, SLAVE_ADDRESS);
        ioctl(fd, I2C_TIMEOUT, 1);
        ioctl(fd, I2C_RETRIES, 1);
        
        write(fd, &address, 1);
        
        read(fd, buf, len);
        
        printf("buf[0] = 0x%x
    ", buf[0]);
        
        printf("Read data success
    ");
    }
    
    int main(int argc, char* argv[])
    {
        int opt;
        int fd = -1;
        
        unsigned char address;
        unsigned short len = 0, i = 0;
        unsigned char buf[256] = {0};
        
        // Open device file
        fd = open("/dev/i2c-0", O_RDWR);
        if(fd < 0)
        {
            printf("Open file error
    ");
            goto Exit;
        }    
            
        while((opt = getopt(argc, argv, "w:r:")) != -1)
        {
            switch(opt)
            {
                case 'w':
                    printf("optarg = %s
    ", optarg);
                    printf("optind = %d
    ", optind);
                    printf("argc = %d
    ", argc);
                    printf("argv[optind] = %s
    ", argv[optind]);
                    
                    address = (unsigned char)strtol(optarg, NULL, 0);
                    printf("address = %x
    ", address);
        
                    for(len = 0; optind < argc; optind++, len++)
                    {
                        buf[len] = (unsigned char)strtol(argv[optind], NULL, 0);
                    }
                    
                    printf("len = %x
    ", len);
                    
                    i2c_write_bytes(fd, address, buf, len);
                    
                    break;
                    
                case 'r':
                    printf("optarg = %s
    ", optarg);
                    printf("optind = %d
    ", optind);
                    printf("argv[optind] = %s
    ", argv[optind]);
                    
                    address = (unsigned char)strtol(optarg, NULL, 0);
                    printf("address = 0x%x
    ", address);
                    
                    len = (unsigned short)strtol(argv[optind], NULL, 0);
                    printf("len = 0x%x
    ", len);
                                
                    i2c_read_bytes(fd, address, buf, len);
                    
                    printf("Read content:
    ");
                    for(i = 0; i < len; i++)
                    {
                        printf("0x%x ", buf[i]);
                    }
                    printf("
    ");
                    break;
                
                default:
                    printf("Invalid parameter
    ");
                    printf(USAGE);
                    break;
            }
        }
    
    Exit:
        close(fd);
        
        return 0;
    }

    (2)通过ioctl实现对I2C设备的操作

    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <malloc.h>
    #include <sys/ioctl.h>
    #include <string.h>
    #include <linux/i2c.h>
    #include <linux/i2c-dev.h>
    
    #define SLAVE_ADDRESS 0x50
    #define I2C_WRITE_FLAG 0x00
    #define I2C_READ_FLAG 0x01
    
    #define USAGE "xxx -r address length
    xxx -w address data1 data2...
    "
    
    void i2c_write_bytes(int fd, unsigned char address, unsigned char* data, unsigned short len)
    {    
        struct i2c_rdwr_ioctl_data e2prom_write_data;
        
        e2prom_write_data.nmsgs = 1;
        e2prom_write_data.msgs = malloc(sizeof(struct i2c_msg) * e2prom_write_data.nmsgs);
        
        e2prom_write_data.msgs[0].addr = SLAVE_ADDRESS;
        e2prom_write_data.msgs[0].flags = I2C_WRITE_FLAG;
        e2prom_write_data.msgs[0].len = len + 1;//address data
        e2prom_write_data.msgs[0].buf = malloc(e2prom_write_data.msgs[0].len);
        
        e2prom_write_data.msgs[0].buf[0] = address;
        
        memcpy(&(e2prom_write_data.msgs[0].buf[1]), data, (size_t)len);
        
        // Using ioctl to write data
        ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_write_data);
        
        printf("Write data success
    ");
        
        if(e2prom_write_data.msgs != NULL)
        {
            free(e2prom_write_data.msgs);
            e2prom_write_data.msgs = NULL;
        }
    }
    
    void i2c_read_bytes(int fd, unsigned char address, unsigned char* buf, unsigned short len)
    {        
        struct i2c_rdwr_ioctl_data e2prom_read_data;
        
        e2prom_read_data.nmsgs = 2;//Need writing address first, then reading
        e2prom_read_data.msgs = malloc(sizeof(struct i2c_msg) * e2prom_read_data.nmsgs);
        
        e2prom_read_data.msgs[0].addr = SLAVE_ADDRESS;
        e2prom_read_data.msgs[0].flags = I2C_WRITE_FLAG;
        e2prom_read_data.msgs[0].len = 1;
        e2prom_read_data.msgs[0].buf = malloc(e2prom_read_data.msgs[0].len);
        
        e2prom_read_data.msgs[0].buf[0] = address;
        
        e2prom_read_data.msgs[1].addr = SLAVE_ADDRESS;
        e2prom_read_data.msgs[1].flags = I2C_READ_FLAG;
        e2prom_read_data.msgs[1].len = len;
        e2prom_read_data.msgs[1].buf = malloc(e2prom_read_data.msgs[0].len);
        e2prom_read_data.msgs[1].buf[0] = 0x00;
        
        // Using ioctl to read data
        ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_read_data);
        
        printf("e2prom_read_data.msgs[1].buf[0] = 0x%x
    ", e2prom_read_data.msgs[1].buf[0]);
        
        memcpy((void*)buf, (void*)(e2prom_read_data.msgs[1].buf), (unsigned int)len);
        
        if(e2prom_read_data.msgs != NULL)
        {
            free(e2prom_read_data.msgs);
            e2prom_read_data.msgs = NULL;
        }
    }
    
    int main(int argc, char* argv[])
    {
        int opt;
        int fd = -1;
        
        unsigned char address;
        unsigned short len = 0, i = 0;
        unsigned char buf[256] = {0};
        
        // Open device file
        fd = open("/dev/i2c-0", O_RDWR);
        if(fd < 0)
        {
            printf("Open file error
    ");
            goto Exit;
        }    
            
        while((opt = getopt(argc, argv, "w:r:")) != -1)
        {
            switch(opt)
            {
                case 'w':
                    printf("optarg = %s
    ", optarg);
                    printf("optind = %d
    ", optind);
                    printf("argc = %d
    ", argc);
                    printf("argv[optind] = %s
    ", argv[optind]);
                    
                    address = (unsigned char)strtol(optarg, NULL, 0);
                    printf("address = %x
    ", address);
                    
                    for(len = 0; optind < argc; optind++,len++)
                    {
                        buf[len] = (unsigned char)strtol(argv[optind], NULL, 0);
                    }
                    
                    printf("len = %x
    ", len);
                    
                    i2c_write_bytes(fd, address, buf, len);
                    
                    break;
                    
                case 'r':
                    printf("optarg = %s
    ", optarg);
                    printf("optind = %d
    ", optind);
                    printf("argv[optind] = %s
    ", argv[optind]);
                    
                    address = (unsigned char)strtol(optarg, NULL, 0);
                    printf("address = 0x%x
    ", address);
                    
                    len = (unsigned short)strtol(argv[optind], NULL, 0);
                    printf("len = 0x%x
    ", len);
                                
                    i2c_read_bytes(fd, address, buf, len);
                    
                    printf("Read content:
    ");
                    for(i = 0; i < len; i++)
                    {
                        printf("0x%x ", buf[i]);
                    }
                    printf("
    ");
                    break;
                
                default:
                    printf("Invalid parameter
    ");
                    printf(USAGE);
                    break;
            }
        }
    
    Exit:
        close(fd);
        
        return 0;
    }
  • 相关阅读:
    庞果网 字符串消除
    剪格子
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 柒
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 柒
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 柒
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 柒
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆
    [转译][马基 杰斯特(MarkeyJester) 摩托罗拉68000 入门教程] 陆
  • 原文地址:https://www.cnblogs.com/wulei0630/p/9607606.html
Copyright © 2011-2022 走看看