Author Topic: OV7670 color settings  (Read 5940 times)

0 Members and 1 Guest are viewing this topic.

Offline AxkTopic starter

  • Regular Contributor
  • *
  • Posts: 221
  • Country: by
OV7670 color settings
« on: February 03, 2019, 03:31:32 pm »
Outputting from OV7670 in VGA@30FPS in YUV 4:2:2 (through a frame buffer to a VGA monitor 640x480@60FPS)
The only register I changed is 0x11 setting it to 0x00 to enable the PLL with the multiplier of 1 which gives a MUCH better image in terms of noise.

The colors are fine with the camera's test pattern (register 0x71 set to 0xC0) so my conversion from YUV to RGB is correct.
The problem is that it gives me wrong colors on the real video. Gives green instead of red, white instead of yellow.
I suppose it has to do with the color matrix registers, but I've not been able to figure out the correct values.

Has anyone found the correct register values to get correct colors out of OV7670?

(The monitor is showing the bottom facet of the cube)
« Last Edit: February 03, 2019, 03:53:52 pm by Axk »
 

Offline AxkTopic starter

  • Regular Contributor
  • *
  • Posts: 221
  • Country: by
Re: OV7670 color settings
« Reply #1 on: February 03, 2019, 08:54:52 pm »
This was a combination of swapping Cr and Cb when taken from the camera and the following register values that I found thanks to another user's comment (elecdev's comment at https://thinksmallthings.wordpress.com/2012/11/03/ov7670-yuv-demystified/comment-page-1/)

The register values are

0x11 0x01
0x6B 0x4A
0x0E 0x61
0x0F 0x4B
0x16 0x02
0x1E 0x07
0x21 0x02
0x22 0x91
0x29 0x07
0x33 0x0B
0x35 0x0B
0x37 0x1D
0x38 0x71
0x39 0x2A
0x3C 0x78
0x4D 0x40
0x4E 0x20
0x69 0x00
0x74 0x10
0x8D 0x4F
0x8E 0x00
0x8F 0x00
0x90 0x00
0x91 0x00
0x96 0x00
0x9A 0x00
0xB0 0x84
0xB1 0x0C
0xB2 0x0E
0xB3 0x82
0xB8 0x0A

The left column is the register address and the right column is the value.

The slave address for write is 0x42.

This is for a 24MHz XCLK which the PLL first divides by 4 (the first register in the list) and then multiplies by 4 (the second register in the list), this results in the same 24MHz but it is much better than without the PLL, I suppose jitter or other clock parameters matter, so the clock from my FPGA is not directly usable by the camera chip without putting it through the PLL first.
The order you set the first 2 registers is important.
« Last Edit: February 16, 2019, 03:32:32 pm by Axk »
 

Offline AxkTopic starter

  • Regular Contributor
  • *
  • Posts: 221
  • Country: by
