已有:

        在5.4版本kernel上驱动起ov2640的经验

目标:

        在6.8.12版本kernel上驱动起来GC0308

 

        计划是先仿照5.4版本的内核阶段ov2640设备树修改6.8.12版本的设备树,在6.8上先把ov2640以及ILI9341 小屏驱动起来,打通一个camera -> tft_lcd业务

 

设备树里先恢复旧项目的基础硬件:

  • 在 sun8i-v3s-licheepi-zero.dts 里启用了 spi0

  • 添加了 ILI9341 小屏节点

  • 添加了 i2c1

  • 添加了 ov2640: camera@30

  • 启用了 csi1

  • 把 ov2640_ep 和 csi1_ep 互相连接起来

menuconfig 关键项已经打开成内建:

CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
CONFIG_V4L2_FWNODE=y
CONFIG_V4L2_ASYNC=y
CONFIG_VIDEO_SUN6I_CSI=y
CONFIG_VIDEO_OV2640=y
CONFIG_VIDEO_GC0308=y
CONFIG_TINYDRM_ILI9341=y

 

中途遇到的异常与解决方法

 

1.编译时遇到过 GCC plugin 缺 gmp.h 的问题。

  原因是:

CONFIG_GCC_PLUGINS=y 
CONFIG_GCC_PLUGIN_ARM_SSP_PER_TASK=y

解决:

        它和屏幕、摄像头、CSI 无关,所以直接关掉 GCC plugins,减少无关变量。

 

2.镜像过大,卡在U-Boot 的 CONFIG_SYS_BOOTM_LEN 编译期限制

common/bootm.c 里的默认值:

解决方法:

新增v3s专用的:

#ifdef CONFIG_MACH_SUN8I_V3S
#ifndef CONFIG_SYS_BOOTM_LEN
#define CONFIG_SYS_BOOTM_LEN        (32 << 20)
#endif
#endif

 

3.uboot阶段通过,kernel阶段卡住

认为:

内核必须先驱动 eth0,才能挂载 NFS 根文件系统。现在 eth0 没出来,就会停在 rootfs 阶段。

驱动本身是打开的:

CONFIG_STMMAC_ETH=y 
CONFIG_STMMAC_PLATFORM=y 
CONFIG_DWMAC_SUN8I=y 
CONFIG_NFS_FS=y 
CONFIG_ROOT_NFS=y

怀疑6.8 的 board DTS 里漏了启用 &emac

        解决方法:

        在设备树中加入

aliases {
        serial0 = &uart0;
        ethernet0 = &emac;
    };
    chosen {
    status = "okay";
};
&emac {
    phy-handle = <&int_mii_phy>;
    phy-mode = "mii";
    allwinner,leds-active-low;
    status = "okay";
};

4.摄像头采集画面偏绿

一开始我以为是yuv字节顺序问题,就用同一份raw按照不同顺序yuv各生成一张,结果各自绿的五花八门

说明并非字节序的问题。

        检查采集指令发现,我抓到的是启动采流后的第一帧,OV2640 的自动曝光/自动白平衡还没稳定,所以会像蒙绿滤镜。

解决方法:

在指令里加 --stream-skip=20 \ 跳过前20帧

media-ctl -d /dev/media0 -V '"ov2640 0-0030":0 [fmt:UYVY8_2X8/320x240 field:none]'
media-ctl -d /dev/media0 -V '"sun6i-csi-bridge":0 [fmt:UYVY8_2X8/320x240 field:none]'
media-ctl -d /dev/media0 -V '"sun6i-csi-bridge":1 [fmt:UYVY8_2X8/320x240 field:none]'
​
v4l2-ctl -d /dev/video0 \
  --set-fmt-video=width=320,height=240,pixelformat=UYVY
​
v4l2-ctl -d /dev/video0 \
  --stream-mmap=2 \
  --stream-skip=20 \
  --stream-count=1 \
  --stream-to=/tmp/ov2640_lcd.uyvy
​
ffmpeg -y \
  -f rawvideo -pix_fmt uyvy422 -s 320x240 \
  -i /tmp/ov2640_lcd.uyvy \
  -vf "transpose=1,format=bgra" \
  -pix_fmt bgra \
  -f fbdev /dev/fb0

 

至此,证明Linux 6.8.12下摄像头主链路已经打通

 

后续思路

  1. 已验证当前 OV2640 可用。

  2. 修改设备树,把 OV2640 换成 GC0308。

  3. 只验证 GC0308 是否 probe 成功,目标是读到 chip ID = 0x9b。

  4. probe 成功后,再验证 media graph。

  5. media graph 正常后,再抓 UYVY raw。

  6. raw 有真实图像后,再显示到 LCD。

  7. 如果有帧但花屏/固定色,再处理 CSI 采样极性

 

