1编写OV9650驱动之前的准备工作:
1.1 使用资源:
开发板:S3C6410芯片
Linux内核: linux-2.6.38
CMOS摄像头: ov9650
1.2 了解需要完成的工作:
1.2.1 背景知识:
I2C驱动:
Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片、音视频采集芯片、音视频输出芯片、EEROM芯片、AD/DA转换芯片等等。
在本例中,ov9650就是对应的I2C设备(但是它并不是用的标准I2C协议,后面会提到)。
1.2.1.1 Linux I2C子系统:
(参考链接:http://blog.csdn.net/jmq_0000/article/details/7473682)
在内核中已经提供I2C子系统,所以在做I2C驱动之前,就必须要熟悉该子系统。
可以看出分为三大组成部分
1)I2C核心(i2c-core)
I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
2)I2C总线驱动(I2C adapter/Algo driver)
I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力。
I2C总线驱动由i2c_adapter和i2c_algorithm来描述。
3)I2C客户驱动程序 (I2C client driver)
I2C客户驱动是对I2C从设备的软件实现,一个具体的I2C客户驱动包括两个部分:一部分是i2c_driver,用于将设备挂接于i2c总线;
另一部分是设备本身的驱动。
I2C客户驱动程序由i2c_driver和i2c_client来描述。
所有的I2C驱动代码位于drivers/i2c目录下
*I2c-core.c 实现I2C核心的功能
*I2c-dev.c 通用的从设备驱动
Chips 特定的I2C设备驱动
Busses I2C适配器的驱动
Algos 实现了一些I2C总线适配器的algorithm
1.2.1.2 I2C设备驱动编写步骤
参考链接:http://www.it165.net/embed/html/201312/2376.html
编写一个I2C设备驱动程序的工作可分为三部分:
1) 定义和注册I2C设备,即构建i2c_client;(在mach-mini6410.c中添加),参考arch/arm/mach-s3c24xx/mach-mini6410.c
我们不用直接定义一个i2c_client结构,Linux会根据I2C设备的相关信息自动创建i2c_client。所以,我们需要提供I2C设备的相关信息。i2c_client 信息通常在BSP的板文件中通过i2c_board_info 填充。
步骤1:用i2c_board_info结构体保存I2C设备相关信息
步骤2:调用i2c_register_board_info函数注册i2c设备相关信息
2) 定义和注册I2C设备驱动,即i2c_driver(利用内核提供的i2c-dev.c的框架来构建) 参考linux-2.6.38\drivers\i2c\i2c-dev.c:
步骤1:构建i2c_driver,定义i2c_driver结构体变量。(struct i2c_driver)。
步骤2:注册i2c_driver, 调用i2c_add_driver注册i2c_driver结构体变量。(__init函数中完成)
步骤3:注销i2c_driver。 (__exit函数中完成)
3) 实现i2c_driver中要示实现的函数
几个重要的结构体:
i2c_msg(设置设备地址的)
i2c_client(从机设备的地址,一般采用平台设备的形式,用probe函数探测)
i2c_driver自己构建。
几个重要的方法:
i2c_add_driver添加设备
i2c_transfer用于进行I2C适配器和I2C设备之间的一组消息的交互
1.2.2任务规划
总线驱动:不需要实现,已有。
这里因为内核中已经提供了S3C6410的I2C总线驱动(在/linux-2.6.38/drivers/i2c/busses目录下的i2c-s3c2410.c文件就是总线驱动,虽然是S3C2410的,但是同样支持S3C6410)。
设备驱动:
1需要完成S3C6410 CAMIF的平台资源注册:
在arch/arm/mach-s3c24xx/mach-mini6410.c文件中:
定义并注册S3C6410的CAMIF(camera interface)
2 然后编写ov9650的设备驱动:
参照 linux-2.6.38\drivers\media\video\ov9640.h, ov9640.c
2 开始编写ov9650驱动
2.1在arch/arm/mach-s3c24xx/mach-mini6410.c:
OV9650
OV9650的从设备地址:
官方资料:
注意 由于摄像头本身使用的是SCCB协议(8位地址),换成I2C协议(7位地址后),地址0x60变为0x30。
I2C与SCCB协议区别:从机地址因为I2C是7位地址,最后一位是读写位,而SCCB是8位地址,比如ov9650,他是SCCB协议,他的地址是0x60,那么如果挂接到I2C总线上,他的地址就变成0x30了,这样算的:
SCCB地址::: 0x60: 0 1 1 0_0 0 0 0 这个0还是地址位
I2C地址:::: 0 1 1 0_0 0 0 0最后红色的0是读写位,那么地址变成了7 位 +读写位 即 0 1 1_ 0 0 0 0 +0( 读写位 ) 所以从机地址变成了0x30
参考链接: http://www.cnblogs.com/crazybingo/archive/2012/03/31/2426226.html
CAMIF :
Tiny6410-1107.pdf
编辑linux-2.6.38/arch/arm/mach-s3c64xx/ mach-mini6410.c
1 i2c对应的通道 ,是默认的,不需要修改
static struct i2c_board_info i2c_devs1[] __initdata = {
{
I2C_BOARD_INFO("ov965x", 0x30), // 可以改为ov9650
},
};
写ov9650设备驱动:
参照 linux-2.6.38\drivers\media\video\ov9640.h, ov9640.c
对照寄存器地址表,可以看出9640的驱动兼容9650,又省去一大头工作。。。。。
其实内核里面的驱动都有了,所以我们不需要写驱动了。。。
只是分析一下大概的结构。
参考资料:
http://blog.csdn.net/mayaoyao11/article/details/6677141
http://www.cnblogs.com/crazybingo/archive/2012/03/31/2426226.html
http://www.cnblogs.com/liugf05/archive/2012/12/11/2812997.html