Re: OV7670 color settings
« Reply #2 on: February 17, 2019, 08:46:15 pm »
Here's probably a better version, I'm not sure, but the colors appear to look better.
The colors don't look realistic under incandescent light, look much better under a while LED (phone torch).
This is mostly based on this github driver's values: https://github.com/yandex/smart/blob/master/drivers/media/i2c/ov7670.c

        public const byte REG_GAIN = 0x00;  /* Gain lower 8 bits (rest in vref) */
        public const byte REG_BLUE = 0x01;  /* blue gain */
        public const byte REG_RED = 0x02;   /* red gain */
        public const byte REG_VREF = 0x03;  /* Pieces of GAIN, VSTART, VSTOP */
        public const byte REG_COM1 = 0x04;  /* Control 1 */
        public const byte COM1_CCIR656 = 0x40;  /* CCIR656 enable */
        public const byte REG_BAVE = 0x05;  /* U/B Average level */
        public const byte REG_GbAVE = 0x06; /* Y/Gb Average level */
        public const byte REG_AECHH = 0x07; /* AEC MS 5 bits */
        public const byte REG_RAVE = 0x08;  /* V/R Average level */
        public const byte REG_COM2 = 0x09;  /* Control 2 */
        public const byte COM2_SSLEEP = 0x10;   /* Soft sleep mode */
        public const byte REG_PID = 0x0a;   /* Product ID MSB */
        public const byte REG_VER = 0x0b;   /* Product ID LSB */
        public const byte REG_COM3 = 0x0c;  /* Control 3 */
        public const byte COM3_SWAP = 0x40;   /* Byte swap */
        public const byte COM3_SCALEEN = 0x08;    /* Enable scaling */
        public const byte COM3_DCWEN = 0x04;      /* Enable downsamp/crop/window */
        public const byte REG_COM4 = 0x0d;  /* Control 4 */
        public const byte REG_COM5 = 0x0e;  /* All "reserved" */
        public const byte REG_COM6 = 0x0f;  /* Control 6 */
        public const byte REG_AECH = 0x10;  /* More bits of AEC value */
        public const byte REG_CLKRC = 0x11; /* Clocl control */
        public const byte CLK_EXT = 0x40;     /* Use external clock directly */
        public const byte CLK_SCALE = 0x3f;   /* Mask for internal clock scale */
        public const byte REG_COM7 = 0x12;  /* Control 7 */
        public const byte COM7_RESET = 0x80;      /* Register reset */
        public const byte COM7_FMT_MASK = 0x38;
        public const byte COM7_FMT_VGA = 0x00;
        public const byte COM7_FMT_CIF = 0x20;    /* CIF format */
        public const byte COM7_FMT_QVGA = 0x10;   /* QVGA format */
        public const byte COM7_FMT_QCIF = 0x08;   /* QCIF format */
        public const byte COM7_RGB = 0x04;    /* bits 0 and 2 - RGB format */
        public const byte COM7_YUV = 0x00;    /* YUV */
        public const byte COM7_BAYER = 0x01;      /* Bayer format */
        public const byte COM7_PBAYER = 0x05;     /* "Processed bayer" */
        public const byte REG_COM8 = 0x13;  /* Control 8 */
        public const byte COM8_FASTAEC = 0x80;    /* Enable fast AGC/AEC */
        public const byte COM8_AECSTEP = 0x40;    /* Unlimited AEC step size */
        public const byte COM8_BFILT = 0x20;      /* Band filter enable */
        public const byte COM8_AGC = 0x04;    /* Auto gain enable */
        public const byte COM8_AWB = 0x02;    /* White balance enable */
        public const byte COM8_AEC = 0x01;    /* Auto exposure enable */
        public const byte REG_COM9 = 0x14;  /* Control 9  - gain ceiling */
        public const byte REG_COM10 = 0x15; /* Control 10 */
        public const byte COM10_HSYNC = 0x40;     /* HSYNC instead of HREF */
        public const byte COM10_PCLK_HB = 0x20;   /* Suppress PCLK on horiz blank */
        public const byte COM10_HREF_REV = 0x08;      /* Reverse HREF */
        public const byte COM10_VS_LEAD = 0x04;   /* VSYNC on clock leading edge */
        public const byte COM10_VS_NEG = 0x02;    /* VSYNC negative */
        public const byte COM10_HS_NEG = 0x01;    /* HSYNC negative */
        public const byte REG_HSTART = 0x17;    /* Horiz start high bits */
        public const byte REG_HSTOP = 0x18; /* Horiz stop high bits */
        public const byte REG_VSTART = 0x19;    /* Vert start high bits */
        public const byte REG_VSTOP = 0x1a; /* Vert stop high bits */
        public const byte REG_PSHFT = 0x1b; /* Pixel delay after HREF */
        public const byte REG_MIDH = 0x1c;  /* Manuf. ID high */
        public const byte REG_MIDL = 0x1d;  /* Manuf. ID low */
        public const byte REG_MVFP = 0x1e;  /* Mirror / vflip */
        public const byte MVFP_MIRROR = 0x20;     /* Mirror image */
        public const byte MVFP_FLIP = 0x10;   /* Vertical flip */
        public const byte REG_AEW = 0x24;   /* AGC upper limit */
        public const byte REG_AEB = 0x25;   /* AGC lower limit */
        public const byte REG_VPT = 0x26;   /* AGC/AEC fast mode op region */
        public const byte REG_HSYST = 0x30; /* HSYNC rising edge delay */
        public const byte REG_HSYEN = 0x31; /* HSYNC falling edge delay */
        public const byte REG_HREF = 0x32;  /* HREF pieces */
        public const byte REG_TSLB = 0x3a;  /* lots of stuff */
        public const byte TSLB_YLAST = 0x04;      /* UYVY or VYUY - see com13 */
        public const byte REG_COM11 = 0x3b; /* Control 11 */
        public const byte COM11_NIGHT = 0x80;     /* NIght mode enable */
        public const byte COM11_NMFR = 0x60;      /* Two bit NM frame rate */
        public const byte COM11_HZAUTO = 0x10;    /* Auto detect 50/60 Hz */
        public const byte COM11_50HZ = 0x08;      /* Manual 50Hz select */
        public const byte COM11_EXP = 0x02;
        public const byte REG_COM12 = 0x3c; /* Control 12 */
        public const byte COM12_HREF = 0x80;      /* HREF always */
        public const byte REG_COM13 = 0x3d; /* Control 13 */
        public const byte COM13_GAMMA = 0x80;     /* Gamma enable */
        public const byte COM13_UVSAT = 0x40;     /* UV saturation auto adjustment */
        public const byte COM13_UVSWAP = 0x01;    /* V before U - w/TSLB */
        public const byte REG_COM14 = 0x3e; /* Control 14 */
        public const byte COM14_DCWEN = 0x10;     /* DCW/PCLK-scale enable */
        public const byte REG_EDGE = 0x3f;  /* Edge enhancement factor */
        public const byte REG_COM15 = 0x40; /* Control 15 */
        public const byte COM15_R10F0 = 0x00;     /* Data range 10 to F0 */
        public const byte COM15_R01FE = 0x80;     /*            01 to FE */
        public const byte COM15_R00FF = 0xc0;     /*            00 to FF */
        public const byte COM15_RGB565 = 0x10;    /* RGB565 output */
        public const byte COM15_RGB555 = 0x30;    /* RGB555 output */
        public const byte REG_COM16 = 0x41; /* Control 16 */
        public const byte COM16_AWBGAIN = 0x08;   /* AWB gain enable */
        public const byte REG_COM17 = 0x42; /* Control 17 */
        public const byte COM17_AECWIN = 0xc0;    /* AEC window - must match COM4 */
        public const byte COM17_CBAR = 0x08;      /* DSP Color bar */
        public const byte REG_CMATRIX_BASE = 0x4f;
        public const byte REG_CMATRIX_SIGN = 0x58;
        public const byte REG_BRIGHT = 0x55;    /* Brightness */
        public const byte REG_CONTRAS = 0x56;   /* Contrast control */
        public const byte REG_GFIX = 0x69;  /* Fix gain control */
        public const byte REG_DBLV = 0x6b;  /* PLL control an debugging */
        public const byte DBLV_BYPASS = 0x00;     /* Bypass PLL */
        public const byte DBLV_X4 = 0x01;     /* clock x4 */
        public const byte DBLV_X6 = 0x10;     /* clock x6 */
        public const byte DBLV_X8 = 0x11;     /* clock x8 */
        public const byte REG_SCALING_XSC = 0x70;   /* Test pattern and horizontal scale factor */
        public const byte TEST_PATTTERN_0 = 0x80;
        public const byte REG_SCALING_YSC = 0x71;   /* Test pattern and vertical scale factor */
        public const byte TEST_PATTTERN_1 = 0x80;
        public const byte REG_REG76 = 0x76; /* OV's name */
        public const byte R76_BLKPCOR = 0x80;     /* Black pixel correction enable */
        public const byte R76_WHTPCOR = 0x40;     /* White pixel correction enable */
        public const byte REG_RGB444 = 0x8c;    /* RGB 444 control */
        public const byte R444_ENABLE = 0x02;     /* Turn on RGB444, overrides 5x5 */
        public const byte R444_RGBX = 0x01;   /* Empty nibble at end */
        public const byte REG_HAECC1 = 0x9f;    /* Hist AEC/AGC control 1 */
        public const byte REG_HAECC2 = 0xa0;    /* Hist AEC/AGC control 2 */
        public const byte REG_BD50MAX = 0xa5;   /* 50hz banding step limit */
        public const byte REG_HAECC3 = 0xa6;    /* Hist AEC/AGC control 3 */
        public const byte REG_HAECC4 = 0xa7;    /* Hist AEC/AGC control 4 */
        public const byte REG_HAECC5 = 0xa8;    /* Hist AEC/AGC control 5 */
        public const byte REG_HAECC6 = 0xa9;    /* Hist AEC/AGC control 6 */
        public const byte REG_HAECC7 = 0xaa;    /* Hist AEC/AGC control 7 */
        public const byte REG_BD60MAX = 0xab;   /* 60hz banding step limit */

        public static byte[,] RegValues = new byte[,] {

{ 0x42, REG_COM7, COM7_RESET },
{   0x42, REG_CLKRC, 0x01 },
{   0x42, 0x6B, 0x4A },
{   0x42, REG_COM7, 0x00 },
{   0x42, REG_HSTART, 0x13 },
{   0x42, REG_HSTOP, 0x01 },
{   0x42, REG_HREF, 0xb6 },
{   0x42, REG_VSTART, 0x02 },
{   0x42, REG_VSTOP, 0x7a },
{   0x42, REG_VREF, 0x0a },
{   0x42, REG_COM3, 0x00 },
{   0x42, REG_COM14, 0x00 },
{   0x42, REG_SCALING_XSC, 0x3a },
{   0x42, REG_SCALING_YSC, 0x35 },
{   0x42, 0x72, 0x11 },
{   0x42, 0x73, 0xf0 },
{   0x42, 0xa2, 0x02 },
{   0x42, REG_COM10, 0x00 },
{   0x42, 0x7a, 0x20 },
{   0x42, 0x7b, 0x10 },
{   0x42, 0x7c, 0x1e },
{   0x42, 0x7d, 0x35 },
{   0x42, 0x7e, 0x5a },
{   0x42, 0x7f, 0x69 },
{   0x42, 0x80, 0x76 },
{   0x42, 0x81, 0x80 },
{   0x42, 0x82, 0x88 },
{   0x42, 0x83, 0x8f },
{   0x42, 0x84, 0x96 },
{   0x42, 0x85, 0xa3 },
{   0x42, 0x86, 0xaf },
{   0x42, 0x87, 0xc4 },
{   0x42, 0x88, 0xd7 },
{   0x42, 0x89, 0xe8 },
{   0x42, REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT },
{   0x42, REG_GAIN, 0x00 },
{   0x42, REG_AECH, 0x00 },
{   0x42, REG_COM4, 0x40 },
{   0x42, REG_COM9, 0x18 },
{   0x42, REG_BD50MAX, 0x05 },
{   0x42, REG_BD60MAX, 0x07 },
{   0x42, REG_AEW, 0x95 },
{   0x42, REG_AEB, 0x33 },

{   0x42, REG_VPT, 0xe3 },
{   0x42, REG_HAECC1, 0x78 },
{   0x42, REG_HAECC2, 0x68 },
{   0x42, 0xa1, 0x03 },
{   0x42, REG_HAECC3, 0xd8 },
{   0x42, REG_HAECC4, 0xd8 },
{   0x42, REG_HAECC5, 0xf0 },
{   0x42, REG_HAECC6, 0x90 },
{   0x42, REG_HAECC7, 0x94 },
{   0x42, REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC },

{   0x42, REG_COM5, 0x61 },
{   0x42, REG_COM6, 0x4b },
{   0x42, 0x16, 0x02 },
{   0x42, REG_MVFP, 0x07 },
{   0x42, 0x21, 0x02 },
{   0x42, 0x22, 0x91 },
{   0x42, 0x29, 0x07 },

{   0x42, 0x33, 0x0b },
{   0x42, 0x35, 0x0b },
{   0x42, 0x37, 0x1d },
{   0x42, 0x38, 0x71 },
{   0x42, 0x39, 0x2a },
{   0x42, REG_COM12, 0x78 },
{   0x42, 0x4d, 0x40 },
{   0x42, 0x4e, 0x20 },
{   0x42, REG_GFIX, 0x00 },
{   0x42, 0x6b, 0x4a },
{   0x42, 0x74, 0x10 },

{   0x42, 0x8d, 0x4f },
{   0x42, 0x8e, 0x00 },
{   0x42, 0x8f, 0x00 },
{   0x42, 0x90, 0x00 },
{   0x42, 0x91, 0x00 },
{   0x42, 0x96, 0x00 },
{   0x42, 0x9a, 0x00 },
{   0x42, 0xb0, 0x84 },
{   0x42, 0xb1, 0x0c },
{   0x42, 0xb2, 0x0e },
{   0x42, 0xb3, 0x82 },
{   0x42, 0xb8, 0x0a },
{   0x42, 0x43, 0x0a },
{   0x42, 0x44, 0xf0 },
{   0x42, 0x45, 0x34 },
{   0x42, 0x46, 0x58 },

{   0x42, 0x47, 0x28 },
{   0x42, 0x48, 0x3a },
{   0x42, 0x59, 0x88 },
{   0x42, 0x5a, 0x88 },
{   0x42, 0x5b, 0x44 },
{   0x42, 0x5c, 0x67 },
{   0x42, 0x5d, 0x49 },
{   0x42, 0x5e, 0x0e },
{   0x42, 0x6c, 0x0a },
{   0x42, 0x6d, 0x55 },
{   0x42, 0x6e, 0x11 },
{   0x42, 0x6f, 0x9f },
{   0x42, 0x6a, 0x40 },
{   0x42, REG_BLUE, 0x40 },
{   0x42, REG_RED, 0x60 },
{   0x42, REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB },
{   0x42, 0x4f, 0x80 },
{   0x42, 0x50, 0x80 },
{   0x42, 0x51, 0x00 },
{   0x42, 0x52, 0x22 },
{   0x42, 0x53, 0x5e },
{   0x42, 0x54, 0x80 },
{   0x42, 0x58, 0x9e },
{   0x42, REG_COM16, COM16_AWBGAIN },
{   0x42, REG_EDGE, 0x00 },
{   0x42, 0x75, 0x05 },
{   0x42, 0x76, 0xe1 },
{   0x42, 0x4c, 0x00 },

{   0x42, 0x77, 0x01 },
{   0x42, REG_COM13, 0xc3 },
{   0x42, 0x4b, 0x09 },
{   0x42, 0xc9, 0x60 },
{   0x42, REG_COM16, 0x38 },
{   0x42, 0x56, 0x40 },
{   0x42, 0x34, 0x11 },
{   0x42, REG_COM11, COM11_EXP|COM11_HZAUTO },
{   0x42, 0xa4, 0x88 },
{   0x42, 0x96, 0x00 },
{   0x42, 0x97, 0x30 },
{   0x42, 0x98, 0x20 },
{   0x42, 0x99, 0x30 },
{   0x42, 0x9a, 0x84 },
{   0x42, 0x9b, 0x29 },
{   0x42, 0x9c, 0x03 },
{   0x42, 0x9d, 0x4c },
{   0x42, 0x9e, 0x3f },
{   0x42, 0x78, 0x04 },
{   0x42, 0x79, 0x01 },
{   0x42, 0xc8, 0xf0 },
{   0x42, 0x79, 0x0f },
{   0x42, 0xc8, 0x00 },
{   0x42, 0x79, 0x10 },
{   0x42, 0xc8, 0x7e },
{   0x42, 0x79, 0x0a },
{   0x42, 0xc8, 0x80 },
{   0x42, 0x79, 0x0b },
{   0x42, 0xc8, 0x01 },
{   0x42, 0x79, 0x0c },
{   0x42, 0xc8, 0x0f },
{   0x42, 0x79, 0x0d },
{   0x42, 0xc8, 0x20 },
{   0x42, 0x79, 0x09 },
{   0x42, 0xc8, 0x80 },
{   0x42, 0x79, 0x02 },
{   0x42, 0xc8, 0xc0 },
{   0x42, 0x79, 0x03 },
{   0x42, 0xc8, 0x40 },
{   0x42, 0x79, 0x05 },
{   0x42, 0xc8, 0x30 },
{   0x42, 0x79, 0x26 },
{   0x42, 0xff, 0xff },
{   0x42, REG_COM7, 0x00 },
{   0x42, REG_RGB444, 0x00 },
{   0x42, REG_COM1, 0x00 },
{   0x42, REG_COM15, COM15_R00FF },
{   0x42, REG_COM9, 0x48 },
{   0x42, 0x4f, 0x80 },
{   0x42, 0x50, 0x80 },
{   0x42, 0x51, 0x00  },
{   0x42, 0x52, 0x22 },
{   0x42, 0x53, 0x5e },
{   0x42, 0x54, 0x80 },
{   0x42, REG_COM13, COM13_GAMMA|COM13_UVSAT }

};

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf