Foreword

Ov7670由于都是拆机货,质量太差了,所以找了个替换,GC0328C,不过GC0328C的资料比较少,很多地方没解释清楚,现成代码注释写的很少,大部分都要自己重新对一遍寄存器

GC0328C

参考仓库

https://github.com/RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi/blob/master/libraries/drivers/include/drv_gc0328c.h

https://github.com/fukuen/Maixduino_GC0328/tree/master

https://github.com/Hengbote/RT-Thread_GC0308

可以参考的板子比较多,ART-Pi,MaixPy,K210,MT62xx,MT65xx,SC6531,SP7731

多数资料里都有一个类似的图

寄存器

GC0328C的寄存器比较复杂,比较多,所以他用了一个切页的方式来切换寄存器映射

所以可以看到手册里P0:xxx P1:xxx 就是不同页的寄存器

读取和写入的时候都需要注意当前是哪一页

地址

一般GC0328地址有2种,一个是0x21,一个是0x42,其实都指同一个

21是主地址,42是加了写偏移的,43是读偏移后的地址

时钟

Timing 这里比较复杂,基本都是参考别人的设置

输出极性

输出极性,需要和配置的DMA或者DCMI,CSI等匹配上

HSYNC和VSYNC,一般设置的极性都是1有效

{0x46 , 0x03}, // SYNC_mode

在ST中这个极性和DCMI的极性设置是反过来的,需要注意一下

帧率控制

帧率主要是通过曝光时间来控制

const rt_uint8_t gc0328c_10pfs_talbe[][2] =
{
    // all AEC_EXP_LEVEL_X set to 0x51e = 1310
    {0xFE,0x01},  // page p1

    {0x2B,0x05},  // AEC_EXP_LEVEL_0 [11:8]
    {0x2C,0x1e},  // AEC_EXP_LEVEL_0 [7:0]

    {0x2D,0x05},  // AEC_EXP_LEVEL_1
    {0x2E,0x1e},

    {0x2F,0x05},  // AEC_EXP_LEVEL_2
    {0x30,0x1e},

    {0x31,0x05},  // AEC_EXP_LEVEL_3
    {0x32,0x1e},

    //{0x33,0x25},  // // AEC_EXP_MIN
    //{0x34,0x1e},
};

至于为什么1310就是10fps,暂时我也不知道,但是基于此可以调整为20fps或者5fps

目前实测如果这里填的是512,fps大概是29-30

这里就具体计算和原因没有任何说明,只能用现有代码反推了

输出格式

输出格式主要是0x44控制,一般用的多的就是RGB565和YUV422,YUV其实就是Y Cb Y Cr

YUV444,每个分量都一样,所以没啥可说的
YUV422,实际数据返回是YuYv,两个Y分别代表了2个像素,但是他们共用了一组u和v,这种方式减少了数据量,但是会有一点点失真
YUV420,实际数据返回是YYYY...uvuvuvuv,16个Y分别代表了4个像素,但是他们共用了一组u和v,这种方式减少了数据量,失真比较厉害

还有一些其他变体

UYVY 这种等于YUV422的变体形式
VYUY 这种等于YUV422的变体形式
YVYU 这种等于YUV422的变体形式

同时还会选择average neighbor chroma,会取平均色度

下面代码则是使用YUYV进行输出,并且取平均色度

{0x44 , 0x22}, // output format YUYV

输出分辨率

分辨率控制,主要是通过三个东西控制,window、crop、subsample,都会影响到最终的分辨率

Window

前面是设置行列数据的开始是什么

后面就是摄像头采样的窗口大小,下面代码中设置的大小就是0x1E8,0x288转换过来就是488x648,就是GC0328的像素矩阵大小

这个是由于Timing环节规定的,这个宽度一定是目标宽度+8

Crop

0x50控制的是否对窗口进行剪裁,默认0就是不剪裁,1是剪裁

x1和y1是指像素的剪裁起始点,后面的宽高则是剪裁大小,下面代码中的0x78,0xA0对应的就是120x160刚好是qqvga的大小

subsample

下采样模式,0x59控制下采样率,1/x,这个值越大,采样越少,代码中就是0x44,下采样就是1/4,默认值是1/1就是全采,对应的就是分辨率是最大值的几分之几。qqvga就是最大的1/4,如果是qvga则是1/2

0x5a,这个应该是采样方法,只是不知道具体是指什么

static const uint8_t qqvga_regs[][2] = {
    {0xfe , 0x00}, // page 0
    // window
    //windowing mode
    {0x09 , 0x00}, // Row start high
    {0x0a , 0x00}, // Row start low
    {0x0b , 0x00}, // Col start high
    {0x0c , 0x00}, // Col start low
    {0x0d , 0x01}, // Window height high
    {0x0e , 0xe8}, // Window height low
    {0x0f , 0x02}, // Window width high
    {0x10 , 0x88}, // Window width low
    //crop mode 
    {0x50 , 0x01}, // crop window mode enable
    {0x51 , 0x00}, // Crop _win_y1[9:8]
    {0x52 , 0x00}, // Crop _win_y1[7:0]
    {0x53 , 0x00}, // Crop _win_x1[10:8]
    {0x54 , 0x00}, // Crop _win_x1[7:0]
    {0x55 , 0x00}, // Crop _win_height[8]
    {0x56 , 0x78}, // Crop _win_height[7:0]
    {0x57 , 0x00}, // Crop _win_width[9:8]
    {0x58 , 0xA0}, // Crop _win_width[7:0]
    //subsample 1/4
    {0x59 , 0x44}, // subsample
    {0x5a , 0x03}, // Sub mode
    {0x5b , 0x00}, // Sub_row_N1
    {0x5c , 0x00}, // Sub_row_N2
    {0x5d , 0x00}, // Sub_row_N3
    {0x5e , 0x00}, // Sub_row_N4
    {0x5f , 0x00}, // Sub_col_N1
    {0x60 , 0x00}, // Sub_col_N2
    {0x61 , 0x00}, // Sub_col_N3
    {0x62 , 0x00}, // Sub_col_N4
          
    {0x00 , 0x00}
};

Summary

移植驱动主要就注意这几点,剩下大量的寄存器配置都是未知的,只能照搬

Quote

https://club.rt-thread.org/ask/question/7e46e3d50a1b6ab5.html

https://github.com/RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi/blob/master/libraries/drivers/include/drv_gc0328c.h

https://github.com/fukuen/Maixduino_GC0328/tree/master

https://github.com/Hengbote/RT-Thread_GC0308

https://blog.csdn.net/rjszcb/article/details/118728264