由于项目需要进行摄像头采集视频传输,方案确定采用TI公司ds90ub947+ds90ub940方案。整个方案框图如下:
在此次调试中,内核版本为3.14.52,文件系统也是从nxp官方下载的。
在整个方案中,ds947是与左边的imx6q的hdmi接口相连接,ds940输出的是MIPI_CSI格式,因此与右边的imx6q的MIPI_CSI接口相连接,ds947与ds940是高速差分串行传输。可以这样理解,相对于左边的imx6q而言,ds947相当于一个hdmi接口的显示,相对于右边的imx6q而言,ds940则是一个MIPI_CSI摄像头。在Ti的方案中,DS947是一个serializer(即串行器),而ds940是一个deserializer(即解串器)。这里要介绍的是ds940在Pattern Generator模式下MIPI_CSI输出,右边的imx6q接收显示。根据ds940的datasheet, Pattern Generator模式是不需要串行输入的一个debug方式,即ds940内部可以自行输出图像用于调试。
根据前面的方案图所示,ds940相对于右边的imx6q可看作一个MIPI_CSI摄像头,因此需要先解决ds940的驱动问题。但是由于TI官方并没有给出DS940的驱动源码,而且ds940是MIPI_CSI接口的,所以参考内核源码中ov5640_mipi.c,编写ds940的驱动源码。驱动源码主要是配置ds940 Pattern Generator模式下的一些寄存器。有关ds940 Pattern Generator模式下的相关配置,需要阅读官方手册snla132c.pdf(AN-2198 Exploring the Internal Test Pattern Generation Feature of 720p FPD-Link III Devices)。该文档是通用文档,使用于ds948,ds928,ds940等等。(手册自行到TI官方下载,或后面的链接)
在阅读snla132c.pdf时,应格外注意下面这些寄存器:
PGCTL(0x64)--该寄存器主要用于配置输出的颜 {MOD}选择以及Pattern Generator Enable,如下图:
PGCFG(0x65)--该寄存器主要用于选择24/18bit,external pixel clock/internal divided clock,its own video timing/external video timing以及Auto-Scroll Enable(滚动条模式),这里选择的是24bit,internal divided clock,its own video timing,以及Auto-Scroll disable。如下图
PGCDC(0x03)--这是一个时钟分频寄存器,当选用内部时钟,可以通过PGCDC这个寄存器进行分频,时钟源固定200M,默认分频系数为8分频 ,需要特别注意的是,这是一个间接寄存器,不能直接访问,需要通过额外的寄存器才能访问,后续会介绍。
其他的寄存器如PGRS,PGGS,PGBS这三个也是间接寄存器,用于自定义RGB颜 {MOD}的,还有一些寄存器是用于配置分辨率之类的,自行了解。
前面提到PGCDG,PGRS,PGGS,PGBS这些寄存器是间接寄存器,是无法直接访问的,需要通过额外的寄存器才能进行访问,这额外的寄存器就是PGIA(0x66),PGID(0x67)。根据手册的解释,PGIA用于存放所要访问的间接寄存器的地址,PGID存放的是所要访问的间接寄存器的值:
举例说明:要配置PGCDC(0x03)这个时钟分频寄存器,该寄存器默认8分频,现在配置为6分频,(项目方案中ds940是挂在i2c0总线下的,ds940可以通过i2c总线访问,ds940在i2c总线下的id为0x2c)步骤如下:
1。先往PGIA这个寄存器写入PGCDC的地址,即把0x03写到0x66;命令:i2cset -f -y 0 0x2c 0x66 0x03
2。再往PGID这个寄存器写入所要设定的值(即6分频,0x06),即把0x06写到0x67;命令: i2cset -f -y 0 0x2c 0x67 0x06
上面是配置间接寄存器的值,而读取间接寄存器的值方法也是一样的,即先把所要访问的间接寄存器的地址写入PGIA(0x66),然后再去读取PGID(0x67),即可获得间接寄存器的值。比如,要读取PGRS(0x00)这个间接寄存器的值,步骤如下:
1。先往PGIA写入PGRS的地址,即0x66 = 0x00,命令: i2cset -f -y 0 0x2c 0x66 0x00
2。直接读取PGID这个寄存器,所获得值就是PGRS的值:i2cget -f -y 0 0x2c 0x67
前面提到过,在整个方案中,ds940相当于一个mipi_csi摄像头,因此,其在内核中就是一个video设备。因此,必须将ds940注册为一个video设备,但是,TI官方并没有给出ds940的驱动源码,所以,只能自己手动编写ds940的驱动源码,思路是参考ov5640_mipi.c进行修改。ds940驱动源码的ioctl函数与ov5640_mipi.c基本保持一致,相关的probe函数也是大同小异,这里不再介绍,这里主要介绍ds940 Pattern Generator模式下的配置使能:这里以snla132c.pdf--4.3 Custom Display Configuration为例,其配置后的参数如下:
对应的驱动源码如下:
ds90ub940_write_reg(0x66, 0x00); //配置PGRS
msleep(100);
ds90ub940_write_reg(0x67, 0x78);
msleep(100);
ds90ub940_write_reg(0x66, 0x01); //配置PGGS
msleep(100);
ds90ub940_write_reg(0x67, 0x12);
msleep(100);
ds90ub940_write_reg(0x66, 0x02); //配置PGBS
msleep(100);
ds90ub940_write_reg(0x67, 0x22);
msleep(100);
ds90ub940_write_reg(0x66, 0x03); //配置时钟分频器,6分频
msleep(100);
ds90ub940_write_reg(0x67, 0x06);
msleep(100);
ds90ub940_write_reg(0x66, 0x07); //配置Active Horizontal Width:
msleep(100);
ds90ub940_write_reg(0x67, 0x20);
msleep(100);
ds90ub940_write_reg(0x66, 0x08); //配置Active Horizontal Width以及Active Vertical Width:
msleep(100);
ds90ub940_write_reg(0x67, 0x03);
msleep(100);
ds90ub940_write_reg(0x66, 0x09); //配置Active Vertical Width:
msleep(100);
ds90ub940_write_reg(0x67, 0x1e);
msleep(100);
ds90ub940_write_reg(0x66, 0x04); //配置Total Horizontal Width
msleep(100);
ds90ub940_write_reg(0x67, 0x98);
msleep(100);
ds90ub940_write_reg(0x66, 0x05); //配置Total Horizontal Width以及Total Vertical Width
msleep(100);
ds90ub940_write_reg(0x67, 0xd4);
msleep(100);
ds90ub940_write_reg(0x66, 0x06); //配置Total Vertical Width
msleep(100);
ds90ub940_write_reg(0x67, 0x20);
msleep(100);
ds90ub940_write_reg(0x66, 0x0c); //配置Horizontal Back Porch width
msleep(100);
ds90ub940_write_reg(0x67, 0xd8);
msleep(100);
ds90ub940_write_reg(0x66, 0x0d); //配置Vertical Back Porch Width
msleep(100);
ds90ub940_write_reg(0x67, 0x23);
msleep(100);
ds90ub940_write_reg(0x6b, 0x50); //YUV422格式输出
msleep(100);
ds90ub940_write_reg(0x65, 0x04);
msleep(100);
ds90ub940_write_reg(0x64, 0xe1); //0xe1自定义颜 {MOD}
msleep(100);
ds940 Pattern Generator模式下相关寄存器配置完成之后,还应该配置MIPI_CLOCK,有关MIPI_CLOCK的配置,需要阅读nxp官方手册AN5305.pdf(MIPI–CSI2 Peripheral on i.MX6 MPUs)--2.3.1. Bandwidth,如下图:
前面ds940的配置参数为800*480,YUV422,60fps,4-lanes,所以
Pixel clock = 800*480*59.94 fps * 1 cycle/pixel * 1.35 blank interval = 31.07MHZ(前面ds940的参数配置Pixel clock为37mhz,可以直接使用,调试时直接使用37mhz即可),Total MIPI data rate is 37 M * 16 bits = 592Mb/s,MIPI CLOCK = 592 /4 /2 = 74MHZ,MIPI_CSI2_PHY_TST_CTRL1 setting = 74 MHz * 2 (DDR mode) = 148 MHz,所以MIPI_CSI2_PHY_TST_CTRL1 = 0x42.有关MIPI_CLOCK的计算务必认真阅读AN5305.pdf这个手册。
ds940的配置参数为1920*720,YUV422,60fps,4-lanes,
Pixel clock = 1920 * 720 * 59.94 * 1 cycle/pixel * 1.35 blank interval = 111.86MHZ
Total MIPI data rate is 111.86 M * 16 bits = 1790 Mb/s
For a 4-lane interface:
MIPI clock = 1790 / 4 / 2 = 223.72MHZ
MIPI_CSI2_PHY_TST_CTRL1 setting = 223.72 MHz * 2 (DDR mode) = 447.44 MHz
MIPI_CSI2_PHY_TST_CTRL1 = 0x0C.
MIPI_CLOCK计算完成后,应该修改内核源码drivers/mxc/mipi/mxc_mipi_csi2.c---int mipi_csi2_reset(struct mipi_csi2_info *info)函数,
mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
mipi_csi2_write(info, 0x00010044, MIPI_CSI2_PHY_TST_CTRL1);
mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
// mipi_csi2_write(info, 0x00000014, MIPI_CSI2_PHY_TST_CTRL1);
//原本是0x14,为了匹配ds940时钟改成0x42,940的时钟,这里可能也需要更改
mipi_csi2_write(info, 0x00000042, MIPI_CSI2_PHY_TST_CTRL1); //对应800*480,60帧
除此之外,还应该注意mipi_csi_ipu通道的选择,参考文档Debug steps for customer MIPI sensor.docx,
IPU0-CSI0: can be connected to parallel interface(GPR1 bit19 is 1) or to mipi-csi2 virtual channel0(GPR1 bit19 is 0).
在此次调试中,MIPI选择IPU1_CSI0,因此GPR1[19]应该为0,对应源码arch/arm/mach-imx/mach-imx6q.c---static void __init imx6q_csi_mux_init(void)函数中,
if (!IS_ERR(gpr)) {
// if (of_machine_is_compatible("fsl,imx6q-sabresd") ||
// of_machine_is_compatible("fsl,imx6q-sabreauto"))
// regmap_update_bits(gpr, IOMUXC_GPR1, 1 << 19, 1 << 19);
// else if (of_machine_is_compatible("fsl,imx6dl-sabresd") ||
if (of_machine_is_compatible("fsl,imx6q-sabresd")) {
regmap_update_bits(gpr, IOMUXC_GPR1, 3 << 19, 0 << 19);
} else if (of_machine_is_compatible("fsl,imx6q-sabreauto")) {
regmap_update_bits(gpr, IOMUXC_GPR1, 3 << 19, 1 << 19);
} else if (of_machine_is_compatible("fsl,imx6dl-sabresd") ||
of_machine_is_compatible("fsl,imx6dl-sabreauto"))
// regmap_update_bits(gpr, IOMUXC_GPR13, 0x3F, 0x0C);
regmap_update_bits(gpr, IOMUXC_GPR13, 0x3F, 0x1C);
} else {
pr_err("%s(): failed to find fsl,imx6q-iomux-gpr regmap
",
__func__);
}
有关MIPI_CLOCK以及ipu_csi的选择,应该认真阅读AN5305.PDF以及Debug steps for customer MIPI sensor.docx这两份手册。完整的ds940驱动源码以及AN5305.pdf以及Debug steps for customer MIPI sensor.docx等等相关手册,后续会有链接以供下载。
源码编写修改完成之后,在编译之前,应确保menuconfig准确配置,尤其是编译成模块时,需要注意模块之间的依赖关系。与mipi_csi相关的模块主要有:mxc_mipi_csi2.ko,ipu_prp_enc.ko,ipu_bg_overlay_sdc.ko,ipu_fg_overlay_sdc.ko,ipu_csi_enc.ko,ipu_still.ko,v4l2-int-device.ko,mxc_v4l2_capture.ko,这些模块在menuconfig中的配置方式阅读NXP官方手册i.MX Linux® Reference Manual--Chapter 20 MIPI CSI2 Driver以及Chapter 6 Image Processing Unit (IPU) Drivers。
模块应该按照如下顺序加载:(模块之间有依赖关系,必须按照先后顺序加载)
insmod mxc_mipi_csi2.ko
insmod ipu_prp_enc.ko
insmod ipu_bg_overlay_sdc.ko
insmod ipu_fg_overlay_sdc.ko
insmod ipu_csi_enc.ko
insmod ipu_still.ko
insmod v4l2-int-device.ko
insmod ds90ub940_camera_mipi_int.ko //编译好的940模块
insmod mxc_v4l2_capture.ko
模块加载完成后,会有一个/dev/video0设备,该设备就是ds940,然后执行下面语句,即可看到一幅图像(下面语句是800*480,YUV422,60fps, 4-lanes),每个参数的含义可通过./mxc_v4l2_overlay.out -help查看
# cd /unit_tests
# ./mxc_v4l2_overlay.out -iw 800 -ih 480 -it 0 -il 0 -ow 800 -oh 480 -ot 0 -ol 0 -r 0 -t 50 -d 0 -fg -fr 60
源码资料链接:
https://download.csdn.net/download/qq_36731830/10909437