关于在全志v3s驱动gc0308摄像头模块的过程
已有:
在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下摄像头主链路已经打通
后续思路
已验证当前 OV2640 可用。
修改设备树,把 OV2640 换成 GC0308。
只验证 GC0308 是否 probe 成功,目标是读到 chip ID = 0x9b。
probe 成功后,再验证 media graph。
media graph 正常后,再抓 UYVY raw。
raw 有真实图像后,再显示到 LCD。
如果有帧但花屏/固定色,再处理 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 +>
怀疑:像素格式问题 或者 同步极性问题
查了一下raw原始数据,发现前面大量固定值
因此并非像之前ov2640遇到过的像素格式问题,而是csi极性问题
此时Vsync和Href同步信号(行同步与帧同步)的波形以及极性如下:
最终关键点:
真正让绿屏, 白屏, 固定色变成正常图像的修改在sun6i-csi并口极性
最终dmesg中应看到IF_CFG=0x00070000
翻转了VSYNC和HREF极性,立刻见效
此时波形以及设备树;
总结:
嵌入式 Linux 外设调试不能只看“驱动有没有起来”,要把设备树 binding、pinctrl 归属、clock 物理输出、media graph、DMA 内存、像素格式、总线极性全部串起来验证;每一层都用可观测证据确认,把问题从“玄学”拆成可解决的小问题。
