IIC驱动(OS)

一、实验平台:开发板fs2410,采用三星s3c2410的CPU,linux操作系统。

二、实现功能:向E2PROM里面写数据,再读出来。

三、实验原理:

       E2PROM属于I2C设备,所以这里用到了I2C的数据传输协议,一根专用串行数据线 SDA和一根串行时钟线SCL在总线主机和连到 I2C总线上的外设之间传输数据,SDA和SCL都是双向的。

当 I2C总线空闲时,SDA和 SCL线都处于高电平状态,当 SCL保持高电平时,一个SDA下降沿可以初始化一个起始条件;当 SCL保持高电平时,SDA的一个上升沿可以初始化一个停止条件。

发送到 SDA上的每个数据必须是8位的,数据总是从MSB开始传输,所有字节后都必须跟1个ACK应答位。

四、实验现象:

       应用程序执行时,若输入./e2prom_test w 1则向E2PROM写入数据1,如输入./e2prom_test r则从E2PROM读取数据,并打印出来。由于应用程序一次最多只能写一个字节,所以0~255的数据可以正确读写,超出范围后,数据会失真。

 

五、实验总结:

在内核中有I2C驱动的体系架构,将其划分为三个层次,从上往下依次为:设备驱动层,核心层以及控制器驱动层。这里主要实现设备驱动层,下面两层使用内核的代码。

驱动的体系架构很重要,不清楚体系架构就没有写代码的思路,所以要多跟内核的代码。同时要体会分层的思想。

六、示例代码:

/*设备驱动代码e2prom.c*/
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include<linux/fs.h>
#include <linux/i2c.h>
#include<asm/uaccess.h>

static unsigned int e2prom_major = 0;
static struct class *e2prom_class = NULL;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = {0x50, I2C_CLIENT_END };
static unsigned char msgs_data[1024];
static struct i2c_client at24c02_client;

static struct i2c_client_address_data at24c02_addr_data = {
	.normal_i2c	= normal_addr,
	.probe		= ignore,
	.ignore		= ignore,
};

static int at24c02_detect(struct i2c_adapter *adapter, int address, int kind);
static int at24c02_attach_adapter(struct i2c_adapter *adapter);
static int at24c02_detach_client(struct i2c_client *client);

static struct i2c_driver at24c02_driver = {
	.driver = {
		.name	= "at24c02",
	},
	.attach_adapter	= at24c02_attach_adapter,
	.detach_client		= at24c02_detach_client,
};

static int e2prom_open(struct inode *inode, struct file *file)
{
	return 0;
}

static ssize_t e2prom_read(struct file *file, char __user *buf, size_t count, loff_t *opps)
{
	int ret;
	unsigned char addr = 0;
	struct i2c_msg msgs[1];
	
	msgs[0].addr = at24c02_client.addr;
	msgs[0].flags = 0;   //读之前要写入器件地址和偏移量
	msgs[0].len = 1;
	msgs[0].buf = &addr;     //偏移地址

	msgs[1].addr = at24c02_client.addr;
	msgs[1].flags = 1;   //读命令
	msgs[1].len = 1;
	msgs[1].buf = msgs_data;     //存放读取的数据

	i2c_transfer(at24c02_client.adapter, msgs, 2);

	ret = copy_to_user(buf, msgs_data, count);

	return 0;
}

static ssize_t e2prom_write(struct file *file, const char __user *buf, size_t count, loff_t *opps)
{
	int ret;
	struct i2c_msg msgs;
	
	ret = copy_from_user(&msgs_data[1], buf, count);
	msgs_data[0] = 0;

	msgs.addr = at24c02_client.addr;
	msgs.flags = 0;   //写命令
	msgs.buf = msgs_data;     //要写入的数据
	msgs.len = count+1;

	i2c_transfer(at24c02_client.adapter, &msgs, 1);
	
	return 0;
}

static struct file_operations e2prom_fops = {
	.owner 	= THIS_MODULE,
	.open 	= e2prom_open,
	.read 	= e2prom_read,
	.write 	= e2prom_write,
};

/*构建struct i2c_client来描述检测到的I2C设备*/
static int at24c02_detect(struct i2c_adapter *adapter, int address, int kind)
{	
	/*初始化i2c_client结构体*/
	at24c02_client.adapter = adapter;
	at24c02_client.addr = address;
	at24c02_client.driver = &at24c02_driver;
	at24c02_client.flags = 0;
	strcpy(at24c02_client.name,"at24c02");

	/*加载到I2C子系统中*/
	i2c_attach_client(&at24c02_client);

	/*注册到内核*/
	e2prom_major = register_chrdev(0, "e2prom", &e2prom_fops);
	e2prom_class = class_create(THIS_MODULE, "e2prom_class");
	class_device_create(e2prom_class, NULL, MKDEV(e2prom_major,0), NULL, "e2prom");

	return 0;
}

/*检测I2C设备是否存在,存在就调用at24c02_detect函数*/
static int at24c02_attach_adapter(struct i2c_adapter *adapter)
{
	return i2c_probe(adapter, &at24c02_addr_data, at24c02_detect);
}

static int at24c02_detach_client(struct i2c_client *client)
{
	i2c_detach_client(client);
	unregister_chrdev(e2prom_major, "e2prom");
	class_destroy(e2prom_class);
	class_device_destroy(e2prom_class, MKDEV(e2prom_major,0));

	return 0;
}


int __init e2prom_init(void)
{
	i2c_add_driver(&at24c02_driver);

	return 0;
}

void __exit e2prom_exit(void)
{
	i2c_del_driver(&at24c02_driver);
}

module_init(e2prom_init);
module_exit(e2prom_exit);

MODULE_LICENSE("GPL");
/*测试代码e2prom_test.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

void print_usage(char *str)
{
    printf("%s r     : read at24c02 addresss 0\n", str);
    printf("%s w val : write at24c02 addresss 0\n", str);
}

int main(int argc, char **argv)
{
    int fd;
    int ret;
    unsigned char val;
    
    if (argc < 2)
    {
        print_usage(argv[0]);
        return -1;
    }

    if((fd = open("/dev/e2prom", O_RDWR)) == -1){
        perror("open /dev/e2prom failed");
        exit(-1);
    }

    if (strcmp(argv[1], "r") == 0){
        read(fd, &val, 1);   
       	printf("get data:%d\n", val);
    }

    else if ((strcmp(argv[1], "w") == 0) && (argc == 3)){
        val = strtoul(argv[2], NULL, 0);
        write(fd, &val, 1);
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值