根据galaxycore,gc0308.yaml

        GC0308 驱动要找的是 reset-gpios 和 powerdown-gpios,不是 OV2640 那套 resetb-gpios/pwdn-gpios;

MCLK 的 pinctrl-0 = <&csi1_mclk_pin> 应该放到 GC0308 节点里;

GC0308 是 8bit DVP,CSI 端不要再用为 OV2640 做的 10bit 引脚组。

 

        GPIO 名字要换成 GC0308 驱动认识的,MCLK 要让 GC0308 自己持有,CSI 数据线要按 GC0308 的 8bit DVP 来配。

 

修改mclk属性

ov2640的设备树写法是把 csi1_mclk_pin 放在 &csi1 下面:

&csi1 {
    pinctrl-0 = <&csi1_8bit_pins>, <&csi1_mclk_pin>;
    status = "okay";
};

        问题是:&csi1 是 CSI 控制器这个 platform device。这个 pinctrl 状态只有在 CSI 控制器设备 被 probe、并选择 default pinctrl 状态时才会应用。它不会因为 DTS 里出现了 csi1_mclk_pin,就自动全局把 PE1 切成 MCLK 输出。

        但 GC0308 更早、更直接需要 MCLK 的时机是在 GC0308 自己的 I2C probe 阶段

gc0308 probe
  -> power_on
  -> enable xclk
  -> release reset / pwdn
  -> read chip ID over I2C

        GC0308 这种 sensor 的 SCCB/I2C 从机逻辑通常依赖外部 MCLK。如果 probe 阶段 PE1 还没有被 pinmux 成 MCLK,即使驱动里打印:

gc0308 debug: xclk enabled, rate=24000000

        也只能说明 CCU 里的 CSI1_MCLK 这个 clock 被打开了,频率设置成 24MHz,不代表这个 24MHz 已经真的从 PE1 管脚输出。

        所以旧设备树的隐患是:时钟源打开了,但管脚复用可能还没切过去。

        修复的思路是让 GC0308 这个 I2C client 自己持有 MCLK pinctrl:

&i2c1 {
    gc0308: camera-sensor@21 {
        compatible = "galaxycore,gc0308";
        reg = <0x21>;
​
        pinctrl-names = "default";
        pinctrl-0 = <&csi1_mclk_pin>;
​
        clocks = <&ccu CLK_CSI1_MCLK>;
        assigned-clocks = <&ccu CLK_CSI1_MCLK>;
        assigned-clock-rates = <24000000>;
    };
};

        这样在 gc0308 0-0021 这个设备 probe 之前或 probe 过程中,Linux 设备核心会给 GC0308 这个设备 应用 default pinctrl,PE1 会先被切到 CSI/MCLK 功能。随后 GC0308 驱动再 clk_prepare_enable(),24MHz 才能真正从 MCLK 管脚出来。

        修复后, GC0308节点自己持有MCLK pinctrl,以及实测MCK管脚 Freq = 24.06MHz

       这一部分总结就是: GC0308 在 I2C probe 阶段 就需要 MCLK。它要先有外部时钟,内部 I2C/SCCB 逻辑才可靠工作,然后驱动才能读 chip ID。所以 MCLK 这根 PE1 管脚不应该只挂在 &csi1 下面,而应该挂到 GC0308 设备节点里.

        目前为止的设备树修改思路

resetb-gpios -> reset-gpios

pwdn-gpios -> powerdown-gpios

MCLK pinctrl 放进 gc0308 节点 assigned-clock-rates 改成 24000000

去掉 clock-names = "xvclk"

补 vdd28-supply

GC0308 endpoint 改成 8bit + data-shift/hsync/vsync/pclk

&csi1 不再持有 csi1_mclk_pin

 

但是上电之后gc0308的采集业务仍然并不理想

 

怀疑:像素格式问题 或者 同步极性问题

查了一下raw原始数据,发现前面大量固定值

 

因此并非像之前ov2640遇到过的像素格式问题,而是csi极性问题

此时Vsync和Href同步信号(行同步与帧同步)的波形以及极性如下:

 

 

最终关键点:

真正让绿屏, 白屏, 固定色变成正常图像的修改在sun6i-csi并口极性

最终dmesg中应看到IF_CFG=0x00070000

 

翻转了VSYNC和HREF极性,立刻见效

 

 

 

此时波形以及设备树;

 总结:

         嵌入式 Linux 外设调试不能只看“驱动有没有起来”,要把 设备树 binding、pinctrl 归属、clock 物理输出、media graph、DMA 内存、像素格式、总线极性 全部串起来验证;每一层都用可观测证据确认,把问题从“玄学”拆成可解决的小问题。

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