正点原子 IMX6ULL移植OV5640驱动

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-gpiosrst-gpiosport必须完全一致。

  • 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.koms6s_capture.ko。、

  • 动态加载

开发板上插上摄像头.动态加载他们即可。注意,先加载ov5640.ko,出现图中的打印信息说明驱动装载成功

在这里插入图片描述

2. 测试程序

使用下面提供的测试程序,我使用的分辨率是800 x 480,使用其他分辨率请阅读源码并修改,重点是修改 height widthv4l2_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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值