【无标题】ic2驱动app

准备工作:

(1)内核层:查看drivers/i2c目录下的Makefile文件。()是否有编译如下文件:i2c-core.c, i2c-dev.c, i2c-drive.c 

(2)总线驱动层:在driver/i2c/busses目录下:看Makefile文件是否有i2c-s3c2410.0

(3)在linux目录下make menuconfig ,查看又没有把配置选进去,这个和Makefile的宏是等同的,比如

obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o  ,那么可以在menuconfig搜索CONFIG_I2C_MUX_GPIO这个宏定义。

Device_Deivers--->I2c_support   //i2c-core.c

                          ---->i2c device interface   //i2c-dev.c

                          ---->i2c hardware bus support---->s3c2410 i2C Driver   // i2c-s3c2410.c

(4)然后在linux根目录下:make uImage 编译生成内核烧录

注册设备

cat /proc/device    //可以查看设备是否被注册成功

注册驱动------平台设备驱动

卸载设备

卸载驱动

i2cdetect -y 1   //此命令可以监测到IIC总线上所有的iic设备,用于确认iic子设备的设备地址
 

 
#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
int main(int argc, char**argv)
{
    int fd;
    fd = open("/dev/i2c-1", O_RDWR);
    if (fd < 0) {
        perror("open failed\n");
        exit(1);
    }
 
    int device_addr = 0x40; //硬件设备地址
    if (ioctl(fd, I2C_SLAVE, device_addr) < 0) {
        perror("ioctl failed\n");
        exit(1);
    }
 
    char wbuf[10];
    char register_addr = 0x3;
    /* Using I2C Write*/
    wbuf[0] = register_addr;
    wbuf[1] = 0x5;
    if (write(fd ,wbuf, 2) != 2) {
        perror("write failed\n");
        exit(1);
    }
 
    if (write(fd ,&register_addr, 1) != 1) {
        perror("write failed\n");
        exit(1);
    }
 
    /* Using I2C Read*/
    char rbuf[10];
    if (read(fd, &rbuf[0], 1) != 1) {
        perror("read failed\n");
        exit(1);
    } else {
        printf("rbuf value = [%d]\n", rbuf[0]);
    }
}
2.用户态驱动设计

我们先分析一下程序大概的流程:

(1)打开通用的字符设备文件

依然是使用open打开设备文件,在开发板的/dev/下面我们可以找到一个叫做i2c-0的设备文件,我们以读写的方式打开这个设备文件。
// 1.打开通用设备文件
fd = open("/dev/i2c-0", O_RDWR);
 (2)构造需要写入到EEPROM中的消息

我们首先需要赋值消息的定义到我们的程序中。即i2c_msg和i2c_rdwr_ioctl_data,可以把一些不需要的数据删掉。
struct i2c_msg 
{
    unsigned short addr;    
    unsigned short flags;
    unsigned short len;        
    unsigned char *buf;        
};
 
struct i2c_rdwr_ioctl_data 
{
    struct i2c_msg *msgs; // 消息指针
    unsigned int nmsgs;    // 消息数量        
};
然后定义一个消息结构,i2c_rdwr_ioctl_data eeprom_data,然后初始化这个结构(别忘了给指针分配空间)。特别要注意的是对应消息的数量读和写肯定是不一样的,因为对于写只需要一个消息,而对于读只需要2个消息,因为先做了一次写,然后在做了一次读。因此我们按最大的长度2,来给i2c_msg分配空间。
接下来可以初始化写的消息,写的信息有2个字节,所以len=2,第一个是偏移地址,第二个是需要写入的数据。初始化后如下:

// 因为对于写只需要一个消息
// 对于读只需要2个消息,因为先做了一次写,然后在做了一次读
// 因此我们按最大的长度2,来给i2c_msg分配空间 
e2prom_data.msgs = (struct i2c_msg *)malloc(2 * sizeof(struct i2c_msg)); 
    
// 2.构造写数据到eeprom的消息
e2prom_data.nmsgs = 1;  // 写只有一条消息
(e2prom_data.msgs[0]).len = 2;  // 偏移地址+数据
(e2prom_data.msgs[0]).addr = 0x50;  // eeprom设备地址
(e2prom_data.msgs[0]).flags = 0;  // 0为写,1为读
(e2prom_data.msgs[0]).buf = (unsigned char *)malloc(2);
(e2prom_data.msgs[0]).buf[0] = 0x10;  // 写入到EEPROM的偏移地址
(e2prom_data.msgs[0]).buf[1] = 0x60;  // 写入到偏移地址的数据
(3)使用ioctl写入数据

