当前位置: 首页 > news >正文

如何建立视频号/关键词优化多少钱

如何建立视频号,关键词优化多少钱,乐山 做网站,网站商城系统设计TQ2440 linux i2c驱动——at24c02(eeprom) 最近因为实习的原因要搞一个摄像头的驱动,多数cmos摄像头是用SCCB协议来配置寄存器,类似于i2c,于是从零o开始。因为TQ2440板上有at24c02 eeprom,正好拿他来开刀。…

TQ2440 linux i2c驱动——at24c02(eeprom

最近因为实习的原因要搞一个摄像头的驱动,多数cmos摄像头是用SCCB协议来配置寄存器,类似于i2c,于是从零o开始。因为TQ2440板上有at24c02 eeprom,正好拿他来开刀。下面把这几天的心得写下来与大家分享。

一.开发环境:

(1)开发板:TQ2440开发板

(2)pc系统:ubuntu 13.04-amd64

(3)交错编译器:arm-linux-gcc version-4.3.3
(4)linux kernel:linux 2.6.30。4

二.i2c系统简介

(这里稍微罗嗦几句结构上的东西,摘抄自网络)
I2c是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.另外,I2C是一种多主机控制总线.它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须由主机发起才可以.而I2C是基于multi master机制.一同总线上可允许多个master.关于I2C协议的知识,这里不再赘述.可自行下载spec阅读即可.

1.I2C架构概述






如上图所示,每一条I2C对应一个adapter.在kernel中,每一个adapter提供了一个描述的结构(struct i2c_adapter),也定义了adapter支持的操作(struct i2c_adapter).再通过i2c core层将i2c设备与i2c adapter关联起来。

2.我们需要动手的部分

(1).平台总线驱动。这个一般内核都有,s3c2440的在/drivers/i2c/busses/i2c-s3c2410.c这里不会分析这个,我也没弄懂.
(2).编写挂在总线上的设备驱动。本文重点讲这个怎么写。这个驱动一般分为二类:

a.i2c-dev.c

这个是linux 内核自带的一个通用驱动(/drivers/i2c/i2c-dev.c).
i2c-dev.c 并没有针对特定的设备而设计,只是提供了通用的 read()、write()和 ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的 i2c 设备的存储空间或寄存器,并控制 I2C设备的工作方式。需要特别注意的是:i2c-dev.c 的 read()、write()方法都只适合于如下方式的数据格式(可查看内核相关源码)

图 1 单开始信号时序


所以不具有太强的通用性,如下面这种情况就不适用(通常出现在读目标时)





图 2 多开始信号时序

而且 read()、write()方法只适用用于适配器支持 i2c 算法的情况,如:
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
而不适合适配器只支持 smbus 算法的情况,如:
static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = i801_access,
.functionality = i801_func,
};
基于上面几个原因,
所以一般都不会使用 i2c-dev.c 的 read()、write()方法。最常用的是 ioctl()
方法。ioctl()方法可以实现上面所有的情况(两种数据格式、以及 I2C 算法和 smbus 算法)

针对 i2c 的算法,需要熟悉 struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是
I2C_RDWR。
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
_ _u16 addr; /* slave address */
_ _u16 flags; /* 标志(读、写) */_ _u16 len; /* msg length */
_ _u8 *buf; /* pointer to msg data */
};
针对 smbus 算法,需要熟悉 struct i2c_smbus_ioctl_data。使用的命令是 I2C_SMBUS。对于
smbus 算法,不需要考虑“多开始信号时序”问题。
struct i2c_smbus_ioctl_data {
__u8 read_write; //读、写
__u8 command; //命令
__u32 size; //数据长度标识
union i2c_smbus_data __user *data; //数据
};

上面是摘抄自网络的内容,下面讲讲如何使用这个驱动来进行i2c通信。如果你在内核开启了i2c支持的话,这个驱动就会被编译并挂载。/dev/i2c-0就是这个设备路径,我们只要写个应用程序就可以了使用它。这里用tq2440的at24c02为例子来讲解。(tq2440自带的i2c_rw.c也是同样的道理,不过这里的例子讲的是用ioctl()来调用读和写的)

                                                           












TQ2440 at24c02电路图

