美文网首页
五 . 树莓派A20 I2C驱动程序

五 . 树莓派A20 I2C驱动程序

作者: wit_yuan | 来源:发表于2017-07-18 15:27 被阅读0次

    1 参考资料

    1.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\input\touchscreen\Gt818_ts.c
    2.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c
    3.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\include\linux\I2c.h
    4.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-dev.c提供应用层接口
    5.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c提供核心层文件
    6.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\busses\I2c-sunxi.c提供底层硬件驱动

    1.1 I2C框架总图

    I2C框架总图

    2 I2C接口

    2.1 函数接口

    /*注册驱动*/
    #define i2c_add_driver(driver) \
        i2c_register_driver(THIS_MODULE, driver)
    /*注销驱动*/
    void i2c_del_driver(struct i2c_driver *driver)
    /*承载实际的数据传输*/
    int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
    

    2.2 结构体

    struct i2c_board_info {
        char        type[I2C_NAME_SIZE];
        unsigned short  flags;
        unsigned short  addr;
        void        *platform_data;
        struct dev_archdata *archdata;
        struct device_node *of_node;
        int     irq;
    };
    
    struct i2c_client {
        unsigned short flags;       /* div., see below      */
        unsigned short addr;        /* chip address - NOTE: 7bit    */
                        /* addresses are stored in the  */
                        /* _LOWER_ 7 bits       */
        char name[I2C_NAME_SIZE];
        struct i2c_adapter *adapter;    /* the adapter we sit on    */
        struct i2c_driver *driver;  /* and our access routines  */
        struct device dev;      /* the device structure     */
        int irq;            /* irq issued by device     */
        struct list_head detected;
    };
    
    struct i2c_driver {
        unsigned int class;
    
        /* Notifies the driver that a new bus has appeared or is about to be
         * removed. You should avoid using this, it will be removed in a
         * near future.
         */
        int (*attach_adapter)(struct i2c_adapter *) __deprecated;
        int (*detach_adapter)(struct i2c_adapter *) __deprecated;
    
        /* Standard driver model interfaces */
        int (*probe)(struct i2c_client *, const struct i2c_device_id *);
        int (*remove)(struct i2c_client *);
    
        /* driver model interfaces that don't relate to enumeration  */
        void (*shutdown)(struct i2c_client *);
        int (*suspend)(struct i2c_client *, pm_message_t mesg);
        int (*resume)(struct i2c_client *);
    
        /* Alert callback, for example for the SMBus alert protocol.
         * The format and meaning of the data value depends on the protocol.
         * For the SMBus alert protocol, there is a single bit of data passed
         * as the alert response's low bit ("event flag").
         */
        void (*alert)(struct i2c_client *, unsigned int data);
    
        /* a ioctl like command that can be used to perform specific functions
         * with the device.
         */
        int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
    
        struct device_driver driver;
        const struct i2c_device_id *id_table;
    
        /* Device detection callback for automatic device creation */
        int (*detect)(struct i2c_client *, struct i2c_board_info *);
        const unsigned short *address_list;
        struct list_head clients;
    };
    
    struct i2c_device_id {
        char name[I2C_NAME_SIZE];
        kernel_ulong_t driver_data  /* Data private to the driver */
                __attribute__((aligned(sizeof(kernel_ulong_t))));
    };
    

    3 硬件原理图

    使用风火轮出品的DVK521底板,其I2C硬件原理图如下所示:


    I2C接口

    找到数据手册中对应引脚描述:


    I2C引脚描述

    从这里可以看出,使用的是i2c1接口。

    我在i2c1上外接的是FM24CL16芯片,该芯片容量为2KB。从机地址按照下图所示:


    image.png

    该模组链接地址为: 链接
    原理图链接地址为: 链接

    也就是如下图所示:

    I2C模组图 原理图

    按照上图,我们将短接帽设置在0上,也就是接地。那么,访问该芯片的地址就为0x50。

    这里就直接给出一个测试例程:

    #include <stdio.h>  
    #include <stdlib.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <fcntl.h>  
    #include <string.h>  
    #include <linux/i2c.h>  
    #include <linux/i2c-dev.h>   
    
    #define SLAVE_ADDRESS 0x50 //FM24CL16芯片地址为0x50
    #define I2C_DEV "/dev/i2c-1"//i2c_dev为i2c adapter创建的别名  
    //读操作先发Slaveaddr_W+Regaddr_H+Regaddr_L 3个字节来告诉设备操作器件及两个byte参数  
    //然后发送Slaveaddr_R读数据  
    static int iic_read(int fd, char buff[], int addr, int count)  
    {  
        int res;  
        char sendbuffer1[2];  
        //sendbuffer1[0]=addr>>8;  
        //sendbuffer1[1]=addr;  
        sendbuffer1[0]=addr;
    
        write(fd,sendbuffer1,1);        
        res=read(fd,buff,count);  
        //printf("read %d byte at 0x%x\n", res, addr);  
        return res;  
    } 
    
    //在写之前,在数据前加两个byte的参数,根据需要解析  
    static int iic_write(int fd, char buff[], int addr, int count)  
    {  
        int res;
        int i,n;
        char sendbuffer[2048+3];  
        memcpy(sendbuffer+1, buff, count);  
        sendbuffer[0]=addr;  
        res=write(fd,sendbuffer,count+1);  
        //printf("write %d byte at 0x%x\n", res, addr);  
    }  
    
    unsigned char wbuf1[2048];
    unsigned char wbuf2[2048];
    unsigned char wbuf3[2048];
    unsigned char wbuf4[2048];
    unsigned char wbuf5[2048];
    unsigned char wbuf6[2048];
    unsigned char wbuf7[2048];
    unsigned char wbuf8[2048];
    
    unsigned char rbuf[2048];
    
    int main(void){  
        int fd;  
        int res;  
        char ch;  
     
        char buf[50];  
        int regaddr,i,slaveaddr;  
        fd = open(I2C_DEV, O_RDWR);// I2C_DEV /dev/i2c-0  
        if(fd < 0){  
            printf("####i2c test device open failed####\n");  
            return -1;  
        }
    
        if(ioctl(fd,I2C_TENBIT,0)<0)
        {
            printf("---set i2c bit error---\r\n");
            return -1;
        }
    
        if(ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS)<0)
        {
            printf("--set i2c address error---\r\n");
            return -1;
        }
        
        /*write data as 512Bytes once*/
        for(i = 0 ; i < 256 ; i ++)
        {
            wbuf1[i] = i;   
            wbuf2[i] = 255-i;   
            wbuf3[i] = i%256;   
            wbuf4[i] = 255-i;   
            wbuf5[i] = i%256;   
            wbuf6[i] = 255-i;   
            wbuf7[i] = i%256;   
            wbuf8[i] = 255-i;   
        }
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+0); 
        iic_write(fd,wbuf1,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
        iic_write(fd,wbuf2,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
        iic_write(fd,wbuf3,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
        iic_write(fd,wbuf4,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
        iic_write(fd,wbuf5,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
        iic_write(fd,wbuf6,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
        iic_write(fd,wbuf7,0,256); 
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
        iic_write(fd,wbuf8,0,256); 
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS);
        iic_read(fd,rbuf,0,256); 
        printf("read page 0:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
        iic_read(fd,rbuf,0,256); 
        printf("read page 1:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
        iic_read(fd,rbuf,0,256); 
        printf("read page 2:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
        iic_read(fd,rbuf,0,256); 
        printf("read page 3:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
        iic_read(fd,rbuf,0,256); 
        printf("read page 4:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
        iic_read(fd,rbuf,0,256); 
        printf("read page 5:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
        iic_read(fd,rbuf,0,256); 
        printf("read page 6:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
        ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
        iic_read(fd,rbuf,0,256); 
        printf("read page 7:\r\n");
        for(i = 0 ; i <256 ; i ++)
        {
            printf("0x%0x ",rbuf[i]);
        }
        printf("\r\n"); 
    
        return 0;  
    }  
    

    在程序编写上,需要着重注意的是访问的寄存器地址。由于我们的地址是8位的,所以,访问256B后面的数据,都是要两个以上的字节了,这个时候,我们就要用上内部的访问地址了。

    简单的讲,就是要变换page。

    4 通过I2C驱动ZLG7290前面板

    4.1 sys_config.fex文件的配置

    配置内容为:

    [twi4_para]
    twi4_used = 1
    twi4_scl = port:PI02<3><default><default><default>
    twi4_sda = port:PI03<3><default><default><default>
    
    twi4配置

    4.2 修改Kconfig和Makefile文件

    在linux-sunxi/drivers/input/misc/目录下,修改Kconfig内容:

    config INPUT_I2C7290
        tristate "I2C7290 Keyboard device"
        depends on I2C
        help
         Say Y here if you want to support a keypad connected via I2C
         with a ZLG7290(bad design by xxx).
         To compile this driver as a module, choose M here: the
         module will be called ZLG7290_keypad.
    

    然后修改该目录下的Makefile文件:

    obj-$(CONFIG_INPUT_I2C7290)     += keyboard_i2c7290.o
    

    然后:

    $ make menuconfig 
    
    选中I2C7290

    在linux-sunxi/drivers/input/misc/目录下,编写keyboard_i2c7290.c文件,内容如下:

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/interrupt.h>
    #include <linux/i2c.h>
    #include <linux/fs.h>
    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    #include <linux/uaccess.h>
    
    //#define KEYBOARD_I2C7290_DEBUG
    
    #ifdef KEYBOARD_I2C7290_DEBUG
    #define keyboard_i2c7290_debug(fmt, ...) printk(KERN_INFO "[KEYBOARD_I2C7290][BUG][%d]"fmt, __LINE__, ##__VA_ARGS__)
    #else
    #define keyboard_i2c7290_debug(fmt, ...)
    #endif /* KEYBOARD_I2C7290_DEBUG */
    
    #define keyboard_i2c7290_error(fmt, ...) printk(KERN_INFO "[KEYBOARD_I2C7290][ERR]"fmt"\n", ##__VA_ARGS__)
    
    #define DRV_NAME "keyboard_i2c7290"
    
    #define ZLG7290_SystemReg   0x00
    #define ZLG7290_Key         0x01
    #define ZLG7290_RepeatCnt   0x02
    #define ZLG7290_FunctionKey 0x03
    #define ZLG7290_CmdBuf      0x07
    #define ZLG7290_CmdBuf0     0x07
    #define ZLG7290_CmdBuf1     0x08
    #define ZLG7290_FlashOnOff  0x0C
    #define ZLG7290_ScanNum     0x0D
    #define ZLG7290_DpRam       0x10
    #define ZLG7290_DpRam0      0x10
    #define ZLG7290_DpRam1      0x11
    #define ZLG7290_DpRam2      0x12
    #define ZLG7290_DpRam3      0x13
    #define ZLG7290_DpRam4      0x14
    #define ZLG7290_DpRam5      0x15
    #define ZLG7290_DpRam6      0x16
    #define ZLG7290_DpRam7      0x17
    
    #define LED_ONOFF_CMD   0x01
    #define LED_ON_MASK     0x80
    #define LED_OFF_MASK        0x7F
    
    #define LED_ON_CMD_U16(led_id)  (((((u16)(led_id | LED_ON_MASK)) << 8) | LED_ONOFF_CMD))
    #define LED_OFF_CMD_U16(led_id) (((((u16)(led_id & LED_OFF_MASK)) << 8) | LED_ONOFF_CMD))
    
    #define LED_IOCTL_ON        0
    #define LED_IOCTL_OFF   1
    
    #define I2C_DELAY_MS        2
    
    struct UserKeyDataStru {
        unsigned int key_state : 8;     //按键状态[1:有键按下,0:没有按键按下(或功能键,此处不用)]
        unsigned int key : 8;           //按键键值
        unsigned int repeat : 8;        //连击计数器
        unsigned int reserved : 8;      //预留
    };
    
    struct KeyboardI2C7290DataStru {
        char *name;
        struct i2c_client *client;
        struct miscdevice misc;
    };
    
    //LED与按键的对应关系定义
    typedef struct LedAndKeyInfoStru {
        unsigned char key;
        unsigned char led_id;
    }LedAndKeyInfoStru_t;
    
    struct KeyboardI2C7290DataStru kb = {.name = DRV_NAME};
    
    const LedAndKeyInfoStru_t led_and_key[] = {
    //  {.key = 1, .led_id = 0},
    //  {.key = 2, .led_id = 8},
    //  {.key = 3, .led_id = 16},
    //  {.key = 4, .led_id = 24},
        {.key = 28, .led_id = 32},
        {.key = 27, .led_id = 40},
        {.key = 26, .led_id = 48},
        {.key = 25, .led_id = 56},
        {.key = 20, .led_id = 56},
        {.key = 19, .led_id = 4},
        {.key = 18, .led_id = 20},
        {.key = 5, .led_id = 24},
    };
    
    static int I2C_Gets(struct i2c_client *client, unsigned int SubAddr, char *dat)
    {
        i2c_smbus_write_byte(client, SubAddr);
    
        *dat = (char)(0xFF & i2c_smbus_read_byte(client));
    
        return 0;
    }
    
    static int read_system_reg(struct KeyboardI2C7290DataStru *kb)
    {
        char c = '\0';
    
        I2C_Gets(kb->client, ZLG7290_SystemReg, &c);
    
        return (int)(c & 0x01);
    }
    
    static int read_key(struct KeyboardI2C7290DataStru *kb)
    {
        char c = '\0';
    
        I2C_Gets(kb->client, ZLG7290_Key, &c);
    
        return (int)c;
    }
    
    static int read_repeat_reg(struct KeyboardI2C7290DataStru *kb)
    {
        char c = '\0';
    
        I2C_Gets(kb->client, ZLG7290_RepeatCnt, &c);
    
        return (int)c;
    }
    
    static void led_on(unsigned char key)
    {
        int i = 0;
        u16 value = 0;
    
        for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
            if (led_and_key[i].key == key) {
                value = LED_ON_CMD_U16(led_and_key[i].led_id);
                i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
                keyboard_i2c7290_debug("value = 0x%04X\n", value);
            }
        }
    }
    
    static void led_off(unsigned char key)
    {
        int i = 0;
        u16 value = 0;
    
        for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
            if (led_and_key[i].key == key) {
                value = LED_OFF_CMD_U16(led_and_key[i].led_id);
                i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
                keyboard_i2c7290_debug("value = 0x%04X\n", value);
            }
        }
    }
    
    static void led_off_all(void)
    {
        int i = 0;
        u16 value = 0;
    
        for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
            value = LED_OFF_CMD_U16(led_and_key[i].led_id);
            i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
        //  keyboard_i2c7290_debug("value = 0x%04X\n", value);
            mdelay(I2C_DELAY_MS);
        }
    }
    
    static int keyboard_i2c7290_open(struct inode *inode, struct file *file)
    {
        u16 value = 0;
    
        //关闭LED闪烁显示
        value = 0x0070;
        i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
        mdelay(I2C_DELAY_MS);
    
        led_off_all();
    
        return 0;
    }
    
    static int keyboard_i2c7290_close(struct inode *inode, struct file *file)
    {
        led_off_all();
    
        return 0;
    }
    
    static ssize_t keyboard_i2c7290_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
    {
        struct UserKeyDataStru user_data = {0};
    
        user_data.key_state = read_system_reg(&kb);
        if (user_data.key_state == 0) {
            //没有键按下
        } else {
            mdelay(I2C_DELAY_MS);
    
            user_data.key = (unsigned char)read_key(&kb);
            mdelay(I2C_DELAY_MS);
    
            user_data.repeat = read_repeat_reg(&kb);
        }
    #if 0
        keyboard_i2c7290_debug("SysReg:%d\n", user_data.key_state);
        keyboard_i2c7290_debug("KEY: %d\n", user_data.key);
        keyboard_i2c7290_debug("Repeat: %d\n", user_data.repeat);
    #endif
        if (copy_to_user(buf, (const void *)&user_data, sizeof(struct UserKeyDataStru)) == 0) {
            //Empty
        }
    
        return sizeof(struct UserKeyDataStru);
    }
    
    static long keyboard_i2c7290_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
        unsigned char key =  *((unsigned char *)arg);
    
        keyboard_i2c7290_debug("Cmd: %d, Key: %d\n", cmd, (unsigned int)key);
        switch (cmd) {
        case LED_IOCTL_ON:
            led_on(key);
            break;
        case LED_IOCTL_OFF:
            led_off(key);
            break;
        default:
            break;
        }
    
        return 0;
    }
    
    static const struct file_operations keyboard_i2c7290_fops = {
        .owner              = THIS_MODULE,
        .open               = keyboard_i2c7290_open,
        .release            = keyboard_i2c7290_close,
        .unlocked_ioctl     = keyboard_i2c7290_ioctl,
        .read      = keyboard_i2c7290_read,
    //  .write     = keyboard_i2c7290_write,
    };
    
    static int keyboard_i2c7290_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
        int ret = 0;
        struct miscdevice *misc = NULL;
        
        keyboard_i2c7290_debug("In %s\n", __FUNCTION__);
    
        keyboard_i2c7290_debug("Addr:0x%X, name:%s\n", client->addr, id->name);
    
        kb.client = client;
    
        misc = &kb.misc;
        misc->minor = MISC_DYNAMIC_MINOR;
        misc->name = DRV_NAME;
        misc->fops = &keyboard_i2c7290_fops;
        ret = misc_register(misc);
        if (ret) {
            keyboard_i2c7290_error("Unable to register a misc device\n");
    
            return -1;
        }
        keyboard_i2c7290_debug("Register a misc device Ok\n");
    
    
        return ret;
    }
    
    static int keyboard_i2c7290_remove(struct i2c_client *client)
    {
        struct miscdevice *misc = NULL;
    
        keyboard_i2c7290_debug("In %s\n", __FUNCTION__);
    
        misc = i2c_get_clientdata(client);
    
        free_irq(client->irq, misc);
        misc_deregister(misc);
    
    
        return 0;
    }
    
    static const struct i2c_device_id keyboard_i2c7290_id[] = {
        {DRV_NAME, 0},
        { },
    };
    
    MODULE_DEVICE_TABLE(i2c, keyboard_i2c7290_id);
    
    static struct i2c_driver keyboard_i2c7290_driver = {
        .driver = {
            .name   = DRV_NAME,
            .owner  = THIS_MODULE,
        },
        .probe      = keyboard_i2c7290_probe,
        .remove     = keyboard_i2c7290_remove,
        .id_table   = keyboard_i2c7290_id,
    };
    
    /*added by wit_yuan 2017-08-11*/
    static struct i2c_board_info __initdata bfin_i2c_board_info4[] = {
    #if defined(CONFIG_INPUT_I2C7290)
        {
            I2C_BOARD_INFO("keyboard_i2c7290", 0x38),
        //  .irq = IRQ_PE15,
        },
    #endif
    };
    
    
    static int __init keyboard_i2c7290_init(void)
    {
        printk("------keyboard_i2c7290_init----\r\n");
        i2c_register_board_info(4, bfin_i2c_board_info4, ARRAY_SIZE(bfin_i2c_board_info4));
        return 0;
    }
    
    static void __exit keyboard_i2c7290_exit(void)
    {
    
        return ;
    }
    
    
    module_init(keyboard_i2c7290_init);
    module_exit(keyboard_i2c7290_exit);
    
    
    
    module_i2c_driver(keyboard_i2c7290_driver);
    
    MODULE_AUTHOR("peace <whb_xxx@sina.com>");
    MODULE_DESCRIPTION("Keyboard driver for I2c7290");
    MODULE_LICENSE("GPL");
    

    在树莓派A20上查看是否有keyboard_i2c7290设备:

    root@marsboard:~# ls /dev/keyboard_i2c7290
    /dev/keyboard_i2c7290
    

    到这一步,就可以写测试程序keyTest.c:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <time.h>
    #include <sys/time.h>
    
    #define KEY_DEV "/dev/keyboard_i2c7290"
    
    struct UserKeyDataStru {
        unsigned int key_state : 8;         //按键状态[1:有键按下,0:没有按键按下(或功能键,此处不用)]
        unsigned int key : 8;               //按键键值
        unsigned int repeat : 8;            //连击计数器
        unsigned int reserved : 8;          //预留
    };
    
    //按键对应的LED状态定义
    typedef struct LedAndKeyInfoStru {
        unsigned int key : 8;
        unsigned int led_state : 8;
    }KeyAndLedStateStru_t;
    
    static int fd = -1;
    
    KeyAndLedStateStru_t led_and_key[] = {
        {.key = 1, .led_state = 0},
        {.key = 2, .led_state = 0},
        {.key = 3, .led_state = 0},
        {.key = 4, .led_state = 0},
        {.key = 28, .led_state = 0},
        {.key = 27, .led_state = 0},
        {.key = 26, .led_state = 0},
        {.key = 25, .led_state = 0},
        {.key = 20, .led_state = 0},
        {.key = 19, .led_state = 0},
        {.key = 18, .led_state = 0},
    };
    
    #define LED_IOCTL_ON    0
    #define LED_IOCTL_OFF   1
    
    static void led_onoff(unsigned int onoff, unsigned int key)
    {
        if (fd < 0) {
            return;
        }
    
        if (onoff == 0) { //ON
            ioctl(fd, LED_IOCTL_ON, &key);
        } else { //OFF
            ioctl(fd, LED_IOCTL_OFF, &key);
        }
    }
    
    #define LED_ON_FUN(key)     led_onoff(0, key)
    #define LED_OFF_FUN(key)    led_onoff(1, key)
    
    static void key_led_onoff(unsigned int key)
    {
        int i = 0;
    
        if (fd < 0) {
            return;
        }
    
        for (i = 0; i < (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t)); ++i) {
            if (led_and_key[i].key == key) {
                break;
            }
        }
    
        if (i >= (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t))) {
            return;
        }
    
        if (led_and_key[i].led_state == 1) {
            LED_OFF_FUN(key);
            led_and_key[i].led_state = 0;
        } else { //OFF
            LED_ON_FUN(key);
            led_and_key[i].led_state = 1;
        }
    }
    
    int main()
    {
        struct UserKeyDataStru user_key_data = {0};
    
        fd = open(KEY_DEV, O_RDONLY);
        if (fd < 0) {
            printf("Error open %s\n\n", KEY_DEV);
            
            return -1;
        }           
        printf("[%d]Open %s Ok\n", fd, KEY_DEV);
    
        while(1) {
            if (read(fd, &user_key_data, sizeof(user_key_data)) < 0) {
                perror("read error");
                break;
            }
    
            if (user_key_data.key_state != 0) {
                printf("key = %d, repeat = %d\n", user_key_data.key, user_key_data.repeat);
                key_led_onoff(user_key_data.key);
            }
            
            usleep(500);
        }
        
        close(fd);
    
        return 0;
    }
    

    在树莓派A20上做测试,效果如下:

    
    root@marsboard:~# ./keyTest
    [3]Open /dev/keyboard_i2c7290 Ok
    key = 20, repeat = 1
    key = 26, repeat = 1
    key = 27, repeat = 1
    key = 28, repeat = 1
    key = 19, repeat = 1
    key = 20, repeat = 1
    key = 26, repeat = 1
    key = 27, repeat = 1
    key = 28, repeat = 1
    key = 1, repeat = 1
    key = 5, repeat = 1
    key = 5, repeat = 1
    

    相关文章

      网友评论

          本文标题:五 . 树莓派A20 I2C驱动程序

          本文链接:https://www.haomeiwen.com/subject/cschkxtx.html