#ifndef __ov7670_H__ #define __ov7670_H__ __ov7670_H__ #include #include #include #include "twi.h" static const uint8_t OV7670_ADDRESS = 0x42; void ov7670_init(void); struct ov7670_register { uint8_t reg_num; uint8_t value; }; static inline uint8_t ov7670_write8(uint8_t reg, uint8_t value) { uint8_t data[2] = {reg, value}; return twi_write(OV7670_ADDRESS, data, 2); } static inline uint8_t ov7670_vsync(void) { return (PINC & (1 << PC0)) != 0; } static inline void ov7670_wait_vsync(void) { while (ov7670_vsync()) ; // Wait until low while (!ov7670_vsync()) ; // Wait until high } static inline void ov7670_set_rst(void) { PORTD |= (1 << PD3); } static inline void ov7670_unset_rst(void) { PORTD &= ~(1 << PD3); } static inline void ov7670_set_wrst(void) { PORTC |= (1 << PC3); } static inline void ov7670_unset_wrst(void) { PORTC &= ~(1 << PC3); } static inline void ov7670_toggle_wrst(void) { ov7670_set_wrst(); _delay_us(5); ov7670_unset_wrst(); } static inline void ov7670_set_rrst(void) { PORTC |= (1 << PC2); } static inline void ov7670_unset_rrst(void) { PORTC &= ~(1 << PC2); } static inline void ov7670_toggle_rrst(void) { ov7670_set_rrst(); _delay_us(5); ov7670_unset_rrst(); } static inline void ov7670_set_we(void) { PORTC |= (1 << PC1); } static inline void ov7670_unset_we(void) { PORTC &= ~(1 << PC1); } static inline void ov7670_set_rck(void) { PORTB |= (1 << PB5); } static inline void ov7670_unset_rck(void) { PORTB &= ~(1 << PB5); } static inline void ov7670_toggle_rck(void) { ov7670_set_rck(); _delay_us(5); ov7670_unset_rck(); } static inline uint8_t ov7670_read_bits(void) { return (PINB & 0x0F) | (PIND & 0xF0); } // Register List borrowed from https://github.com/dasaki/arduvision /* Registers */ static const uint8_t REG_GAIN = 0x00; /* Gain lower 8 bits (rest in vref) */ static const uint8_t REG_BLUE = 0x01; /* blue gain */ static const uint8_t REG_RED = 0x02; /* red gain */ static const uint8_t REG_VREF = 0x03; /* Pieces of GAIN, VSTART, VSTOP */ static const uint8_t REG_COM1 = 0x04; /* Control 1 */ static const uint8_t COM1_CCIR656 = 0x40; /* CCIR656 enable */ static const uint8_t REG_BAVE = 0x05; /* U/B Average level */ static const uint8_t REG_GbAVE = 0x06; /* Y/Gb Average level */ static const uint8_t REG_AECHH = 0x07; /* AEC MS 5 bits */ static const uint8_t REG_RAVE = 0x08; /* V/R Average level */ static const uint8_t REG_COM2 = 0x09; /* Control 2 */ static const uint8_t COM2_SSLEEP = 0x10; /* Soft sleep mode */ static const uint8_t REG_PID = 0x0a; /* Product ID MSB */ static const uint8_t REG_VER = 0x0b; /* Product ID LSB */ static const uint8_t REG_COM3 = 0x0c; /* Control 3 */ static const uint8_t COM3_SWAP = 0x40; /* Byte swap */ static const uint8_t COM3_SCALEEN = 0x08; /* Enable scaling */ static const uint8_t COM3_DCWEN = 0x04; /* Enable downsamp/crop/window */ static const uint8_t REG_COM4 = 0x0d; /* Control 4 */ static const uint8_t REG_COM5 = 0x0e; /* All "reserved" */ static const uint8_t REG_COM6 = 0x0f; /* Control 6 */ static const uint8_t REG_AECH = 0x10; /* More bits of AEC value */ static const uint8_t REG_CLKRC = 0x11; /* Clocl control */ static const uint8_t CLK_EXT = 0x40; /* Use external clock directly */ static const uint8_t CLK_SCALE = 0x3f; /* Mask for internal clock scale */ static const uint8_t REG_COM7 = 0x12; /* Control 7 */ // REG mean address. static const uint8_t COM7_RESET = 0x80; /* Register reset */ static const uint8_t COM7_FMT_MASK = 0x38; static const uint8_t COM7_FMT_VGA = 0x00; static const uint8_t COM7_FMT_CIF = 0x20; /* CIF format */ static const uint8_t COM7_FMT_QVGA = 0x10; /* QVGA format */ static const uint8_t COM7_FMT_QCIF = 0x08; /* QCIF format */ static const uint8_t COM7_RGB = 0x04; /* bits 0 and 2 - RGB format */ static const uint8_t COM7_YUV = 0x00; /* YUV */ static const uint8_t COM7_BAYER = 0x01; /* Bayer format */ static const uint8_t COM7_PBAYER = 0x05; /* "Processed bayer" */ static const uint8_t REG_COM8 = 0x13; /* Control 8 */ static const uint8_t COM8_FASTAEC = 0x80; /* Enable fast AGC/AEC */ static const uint8_t COM8_AECSTEP = 0x40; /* Unlimited AEC step size */ static const uint8_t COM8_BFILT = 0x20; /* Band filter enable */ static const uint8_t COM8_AGC = 0x04; /* Auto gain enable */ static const uint8_t COM8_AWB = 0x02; /* White balance enable */ static const uint8_t COM8_AEC = 0x01; /* Auto exposure enable */ static const uint8_t REG_COM9 = 0x14; /* Control 9- gain ceiling */ static const uint8_t REG_COM10 = 0x15; /* Control 10 */ static const uint8_t COM10_HSYNC = 0x40; /* HSYNC instead of HREF */ static const uint8_t COM10_PCLK_HB = 0x20; /* Suppress PCLK on horiz blank */ static const uint8_t COM10_HREF_REV = 0x08; /* Reverse HREF */ static const uint8_t COM10_VS_LEAD = 0x04; /* VSYNC on clock leading edge */ static const uint8_t COM10_VS_NEG = 0x02; /* VSYNC negative */ static const uint8_t COM10_HS_NEG = 0x01; /* HSYNC negative */ static const uint8_t REG_HSTART = 0x17; /* Horiz start high bits */ static const uint8_t REG_HSTOP = 0x18; /* Horiz stop high bits */ static const uint8_t REG_VSTART = 0x19; /* Vert start high bits */ static const uint8_t REG_VSTOP = 0x1a; /* Vert stop high bits */ static const uint8_t REG_PSHFT = 0x1b; /* Pixel delay after HREF */ static const uint8_t REG_MIDH = 0x1c; /* Manuf. ID high */ static const uint8_t REG_MIDL = 0x1d; /* Manuf. ID low */ static const uint8_t REG_MVFP = 0x1e; /* Mirror / vflip */ static const uint8_t MVFP_MIRROR = 0x20; /* Mirror image */ static const uint8_t MVFP_FLIP = 0x10; /* Vertical flip */ static const uint8_t REG_AEW = 0x24; /* AGC upper limit */ static const uint8_t REG_AEB = 0x25; /* AGC lower limit */ static const uint8_t REG_VPT = 0x26; /* AGC/AEC fast mode op region */ static const uint8_t REG_HSYST = 0x30; /* HSYNC rising edge delay */ static const uint8_t REG_HSYEN = 0x31; /* HSYNC falling edge delay */ static const uint8_t REG_HREF = 0x32; /* HREF pieces */ static const uint8_t REG_TSLB = 0x3a; /* lots of stuff */ static const uint8_t TSLB_YLAST = 0x04; /* UYVY or VYUY - see com13 */ static const uint8_t REG_COM11 = 0x3b; /* Control 11 */ static const uint8_t COM11_NIGHT = 0x80; /* NIght mode enable */ static const uint8_t COM11_NMFR = 0x60; /* Two bit NM frame rate */ static const uint8_t COM11_HZAUTO = 0x10; /* Auto detect 50/60 Hz */ static const uint8_t COM11_50HZ = 0x08; /* Manual 50Hz select */ static const uint8_t COM11_EXP = 0x02; static const uint8_t REG_COM12 = 0x3c; /* Control 12 */ static const uint8_t COM12_HREF = 0x80; /* HREF always */ static const uint8_t REG_COM13 = 0x3d; /* Control 13 */ static const uint8_t COM13_GAMMA = 0x80; /* Gamma enable */ static const uint8_t COM13_UVSAT = 0x40; /* UV saturation auto adjustment */ static const uint8_t COM13_UVSWAP = 0x01; /* V before U - w/TSLB */ static const uint8_t REG_COM14 = 0x3e; /* Control 14 */ static const uint8_t COM14_DCWEN = 0x10; /* DCW/PCLK-scale enable */ static const uint8_t REG_EDGE = 0x3f; /* Edge enhancement factor */ static const uint8_t REG_COM15 = 0x40; /* Control 15 */ static const uint8_t COM15_R10F0 = 0x00; /* Data range 10 to F0 */ static const uint8_t COM15_R01FE = 0x80; /* 01 to FE */ static const uint8_t COM15_R00FF = 0xc0; /* 00 to FF */ static const uint8_t COM15_RGB565 = 0x10; /* RGB565 output */ static const uint8_t COM15_RGB555 = 0x30; /* RGB555 output */ static const uint8_t REG_COM16 = 0x41; /* Control 16 */ static const uint8_t COM16_AWBGAIN = 0x08; /* AWB gain enable */ static const uint8_t REG_COM17 = 0x42; /* Control 17 */ static const uint8_t COM17_AECWIN = 0xc0; /* AEC window - must match COM4 */ static const uint8_t COM17_CBAR = 0x08; /* DSP Color bar */ /* * This matrix defines how the colors are generated, must be * tweaked to adjust hue and saturation. * * Order: v-red, v-green, v-blue, u-red, u-green, u-blue * They are nine-bit signed quantities, with the sign bit * stored in0x58.Sign for v-red is bit 0, and up from there. */ static const uint8_t REG_CMATRIX_BASE = 0x4f; static const uint8_t CMATRIX_LEN = 6; static const uint8_t REG_CMATRIX_SIGN = 0x58; static const uint8_t REG_BRIGHT = 0x55; /* Brightness */ static const uint8_t REG_CONTRAS = 0x56; /* Contrast control */ static const uint8_t REG_GFIX = 0x69; /* Fix gain control */ static const uint8_t REG_REG76 = 0x76; /* OV's name */ static const uint8_t R76_BLKPCOR = 0x80; /* Black pixel correction enable */ static const uint8_t R76_WHTPCOR = 0x40; /* White pixel correction enable */ static const uint8_t REG_RGB444 = 0x8c; /* RGB 444 control */ static const uint8_t R444_ENABLE = 0x02; /* Turn on RGB444, overrides 5x5 */ static const uint8_t R444_RGBX = 0x01; /* Empty nibble at end */ static const uint8_t REG_HAECC1 = 0x9f; /* Hist AEC/AGC control 1 */ static const uint8_t REG_HAECC2 = 0xa0; /* Hist AEC/AGC control 2 */ static const uint8_t REG_BD50MAX = 0xa5; /* 50hz banding step limit */ static const uint8_t REG_HAECC3 = 0xa6; /* Hist AEC/AGC control 3 */ static const uint8_t REG_HAECC4 = 0xa7; /* Hist AEC/AGC control 4 */ static const uint8_t REG_HAECC5 = 0xa8; /* Hist AEC/AGC control 5 */ static const uint8_t REG_HAECC6 = 0xa9; /* Hist AEC/AGC control 6 */ static const uint8_t REG_HAECC7 = 0xaa; /* Hist AEC/AGC control 7 */ static const uint8_t REG_BD60MAX = 0xab; /* 60hz banding step limit */ static const uint8_t MTXS = 0x58; /* Matrix Coefficient Sign */ static const uint8_t AWBC7 = 0x59; /* AWB Control 7 */ static const uint8_t AWBC8 = 0x5a; /* AWB Control 8 */ static const uint8_t AWBC9 = 0x5b; /* AWB Control 9 */ static const uint8_t AWBC10 = 0x5c; /* AWB Control 10 */ static const uint8_t AWBC11 = 0x5d; /* AWB Control 11 */ static const uint8_t AWBC12 = 0x5e; /* AWB Control 12 */ static const uint8_t REG_GFI = 0x69; /* Fix gain control */ static const uint8_t GGAIN = 0x6a; /* G Channel AWB Gain */ static const uint8_t DBLV = 0x6b; static const uint8_t AWBCTR3 = 0x6c; /* AWB Control 3 */ static const uint8_t AWBCTR2 = 0x6d; /* AWB Control 2 */ static const uint8_t AWBCTR1 = 0x6e; /* AWB Control 1 */ static const uint8_t AWBCTR0 = 0x6f; /* AWB Control 0 */ #endif