五 . 树莓派A20 I2C驱动程序


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框架总图

五 . 树莓派A20 I2C驱动程序_第1张图片
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硬件原理图如下所示:


五 . 树莓派A20 I2C驱动程序_第2张图片
I2C接口

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


I2C引脚描述

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

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


五 . 树莓派A20 I2C驱动程序_第3张图片
image.png

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

也就是如下图所示:

五 . 树莓派A20 I2C驱动程序_第4张图片
I2C模组图
五 . 树莓派A20 I2C驱动程序_第5张图片
原理图

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

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

#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include    

#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>
twi4_sda = port:PI03<3>
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 
五 . 树莓派A20 I2C驱动程序_第6张图片
选中I2C7290

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

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//#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 ");
MODULE_DESCRIPTION("Keyboard driver for I2c7290");
MODULE_LICENSE("GPL");

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

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

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

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#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驱动程序)