OV2640时钟频率和帧率的计算

2019-07-20 03:48发布

本帖最后由 lvehe 于 2016-10-11 14:56 编辑

经本人耐心搜寻和潜心研究,终于摸清了OV2640时钟频率和帧率计算的窍门。
主要依据以下2个权威资料:
《OV2640 datasheet 2.2》中图13~15分别给出UXGA、SVGA和CIF的帧时序图。
《OV2640 Camera Module Software Application Notes 1.04》中第3节“How to Adjust frame rate”中只给出了几个示例,并没有提到具体的公式。

具体来说,其中的0x3D(0xFF=0x01)会影响时钟频率,而datasheet中却是作为保留寄存器未透露任何信息。Datasheet中可查到的0x11则是影响分频系数,二者共同决定最终的时钟频率。

帧率则稍微复杂一点,帧率=时钟频率÷每行像素数÷每帧总行数÷虚拟帧数。其中 每行像素数=每行有效像素数+每行虚拟像素数。以UXGA模式为例,有效像素数为1922。虚拟像素数则为用户自定义的无效像素数。每帧总行数=每帧有效行数+每帧虚拟行数。以UXGA模式为例,每帧有效行数为1248。这里的 虚拟帧数=有效帧+虚拟帧,有效帧总为1,通常虚拟帧为0,则总的帧数为1。如果修改了0x03寄存器,一个有效帧后面可能会带上若干个无效帧,帧率就会成倍的下降。可以把虚拟像素、虚拟行数和虚拟帧认为都是用于填补行、帧之间的空隙的无效时间段。

以《OV2640 Camera Module Software Application Notes 1.04》中3.6节“UXGA Capture, 7.14fps, 24 Mhz input clock”为例:
write_SCCB(0xff, 0x01);
write_SCCB(0x11, 0x01);
write_SCCB(0x12, 0x00);
write_SCCB(0x2a, 0x00);
write_SCCB(0x2b, 0x00);
write_SCCB(0x46, 0x3f);
write_SCCB(0x47, 0x00);
write_SCCB(0x3d, 0x34);

先计算 时钟频率=24000000*(0x40-0x34)/2/2/4=18000000Hz。
再计算 帧率=18000000/(1922+0x00)/(1248+0x3f)/1=7.14fps。由于没有提到0x03寄存器的值,这里假设为默认值。


[mw_shl_code=c,true]#define  OV2640_XVCLK  24000000

uint32_t OV2640_LinePixels[3] = {1922, 595, 1190}; //UXGA, CIF, SVGA
uint32_t OV2640_FrameLines[3] = {1248, 336, 672};  //UXGA, CIF, SVGA

//获取分辨率 UXGA:0, CIF:1, SVGA:2
uint8_t OV2640_GetResMode(void)
{
        uint8_t Res;
        OV2640_WriteReg(0xFF, 0x01);
        Res = ((OV2640_ReadReg(0x12) & 0x70) >> 5);
        return Res;
}

//获取虚拟像素
uint32_t OV2640_GetDummyPixel(void)
{
        uint32_t Dummy_Pixel;
        
        OV2640_WriteReg(0xFF, 0x01);
        Dummy_Pixel = ((uint32_t)(OV2640_ReadReg(0x2A) & 0xF0) << 4) + OV2640_ReadReg(0x2B);
        return Dummy_Pixel;
}

//获取虚拟行数
uint32_t OV2640_GetDummyLines(void)
{
        uint32_t Dummy_Lines;
        
        OV2640_WriteReg(0xFF, 0x01);
        Dummy_Lines = ((uint32_t)OV2640_ReadReg(0x47) << 8) + OV2640_ReadReg(0x46);
        return Dummy_Lines;
}

//获取虚拟帧数(包括有效帧)
uint32_t OV2640_GetDummyFrame(void)
{
        uint32_t Dummy_Frame;
        
        OV2640_WriteReg(0xFF, 0x01);
        Dummy_Frame = OV2640_ReadReg(0x03) & 0xC0;
        switch (Dummy_Frame)
        {
                case 0x00:
                        Dummy_Frame = 1; //有效帧+虚拟帧
                        break;
                case 0x40:
                        Dummy_Frame = 2;
                        break;
                case 0x80:
                        Dummy_Frame = 4;
                        break;
                case 0xC0:
                        Dummy_Frame = 8;
                        break;
        }
        return Dummy_Frame;
}

// OV2640 时钟计算
// fCLK: PLL output clock
// fCLK = (0x40 - 0x3D[5:0]) * MCLK / M, where
//      M = 2 if 0x3D[7:6] = 00
//      M = 3 if 0x3D[7:6] = 01
//      M = 4 if 0x3D[7:6] = 10
//      M = 6 if 0x3D[7:6] = 11
// fINT: internal clock
// fINT = fCLK / (2 * (0x11[5:0] + 1))
// PCLK = fINT / 2
/* ---------------------------------------------------------------------------*/
float OV2640_GetPCLK(void)
{
        float PCLK;
        uint8_t  M;
        uint8_t  REG3D;
        uint8_t  Clock_Divider;
        
        OV2640_WriteReg(0xFF, 0x01);
        Clock_Divider = (OV2640_ReadReg(0x11) & 0x3F) + 1;
        
        REG3D = OV2640_ReadReg(0x3D);
        switch (REG3D & 0xC0)
        {
                case 0x00:
                        M = 2;
                        break;
                case 0x40:
                        M = 3;
                        break;
                case 0x80:
                        M = 4;
                        break;
                case 0xC0:
                        M = 6;
                        break;
        }
        
        PCLK = (float)OV2640_XVCLK * (0x40 - (REG3D & 0x3F)) / M / Clock_Divider / 4;
        return PCLK;
}

float OV2640_GetFrameRate(void)
{
        float Frame_Rate;
        uint8_t  Res;
        uint32_t Line_Pixels;
        uint32_t Frame_Lines;
        uint32_t Dummy_Frame;
        
        Res = OV2640_GetResMode();
        Line_Pixels = OV2640_LinePixels[Res] + OV2640_GetDummyPixel();
        Frame_Lines = OV2640_FrameLines[Res] + OV2640_GetDummyLines();
        Dummy_Frame = OV2640_GetDummyFrame();

        Frame_Rate = (float)OV2640_GetPCLK() / Line_Pixels / Frame_Lines / Dummy_Frame;
        return Frame_Rate;
}[/mw_shl_code]
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。