由图可得,A0,A1,A2接GND,查datasheet可得at24c02的地址为0x50。下面直接上所有代码吧.i2c_test.c
/*************************************************************************
> File Name: i2c_test.c
> Author: izobs
> Mail: ivincentlin@gmail.com
> Created Time: 2013年07月15日 星期一 15时04分23秒
************************************************************************/#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#define I2C_RETRIES 0x0701
#define I2C_TIMEOUT 0x0702
#define I2C_RDWR 0x0707struct i2c_msg
{
unsigned short addr;
unsigned short flags;
#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
unsigned short len;
unsigned char *buf;
};struct i2c_rdwr_ioctl_data
{
struct i2c_msg *msgs;
int nmsgs;
};int main()
{
int fd,ret;
struct i2c_rdwr_ioctl_data e2prom_data;
fd = open("/dev/i2c-0",O_RDWR);
if(fd < 0)
{
perror("open error\n");
}
e2prom_data.nmsgs = 2; /*读时序为2个开始信号*/
e2prom_data.msgs = (struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
if(!e2prom_data.msgs)
{
perror("malloc error");
exit(1);
}ioctl(fd,I2C_TIMEOUT,1); /*超时时间*/
ioctl(fd,I2C_RETRIES,2); /*重复次数*/e2prom_data.nmsgs = 1;
(e2prom_data.msgs[0]).len = 2;
(e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址
(e2prom_data.msgs[0]).flags=0; //write
(e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
(e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 写入目标的地址
(e2prom_data.msgs[0]).buf[1]=0x58;//the data to write
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);if(ret < 0)
{
perror("ioctl error");
}
sleep(1);e2prom_data.nmsgs = 2;
(e2prom_data.msgs[0]).len=1; //e2prom 目标数据的地址
(e2prom_data.msgs[0]).addr=0x50; // e2prom 设备地址
(e2prom_data.msgs[0]).flags=0;//write
(e2prom_data.msgs[0]).buf[0]=0x10;//e2prom 数据地址
(e2prom_data.msgs[1]).len=1;//读出的数据
(e2prom_data.msgs[1]).addr=0x50;// e2prom 设备地址
(e2prom_data.msgs[1]).flags=I2C_M_RD;//read
(e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。
(e2prom_data.msgs[1]).buf[0]=0;//初始化读缓冲
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
if(ret<0)
{
perror("ioctl error2");
}
printf("buff[0] = %x\n",e2prom_data.msgs[1].buf[0]);
close(fd);
return 0;


b.legacy式和new style式 i2c设备驱动

好吧,这个才是重头戏。i2c设备驱动,可以以字符设备的架构来写。在read(),write()里面用i2c的通信方式。而结合i2c,即adapter的方法有两种方式:
(1)legacy
这个方面查资料说,在2.6.30.后的内核可能已经不能再使用了。说是部分函数已经不能再被调用了。我在/Documentation/i2c/writing-client里找到这段话.

accordingly, the I2C stack now has two models for associating I2C deviceswith their drivers: the original "legacy" model, and a newer one that'sfully compatible with the Linux 2.6 driver model. These models do not mix,since the "legacy" model requires drivers to create "i2c_client" device objects after SMBus style probing, while the Linux driver model expects drivers to be given such device objects in their probe() routines.

The legacy model is deprecated now and will soon be removed, so we nolonger document it here
.

所以,这个part就到此结束吧!
(2)new style
这个一听就很有派头。这个方式,是通过probe函数,即一个探针去探测什么设备是挂在总线上的。所以我们必须在平台上写上我们设备的名字。即注册 i2c_board_info。下面讲讲在tq2440怎么把这个at24c20注册进去。
进入linux-2.6.30.4/arch/arm/mach-s3c2440,打开math-tq2440.c
做如下修改:

#include <linux/i2c.h>
#include <linux/i2c-id.h>

#include <linux/mod_devicetable.h>
#include <linux/device.h>/* for struct device */
#include <linux/sched.h>/* for completion */
#include <linux/mutex.h>

在340行左右加:
static struct i2c_board_info i2c_devices[] __initdata = {
{
I2C_BOARD_INFO("at24c02",0x50), //at24c02和他的地址0x50
},
};

在359行附近, tq2440_machine_init函数,加下面句子
static void __init tq2440_machine_init(void)
{
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));
}。

重新编译内核,make zImage -j2 ,你懂的!


下面是new style设备代码,架构是cdev char device。如下:

/*************************************************************************
> File Name: at24c02.c
> Author: izobs
> Mail: ivincentlin@gmail.com
> Created Time: 2013年07月16日 星期二 19时37分14秒
************************************************************************/#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/delay.h>#define AT24C02_MAJOR 250#define DEBUG 1static int at24c02_major = AT24C02_MAJOR;/*声明at24c02结构体*/
struct at24c02_dev
{
struct i2c_client *client;
unsigned int addr;
char name[30];
unsigned short current_pointer;
struct cdev cdev;
};
struct at24c02_dev *at24c02_devp;static int at24c02_open(struct inode *inode,struct file*filp)
{
filp->private_data = at24c02_devp;
printk("at24c02_open is called\n");#if DEBUG
printk(KERN_NOTICE"open decvice is called\n");
#endif
return 0;
}static ssize_t at24c02_read(struct file *filp, char __user *buf, size_t size,loff_t *ppos)
{
int i = 0;
int transferred = 0;
unsigned char ret =0;
unsigned char my_buff[512]={0};struct at24c02_dev *dev = (struct at24c02_dev *)filp->private_data;
dev->current_pointer = *ppos;
/*检测adapter是否支持读写功能
*start inline int i2c_check_functionality(struct adapter*adp,u32 func)
*/
if(i2c_check_functionality(dev->client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA))
{
while(transferred < size)
{
/*s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);*/
/*将会调用i2c_smbus_xfer*/
ret = i2c_smbus_read_byte_data(dev->client,dev->current_pointer +i);
my_buff[i++] = (unsigned char) ret;
transferred +=1;
#if DEBUG
printk(KERN_NOTICE"the my_buff[%d] is %x,transferred is %d",i,my_buff[i],transferred);
#endif}
copy_to_user(buf,(void *)my_buff,transferred);
dev->current_pointer += transferred;
}return transferred;
}static ssize_t at24c02_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int i = 0;
int transferred = 0;
int ret;
unsigned char my_buff[512];struct at24c02_dev *dev = (struct at24c02_dev *)filp->private_data;
dev->current_pointer = *ppos;
if(i2c_check_functionality(dev->client->adapter,I2C_FUNC_SMBUS_BYTE_DATA))
{
copy_from_user(my_buff,buf,size);
while(transferred < size)
{
ret = i2c_smbus_write_byte_data(dev->client,dev->current_pointer+i,my_buff[i]);
#if DEBUG
printk(KERN_NOTICE"write data %d-----my_buff%x",i,my_buff[i]);
#endifi+=1;
transferred +=1;
}
dev->current_pointer +=transferred;
}
return transferred;
}static int at24c02_ioctl(struct inode*inodep,struct file *filp,unsigned int cmd,unsigned long arg)
{
return 0;
}static int at24c02_release(struct inode*inodep,struct file *filp)
{
filp->private_data = NULL;
return 0;
}static const struct file_operations at24c02_fops =
{
.owner = THIS_MODULE,
.open = at24c02_open,
.read = at24c02_read,
.write = at24c02_write,
.ioctl = at24c02_ioctl,
.release = at24c02_release,
};static void at24c02_setup_cdev(struct at24c02_dev*dev, int index)
{
int err, devnum = MKDEV(at24c02_major, index);
#if DEBUG
printk(KERN_NOTICE"the devnum is %d\n",devnum);
#endif
cdev_init(&dev->cdev, &at24c02_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &at24c02_fops;err = cdev_add(&dev->cdev, devnum, 1);
if (err)
printk(KERN_NOTICE"Error %d adding at24c02 %d", err, index);}/*在__devinit probe函数中初始化cdev*/static int __devinit at24c02_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret;
#if DEBUG
printk(KERN_NOTICE"at24c02 probe is start init\n");
#endifdev_t devnum = MKDEV(at24c02_major,0);if (at24c02_major)
{
ret = register_chrdev_region(devnum,1,"at24c02");
}
else
{
ret = alloc_chrdev_region(&devnum,0,1,"at24c02");
}if(ret < 0)
return ret;
at24c02_devp = kmalloc(sizeof(struct at24c02_dev),GFP_KERNEL);
if(!at24c02_devp)
{
ret = -ENOMEM;
goto fail_malloc;
}
memset(at24c02_devp,0,sizeof(struct at24c02_dev));at24c02_devp->client = client;at24c02_setup_cdev(at24c02_devp,0);
return 0;fail_malloc:
unregister_chrdev_region(devnum,1);
#if DEBUG
printk(KERN_NOTICE"fail_malloc\n");
#endif
return ret;}/*__devexit _remove函数*/static int __devexit at24c02_remove(struct i2c_client *client)
{
cdev_del(&at24c02_devp->cdev);
kfree(at24c02_devp);
unregister_chrdev_region(MKDEV(at24c02_major,0),1);
return 0;
}static const struct i2c_device_id at24c02_id[] = {
{"at24c02",0},
{}
};MODULE_DEVICE_TABLE(i2c,at24c02_id);static struct i2c_driver at24c02_driver =
{
.driver = {
.name = "at24c02",
.owner = THIS_MODULE,
},
.probe = at24c02_probe,
.remove = __devexit_p(at24c02_remove),
.id_table = at24c02_id,
};static int __init at24c02_init(void)
{
int ret;
#if DEBUG
printk(KERN_NOTICE"at24c02 probe is start init\n");
#endif
ret = i2c_add_driver(&at24c02_driver);
return ret;
}void at24c02_exit(void)
{
i2c_del_driver(&at24c02_driver);
#if DEBUG
printk(KERN_NOTICE"at24c02 is rmmod\n");
#endif}MODULE_AUTHOR("izobs");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("at24c02 eeprom driver");module_param(at24c02_major, int, S_IRUGO);module_init(at24c02_init);
module_exit(at24c02_exit);



这里讲讲怎么用吧,
~/ cd /dev
~/ insmod at24c02.ko
~/ cat /proc/devices 获得 设备号
~/ mknod /dev/at24c02 c 250 0 设备路径生成,ok


写个app,效果如下:




我会把所有代码push到gitcafe

~/ git clone git://gitcafe.com/iZobs/TQ2440-at24c02.git
http://www.jmfq.cn/news/5268115.html

相关文章:

  • 中山网站建设价格/seo排名的职位
  • asp.net 4.0网站开发 下载/百度电脑版网页版
  • 厦门集团网站建设/长沙线上引流公司
  • 建门户网站需要多少钱/系统优化软件十大排名
  • 网站代码seo优化/国产十大erp软件
  • 哪个网站做设计可以挣钱/俄罗斯搜索引擎yandex推广
  • 电商网站建设与管理/aso搜索优化
  • 机械设备网站/公司企业网站模板
  • 怎么把网站加入黑名单/百度上怎么免费开店
  • 口碑好的东莞网站建设/百度指数指的是什么
  • 小型网站建设公司/整站优化服务
  • 广东平台网站建设找哪家/广州seo站内优化
  • web程序设计网站开发工具/制作网站费用
  • 用win2008做网站/今日国内重大新闻事件
  • wordpress电影模板下载/如何将网站的关键词排名优化
  • iis6 网站无法访问/公司网站
  • 烟台做网站的公司/游戏推广员好做吗
  • wordpress模板 更换/seo刷关键词排名免费
  • 石家庄市最新公告/苏州整站优化
  • 吉林seo基础知识/上首页seo
  • 网站建设费用:做个网站要多少钱?/影视剪辑培训机构排名
  • 自己做网站能宣传自己的产品吗/网络推广员为什么做不长
  • 北京建设网站的公司兴田德润优惠/seo 优化顾问
  • 营销型网站 开源程序/大数据营销系统软件
  • 做美女网站挣钱/百度首页关键词推广
  • 兰州企业做网站/软文写作服务
  • 海南智能网站建设公司/外贸独立站推广
  • 网页的制作教案/成都网站seo厂家
  • 做公司网站需要准备什么/怎么有自己的网站
  • 重庆金融网站建设/搜索引擎优化心得体会