我使用的是cubieboard2板+dvk521扩展板,源码包是到官网下载的cubieboard2_android_SDK_v1.05。
android系统及内核源码编译见:http://blog.csdn.net/lynchyo/article/details/38292407。
关于全志A20摄像头模块配置的资料很多,杂乱无章,而且只是操作性介绍,并没有详细地说明相应操作的原因,也没有针对相应板子和源码包进行配置说明,导致像我一样的初学者刚接触时往往会一头雾水,按着资料配置很难配置成功。
经过一段时间的摸索,理清了整个配置过程,故总结之。
一、ov7670驱动文件ov7670.c在哪?
我的源码包cubieboard2_android_SDK_v1.05编译完后并没有ov7670.ko模块,原因有两个:一个是没驱动文件ov7670.c,一个是模块没指定编译。
不过通过到lichee/linux-3.4/目录下,make menuconfig,发现ov7670模块已指定编译成模块,那是不是真的没有驱动文件呢?
Device Drivers ---> <*> Multimedia support ---> [*] CSI Driver Config for sunxi ---> <M> OmniVision OV7670 sensor support
再到CubieBoard2_SDK/lichee/linux-3.4/drivers/media/video/sunxi_csi/device目录下,果然没有ov7670驱动文件ov7670.c,那到哪里去找ov7670.c文件呢?
在lichee/linux-3.4目录下$ locate ov7670.c,发现在CubieBoard2_SDK/lichee/linux-3.4/drivers/media/video目录下有一个ov7670.c,是不是它呢?不管三七二十一,把它copy一份到CubieBoard2_SDK/lichee/linux-3.4/drivers/media/video/sunxi_csi/device目录下,然后修改该目录下的makefile,在文件后面加上:obj-$(CONFIG_CSI_OV7670)+= ov7670.o
重新编译内核:
$ cd lichee/linux-3.4
$ make clean
$ cp arch/arm/configs/cubieboard2_config .config
$ cd ..
$ ./build.sh -p sun7i_android
编译完成后在CubieBoard2_SDK/lichee/linux-3.4/drivers/media/video/sunxi_csi/device目录下生成ov7670.ko。
配置sys_config.fex,camera.cfg,init.sun7i.rc,ueventd.sun7i.rc文件,然后
$ cd ../android
$ source build/envsetup.sh
$ lunch 选15
$ extract-bsp
$ make
$ pack
生成镜像在windows下用PhoenixSuit烧录到板子上,点击camera启动图标,会出现Unfortunately,Camera has stopped.
在cmd下adb logcat可看到程序运行出错原因,是因为找不到/dev/video0,而/dev/video0是否存在正是反映了驱动加载是否成功,不存在/dev/video0,证明驱动没加载成功。
adb root
adb shell
lsmod 查看已加载的模块
并没有camera.ko和sunxi_csi1.ko,调试内核,手动加载驱动(注意顺序):
echo 8 > /proc/sys/kernel/printk
rmmod /system/vendor/modules/sunxi_csi1.ko
rmmod /system/vendor/modules/ov7670.ko
rmmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/ov7670.ko
insmod /system/vendor/modules/sunxi_csi1.ko
dmesg > /sdcard/1.txt
查看1.txt:
可根据打印的信息用notepad++搜索打印该信息的地方,进而跟踪出错的原因,初步定位在以下位置:
无论怎么配置sys_config.fex,camera.cfg,init.sun7i.rc,ueventd.sun7i.rc这四个文件,无论是自动加载驱动,还是通过adb shell 手动rmmod,insmod,驱动都是没加载成功,不过初步觉得是sunxi_csi1.ko和ov7670.ko的问题。究竟问题在哪呢?
另外,购买板子时附带了一些资料:
出现格式不对的错误,原因是附带的ko文件编译时所依赖的内核版本跟我编译的内核版本不一致,所以附带的摄像头驱动资料也用不了。通过在Ubuntu下modinfo ov7670.ko知道该模块是在3.4.61版本内核下编译的,而我用的内核版本是3.4.39(cubieboard2_android_SDK_v1.05)。
另外发现一个问题:附带资料里的ov7670.ko大小有173KB,而我编出来的ov7670.ko只有63KB,是不是我用来编译的ov7670.c有问题?我拷贝的ov7670.c是不是linux内核本身自带有的驱动文件,并不适合板子用?于是我到网上或官网上尝试寻找正确的ov7670.c,未果。
再到http://docs.cubieboard.org/tutorials/cb2/development/building_your_own_android_image,对新的源码包cubieboard2_android_SDK_v1.09产生了兴趣,既然买板子时配了ov7670模块,那么肯定有源码包带有ov7670.c,于是我下载了这个源码包,解压,在lichee/linux-3.4/drivers/media/video/sunxi_csi/device目录下的确有了ov7670.c,拿来跟我之前copy的ov7670.c比较:
原来的ov7670.c真的不行啊!通过文件比较,camera.ko及sunxi_sci1.ko的源文件在两个源码包中一样,驱动加载不成功的原因很明确,就是没找到对应的ov7670.c。
于是用这个新的驱动文件替换掉原来的,再到CubieBoard2_SDK/android/out/target/product/sugar-cubieboard2/system/vendor/modules目录下把ov7670.ko删了(这一步很重要,如果没删,重新编译打包后ov7670.ko还是原来那个,所以必须删)。
二、正确配置文件
保证驱动模块没问题之后,必须正确配置sys_config.fex,camera.cfg,init.sun7i.rc,ueventd.sun7i.rc四个文件。
lichee/tools/pack/chips/sun7i/configs/android/sugar-cubieboard2/sys_config.fex文件:
[camera_list_para]
camera_list_para_used = 0
ov7670 = 1
gc0308 = 0
gt2005 = 0
hi704 = 0
sp0838 = 0
mt9m112 = 0
mt9m113 = 0
ov2655 = 0
hi253 = 0
gc0307 = 0
mt9d112 = 0
ov5640 = 0
gc2015 = 0
ov2643 = 0
gc0329 = 0
gc0309 = 0
tvp5150 = 0
s5k4ec = 0
ov5650_mv9335 = 0
siv121d = 0
;--------------------------------------------------------------------------------
;csi gpio configuration
;csi_if: 0:hv_8bit 1:hv_16bit 2:hv_24bit 3:bt656 1ch 4:bt656 2ch 5:bt656 4ch
;csi_mode: 0:sample one csi to one buffer 1:sample two csi to one buffer
;csi_dev_qty: The quantity of devices linked to csi interface
;csi_vflip: flip in vertical direction 0:disable 1:enable
;csi_hflip: flip in horizontal direction 0:disable 1:enable
;csi_stby_mode: 0:not shut down power at standby 1:shut down power at standby
;csi_iovdd: camera module io power , pmu power supply
;csi_avdd: camera module analog power , pmu power supply
;csi_dvdd: camera module core power , pmu power supply
;pmu_ldo3: fill "axp20_pll"
;pmu_ldo4: fill "axp20_hdmi"
;fill "" when not using any pmu power supply
;csi_flash_pol: the active polority of the flash light IO 0:low active 1:high active
;--------------------------------------------------------------------------------
[csi0_para]
csi_used = 0
csi_dev_qty = 1
csi_stby_mode = 0
csi_mname = "ov7670"
csi_if = 0
csi_iovdd = ""
csi_avdd = ""
csi_dvdd = ""
csi_vol_iovdd =
csi_vol_dvdd =
csi_vol_avdd =
csi_vflip = 1
csi_hflip = 0
csi_flash_pol = 1
csi_facing = 0
csi_twi_id = 1
csi_twi_addr = 0x42
csi_pck = port:PG00<3><default><default><default>
csi_ck = port:PG01<3><default><default><default>
csi_hsync = port:PG02<3><default><default><default>
csi_vsync = port:PG03<3><default><default><default>
csi_d0 = port:PG04<3><default><default><default>
csi_d1 = port:PG05<3><default><default><default>
csi_d2 = port:PG06<3><default><default><default>
csi_d3 = port:PG07<3><default><default><default>
csi_d4 = port:PG08<3><default><default><default>
csi_d5 = port:PG09<3><default><default><default>
csi_d6 = port:PG10<3><default><default><default>
csi_d7 = port:PG11<3><default><default><default>
csi_reset = port:PH14<1><default><default><0>
csi_power_en =
csi_stby = port:PH17<1><default><default><0>
[csi1_para]
csi_used = 1
csi_dev_qty = 1
csi_stby_mode = 0
csi_mname = "ov7670"
csi_if = 0
csi_iovdd = ""
csi_avdd = ""
csi_dvdd = ""
csi_vol_iovdd =
csi_vol_dvdd =
csi_vol_avdd =
csi_vflip = 1
csi_hflip = 0
csi_flash_pol = 1
csi_facing = 0
csi_twi_id = 1
csi_twi_addr = 0x42
csi_pck = port:PG00<3><default><default><default>
csi_ck = port:PG01<3><default><default><default>
csi_hsync = port:PG02<3><default><default><default>
csi_vsync = port:PG03<3><default><default><default>
csi_d0 = port:PG04<3><default><default><default>
csi_d1 = port:PG05<3><default><default><default>
csi_d2 = port:PG06<3><default><default><default>
csi_d3 = port:PG07<3><default><default><default>
csi_d4 = port:PG08<3><default><default><default>
csi_d5 = port:PG09<3><default><default><default>
csi_d6 = port:PG10<3><default><default><default>
csi_d7 = port:PG11<3><default><default><default>
csi_reset = port:PH14<1><default><default><0>
csi_power_en =
csi_stby = port:PH17<1><default><default><0>
android/device/softwinner/sugar-cubieboard2/camera.cfg文件:
;-------------------------------------------------------------------------------
; 1 for single camera, 2 for double camera
;-------------------------------------------------------------------------------
number_of_camera = 1
;-------------------------------------------------------------------------------
; CAMERA_FACING_BACK
; gc0308 ov7670
;-------------------------------------------------------------------------------
camera_id = 0
;-------------------------------------------------------------------------------
; 1 for CAMERA_FACING_FRONT
; 0 for CAMERA_FACING_BACK
;-------------------------------------------------------------------------------
camera_facing = 0
;-------------------------------------------------------------------------------
; camera orientation (0, 90, 180, 270)
;-------------------------------------------------------------------------------
camera_orientation = 0
;-------------------------------------------------------------------------------
; driver device name
;-------------------------------------------------------------------------------
camera_device = /dev/video1
;-------------------------------------------------------------------------------
; device id
; for two camera devices with one CSI
;-------------------------------------------------------------------------------
device_id = 0
android/device/softwinner/sugar-cubieboard2/init.sun7i.rc文件:
# csi module
insmod /system/vendor/modules/videobuf-core.ko
insmod /system/vendor/modules/videobuf-dma-contig.ko
insmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/ov7670.ko
insmod /system/vendor/modules/sunxi_csi1.ko
#insmod /system/vendor/modules/uvcvideo.ko
android/device/softwinner/sugar-cubieboard2/ueventd.sun7i.rc文件:
# disp driver
/dev/disp 0777 system system
/dev/cedar_dev 0666 system system
/dev/ace_dev 0666 system system
/dev/ump 0777 system graphics
/dev/mali 0777 system graphics
/dev/ump 0777 system graphics
#/dev/video0 0777 system system
/dev/snd/pcmC0D0c 0777 system system
/dev/snd/pcmC0D0p 0777 system system
/dev/ttyUSB0 0777 system system
/dev/ttyUSB1 0777 system system
/dev/ttyUSB2 0777 system system
/dev/ttyUSB3 0777 system system
/dev/gps 0777 system system
/dev/pa_dev 0777 system system
/dev/g2d 0666 system system
/dev/vmouse 0666 system system
/dev/sunxi_mem 0666 media media
/dev/video1 0666 media media
重新编译内核和源码,pack,生成img文件,烧到板子上,即可打开自动的摄像头程序。
驱动成功加载成功后lsmod:
通过命令" ls /dev/ "可看到video1设备节点
内核打印信息:
三、附加说明
1、/dev/video0与/dev/video1
[csi1_para ] csi_used = 1
# csi module
insmod /system/vendor/modules/videobuf-core.ko
insmod /system/vendor/modules/videobuf-dma-contig.ko
insmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/ov7670.ko
insmod /system/vendor/modules/sunxi_csi1.ko
需要/dev/video1节点,用于ov7670摄像头。
[csi0_para ] csi_used = 1
# csi module
insmod /system/vendor/modules/videobuf-core.ko
insmod /system/vendor/modules/videobuf-dma-contig.ko
insmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/ov7670.ko
insmod /system/vendor/modules/sunxi_csi0.ko
需要/dev/video0节点,用于gc0308等摄像头。
2、csi0与csi1
ov7670模块必须使用csi1,若使用csi0,驱动会加载不成功,不会产生/dev/video0节点。因此需把sys_config.fex文件里的[csi0_para ] csi_used = 0,[csi1_para ] csi_used = 1
3、 camera_list_para_used
[camera_list_para]中的camera_list_para_used不能置为1,置为1自动加载camera.ko会不成功,手动加载系统会卡死(这个暂时不知道原因)。
camera_list_para_used的使用是为了Camera模组能实现自适应功能,从而满足一个板子能够适应不同Camera模组,开启了该功能就可以实现Camera模组的自动检测,确认板子使用的Camera模组型号并保存相关参数供后面使用,关闭该功能即可恢复Camera模组固定配置的模式(camera_list_para_used = 0),我配置时只有一个ov7670,因此采用固定配置模式。
4、/dev/video1节点设置
在camera.cfg中指定/dev/video1节点和摄像头个数number_of_camera = 1
在ueventd.sun7i.rc中加入/dev/video1 0666 media media
5、camera.ko
insmod /system/vendor/modules/videobuf-core.ko
insmod /system/vendor/modules/videobuf-dma-contig.ko
insmod /system/vendor/modules/camera.ko
insmod /system/vendor/modules/ov7670.ko
insmod /system/vendor/modules/sunxi_csi1.ko
camera.ko必须放在中间(模块间有依赖关系)。camera.ko是自动检测模块,不管camera_list_para_used是0还是1,都必须加载。如果没有camera.ko,sunxi_csi1.ko会加载不成功(这是我看过的所有有关A20摄像头配置资料都没提及的),原因是sunxi_csi1.ko依赖于camera.ko(区别于sun4i_csi1(sun4i_csi0),有关sun4i_csi的配置资料并没有加载camera.ko)。
camera_export_info存在
lichee/linux-3.4/drivers/media/video/sunxi_csi/camera_detector/camera_detect.c中。
在ubuntu下使用modinfo命令查看驱动模块的依赖:
6、调试
在windows调试时,使用360手机助手安装驱动。
adb root
adb shell
但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。
通过读写/proc/sys/kernel/printk文件可读取和修改控制台的日志级别。查看这个文件的方法如下:
#cat /proc/sys/kernel/printk
6 4 1 7
上面显示的4个数据分别对应控制台日志级别、默认的消息日志级别、最低的控制台日志级别和默认的控制台日志级别。
可用下面的命令设置当前日志级别:echo 8 > /proc/sys/kernel/printk
/proc/sys/kernel/printk
该文件可以调节printk的输出等级,文件中有四个数字值。
(1) 控制台日志级别:优先级高于该值的消息将被打印至控制台。
(2) 默认的消息日志级别:用该优先级来打印未定义优先级的消息。
(3) 最低的控制台日志级别:控制台日志界别可被设置的最小值。
(4) 默认的控制台日志级别:控制台日志级别的默认值
#define KERN_EMERG "<0>" /*紧急事件,一般是系统崩溃之前的提示消息*/
#define KERN_ALERT "<1>" /*必须立即采取行动*/
#define KERN_CRIT "<2>" /*临界状态,通常涉及严重的硬件或者软件操作失败*/
#define KERN_ERR "<3>" /*用于报告错误状态,设备驱动会经常使用KERN_ERR来报告硬件错误*/
#define KERN_WARNING "<4>" /*对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重问题 */
#define KERN_NOTICE "<5>" /*有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报*/
#define KERN_INFO "<6>" /*内核提示性信息,很多驱动程序在启动的时候以这个级别打印找到的硬件信息*/
#define KERN_DEBUG "<7>" /*用于调试信息*/
常用调试命令:
adb push D:\camera.ko /system/vendor/modules/
adb root
adb shell
cat /proc/version 查看内核版本
cat /proc/devices 列出字符和块设备的主设备号以及分配到这些设备号的设备名称
ls dev 查看可是使用的设备节点
lsmod 列出当前系统载入的模块
insmod /system/vendor/modules/camera.ko
rmsmod /system/vendor/modules/camera.ko
dmesg | grep sunxi_csi1
dmesg > /sdcard/kernel_log.txt
cat /proc/kmsg 与dmesg功能类似,dmesg只显示到目前为止的信息,而该命令会不断刷新
dmesg命令说明:
kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。开机信息亦保存在/var/log目录中,名称为dmesg的文件里。
dmesg用来显示内核环缓冲区(kernel-ring buffer)内容,内核将各种消息存放在这里。在系统引导时,内核将与硬件和模块初始化相关的信息填到这个缓冲区中。内核环缓冲区中的消息对于诊断系统问题通常非常有用。在运行dmesg时,它显示大量信息。通常通过grep使用管道查看dmesg的输出,这样可以更容易找到待查信息。
参 数:
-c 显示信息后,清除ring buffer中的内容。
-s<缓冲区大小> 预设置为8196,刚好等于ring buffer的大小。
-n 设置记录信息的层级