ioctl的第一个参数是fd,第二个参数是操作类型,这里是I2C_RDWR,我们需要拷贝I2C_RDWR到自己的程序中,第三个是参数就是eeprom_data了,我们在取地址之后需要进行类型转换,因为i2cdev_ioctl_rdrw的参数是unsigned long.
 

#define I2C_RDWR    0x0707    
// 3.使用ioctl写入数据
ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
(4)构造从EEPROM读数据的消息

读消息的构造也类似,不过这里需要2个消息,第一个实现写,第二个实现读:
// 4.构造从EEPROM读数据的消息
eeprom_data.nmsgs = 2;  // 读有二条消息
(eeprom_data.msgs[0]).addr = 0x50;// 先写入需要开始读取的偏移地址,然后开始读
(eeprom_data.msgs[0]).flags = 0;
(eeprom_data.msgs[0]).len = 1;
(eeprom_data.msgs[0]).buf[0] = 0x10;
 
(eeprom_data.msgs[1]).addr = 0x50;
(eeprom_data.msgs[1]).flags = 1;
(eeprom_data.msgs[1]).len = 1;
(eeprom_data.msgs[1]).buf = (unsigned char *)malloc(2);
(eeprom_data.msgs[1]).buf[0] = 0;  // 先把读取缓冲清0
 (5)使用ioctl读出消息

ioctl(fd, I2C_RDWR, (unsigned long)&eeprom_data);
 
// 读取到的消息会保存在以buf[0]为起始地址的存储空间中。
(6)关闭字符设备

close(fd) 
完整代码:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
 
#define I2C_RDWR 0x0707    
 
struct i2c_msg 
{
    unsigned short addr;    
    unsigned short flags;
    unsigned short len;        
    unsigned char *buf;        
};
 
struct i2c_rdwr_ioctl_data 
{
    struct i2c_msg *msgs;    // 消息指针
    unsigned int nmsgs;    // 消息数量        
};
 
int main()
{
    int fd;    
    struct i2c_rdwr_ioctl_data e2prom_data;
    
    // 1.打开通用设备文件
    fd = open("/dev/i2c-0", O_RDWR);
    
    // 因为对于写只需要一个消息
    // 对于读只需要2个消息,因为先做了一次写,然后在做了一次读
    // 因此我们按最大的长度2,来给i2c_msg分配空间 
    e2prom_data.msgs = (struct i2c_msg *)malloc(2 * sizeof(struct i2c_msg)); 
    
    // 2.构造写数据到eeprom的消息
    e2prom_data.nmsgs = 1;  // 写只有一条消息
    (e2prom_data.msgs[0]).len = 2;  // 偏移地址+数据
    (e2prom_data.msgs[0]).addr = 0x50;  // eeprom设备地址
    (e2prom_data.msgs[0]).flags = 0;  // //0为写,1为读
    (e2prom_data.msgs[0]).buf = (unsigned char *)malloc(2);
    (e2prom_data.msgs[0]).buf[0] = 0x10;  // 写入到EEPROM的偏移地址
    (e2prom_data.msgs[0]).buf[1] = 0x60;  // 写入到偏移地址的数据
    
    // 3.使用ioctl写入数据
    ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
    
    // 4.构造从EEPROM读数据的消息
    eeprom_data.nmsgs = 2;  // 读有二条消息
    (eeprom_data.msgs[0]).addr = 0x50;// 先写入需要开始读取的偏移地址,然后开始读
    (eeprom_data.msgs[0]).flags = 0;
    (eeprom_data.msgs[0]).len = 1;
    (eeprom_data.msgs[0]).buf[0] = 0x10;
 
    (eeprom_data.msgs[1]).addr = 0x50;
    (eeprom_data.msgs[1]).flags = 1;
    (eeprom_data.msgs[1]).len = 1;
    (eeprom_data.msgs[1]).buf = (unsigned char *)malloc(2);
    (eeprom_data.msgs[1]).buf[0] = 0;  // 先把读取缓冲清0
 
    
    // 5.使用ioctl读出数据    
    ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
    printf("buffer[0] = %x\n", (e2prom_data.msgs[1]).buf[0]);
    
    // 6.关闭设备
    close(fd);
}
3.编译

arm-linux-gcc -static i2c-app-drv.c -o i2c-app-drv
拷贝到开发板上,执行./i2c-app-drv: 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值