0.实验平台
使用的是 正点原子的IMX6LL + 1024 x 600的屏幕
系统是自己根据busybox移植的根文件系统
Linux内核是根据NXP官方结合正点原子教程修改而来 设备树也是
1.驱动移植
先说结论:
- 不需要去 LINUX图像化界面配置和使能里面的驱动
- 需要使用正点原子出厂的相关驱动
1.1 修改设备树
使用正点原子的板子肯定得照他们的板子来修改设备树。在自己的设备树下,做如下修改
- 修改 ov5640节点
ov5640: ov5640@3c {
compatible = "ovti,ov5640";
reg = <0x3c>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_csi1
&csi_pwn_rst>;
clocks = <&clks IMX6UL_CLK_CSI>;
clock-names = "csi_mclk";
pwn-gpios = <&gpio1 4 1>;
rst-gpios = <&gpio1 2 0>;
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
status = "okay";
port {
camera_ep: endpoint {
remote-endpoint = <&csi_ep>;
};
};
};
需要注意,修改的pinctrl-0 pwn-gpios和rst-gpios和port必须完全一致。
pinctrl-0节点
pinctrl_csi1: csi1grp {
fsl,pins = <
MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088
MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088
MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088
MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088
MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088
MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088
MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088
MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
>;
};
csi_pwn_rst: csi_pwn_rstgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0x10b0
MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x10b0
>;
};
csi
&csi {
status = "okay";
port {
csi_ep: endpoint {
remote-endpoint = <&camera_ep>;
};
};
};
1.2 驱动模块编译
原厂的驱动是不能用的,原厂的这个驱动也是以模块化形式编译进去的,不需要去修改要编译的内核驱动源码,我们找到正点原子出厂的内核源码的相关代码,以模块化形式编译,在动态加载即可,不要搞那么复杂。
- 首先找到需要模块化编译的代码位置。使用
fine -name ov5640.c找打模块的源代码位置.我的如下
./drivers/media/platform/mxc/subdev/ov5640.c
-
去正点原子出厂系统的内核源码下
subdev,复制所有文件到一个文件夹下,创建一个驱动工程。 -
模块化编译
Makefile文件如下
export ARCH := arm
export CROSS_COMPILE := arm-linux-gnueabihf-
KERNELDIR := /home/constant_z/linux/IMX6ULL/linux/nxp_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
POJECT_NAME := ov5640test
CURRENT_PATH := $(shell pwd)
obj-m := ov5640.o mx6s_capture.o
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
重点就是我们生成的ov5640.ko和ms6s_capture.ko。、
- 动态加载
开发板上插上摄像头.动态加载他们即可。注意,先加载ov5640.ko,出现图中的打印信息说明驱动装载成功

2. 测试程序
使用下面提供的测试程序,我使用的分辨率是800 x 480,使用其他分辨率请阅读源码并修改,重点是修改 height width和v4l2_read_data中的行列更新方式
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#define FB_DEV "/dev/fb0" //LCD设备节点
#define FRAMEBUFFER_COUNT 4 //帧缓冲数量
/*** 摄像头像素格式及其描述信息 ***/
typedef struct camera_format {
unsigned char description[32]; //字符串描述信息
unsigned int pixelformat; //像素格式
} cam_fmt;
/*** 描述一个帧缓冲的信息 ***/
typedef struct cam_buf_info {
unsigned short *start; //帧缓冲起始地址
unsigned long length; //帧缓冲长度
} cam_buf_info;
static int width; //LCD宽度
static int height; //LCD高度
static unsigned short *screen_base = NULL;//LCD显存基地址
static int fb_fd = -1; //LCD设备文件描述符
static int v4l2_fd = -1; //摄像头设备文件描述符
static cam_buf_info buf_infos[FRAMEBUFFER_COUNT];
static cam_fmt cam_fmts[10];
static int frm_width, frm_height; //视频帧宽度和高度
static int fb_dev_init(void)
{
struct fb_var_screeninfo fb_var = {
0};
struct fb_fix_screeninfo fb_fix = {
0};
unsigned long screen_size;
/* 打开framebuffer设备 */
fb_fd = open(FB_DEV, O_RDWR);
if (0 > fb_fd) {
fprintf(stderr, "open error: %s: %s\n", FB_DEV, strerror(errno));
return -1;
}
/* 获取framebuffer设备信息 */
ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);
screen_size = fb_fix.line_length * fb_var.yres;
//width = fb_var.xres;
//height = fb_var.yres;
width = 800;
height = 480;
/* 内存映射 */
screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (MAP_FAILED == (void *)screen_base) {
perror("mmap error");
close(fb_fd);
return -1;
}
/* LCD背景刷白 */
memset(screen_base, 0xFF, screen_size);
return 0;
}
static int v4l2_dev_init(const char *device)
{
struct v4l2_capability cap = {
0};
/* 打开摄像头 */
v4l2_fd = open(device, O_RDWR);
if (0 > v4l2_fd) {
fprintf(stderr, "open error: %s: %s\n", device, strerror(errno));
return -1;
}
/* 查询设备功能 */
ioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap);
/* 判断是否是视频采集设备 */
if (!(V4L2_CAP_VIDEO_CAPTURE & cap.capabilities)) {
fprintf(stderr, "Error: %s: No capture video device!\n", device);
close(v4l2_fd);
return -1;
}
if((cap.capabilities & V4L2_MEMORY_MMAP) == 0){
fprintf(stderr, "Error: %s: No V4L2_MEMORY_MMAP video device!\n", device

最低0.47元/天 解锁文章
2336






