/ adafruit_ov7670.py
adafruit_ov7670.py
1 # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 # SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries 3 # 4 # SPDX-License-Identifier: MIT 5 """ 6 `adafruit_ov7670` 7 ================================================================================ 8 9 CircuitPython driver for OV7670 cameras 10 11 12 * Author(s): Jeff Epler 13 14 Implementation Notes 15 -------------------- 16 17 **Hardware:** 18 19 **Software and Dependencies:** 20 21 * Adafruit CircuitPython firmware for the supported boards: 22 https://github.com/adafruit/circuitpython/releases 23 * The CircuitPython build for your board must support the ``imagecapture`` module. 24 * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 25 """ 26 27 # imports 28 29 __version__ = "0.0.0-auto.0" 30 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ov7670.git" 31 32 import time 33 34 import digitalio 35 import imagecapture 36 import pwmio 37 from adafruit_bus_device.i2c_device import I2CDevice 38 39 from micropython import const 40 41 # Supported color formats 42 OV7670_COLOR_RGB = 0 # RGB565 big-endian 43 OV7670_COLOR_YUV = 1 # YUV/YCbCr 4:2:2 big-endian 44 45 # Supported sizes (VGA division factor) for OV7670_set_size() 46 OV7670_SIZE_DIV1 = 0 # 640 x 480 47 OV7670_SIZE_DIV2 = 1 # 320 x 240 48 OV7670_SIZE_DIV4 = 2 # 160 x 120 49 OV7670_SIZE_DIV8 = 3 # 80 x 60 50 OV7670_SIZE_DIV16 = 4 # 40 x 30 51 52 # Test patterns 53 OV7670_TEST_PATTERN_NONE = 0 # Disable test pattern 54 OV7670_TEST_PATTERN_SHIFTING_1 = 1 # "Shifting 1" pattern 55 OV7670_TEST_PATTERN_COLOR_BAR = 2 # 8 color bars 56 OV7670_TEST_PATTERN_COLOR_BAR_FADE = 3 # Color bars w/fade to white 57 58 # Table of bit patterns for the different supported night modes. 59 # There's a "same frame rate" option for OV7670 night mode but it 60 # doesn't seem to do anything useful and can be skipped over. 61 OV7670_NIGHT_MODE_OFF = 0 # Disable night mode 62 OV7670_NIGHT_MODE_2 = 0b10100000 # Night mode 1/2 frame rate 63 OV7670_NIGHT_MODE_4 = 0b11000000 # Night mode 1/4 frame rate 64 OV7670_NIGHT_MODE_8 = 0b11100000 # Night mode 1/8 frame rate 65 66 OV7670_ADDR = 0x21 # Default I2C address if unspecified 67 68 _OV7670_REG_GAIN = const(0x00) # AGC gain bits 7:0 (9:8 in VREF) 69 _OV7670_REG_BLUE = const(0x01) # AWB blue channel gain 70 _OV7670_REG_RED = const(0x02) # AWB red channel gain 71 _OV7670_REG_VREF = const(0x03) # Vert frame control bits 72 _OV7670_REG_COM1 = const(0x04) # Common control 1 73 _OV7670_COM1_R656 = const(0x40) # COM1 enable R656 format 74 _OV7670_REG_BAVE = const(0x05) # U/B average level 75 _OV7670_REG_GbAVE = const(0x06) # Y/Gb average level 76 _OV7670_REG_AECHH = const(0x07) # Exposure value - AEC 15:10 bits 77 _OV7670_REG_RAVE = const(0x08) # V/R average level 78 _OV7670_REG_COM2 = const(0x09) # Common control 2 79 _OV7670_COM2_SSLEEP = const(0x10) # COM2 soft sleep mode 80 _OV7670_REG_PID = const(0x0A) # Product ID MSB (read-only) 81 _OV7670_REG_VER = const(0x0B) # Product ID LSB (read-only) 82 _OV7670_REG_COM3 = const(0x0C) # Common control 3 83 _OV7670_COM3_SWAP = const(0x40) # COM3 output data MSB/LSB swap 84 _OV7670_COM3_SCALEEN = const(0x08) # COM3 scale enable 85 _OV7670_COM3_DCWEN = const(0x04) # COM3 DCW enable 86 _OV7670_REG_COM4 = const(0x0D) # Common control 4 87 _OV7670_REG_COM5 = const(0x0E) # Common control 5 88 _OV7670_REG_COM6 = const(0x0F) # Common control 6 89 _OV7670_REG_AECH = const(0x10) # Exposure value 9:2 90 _OV7670_REG_CLKRC = const(0x11) # Internal clock 91 _OV7670_CLK_EXT = const(0x40) # CLKRC Use ext clock directly 92 _OV7670_CLK_SCALE = const(0x3F) # CLKRC Int clock prescale mask 93 _OV7670_REG_COM7 = const(0x12) # Common control 7 94 _OV7670_COM7_RESET = const(0x80) # COM7 SCCB register reset 95 _OV7670_COM7_SIZE_MASK = const(0x38) # COM7 output size mask 96 _OV7670_COM7_PIXEL_MASK = const(0x05) # COM7 output pixel format mask 97 _OV7670_COM7_SIZE_VGA = const(0x00) # COM7 output size VGA 98 _OV7670_COM7_SIZE_CIF = const(0x20) # COM7 output size CIF 99 _OV7670_COM7_SIZE_QVGA = const(0x10) # COM7 output size QVGA 100 _OV7670_COM7_SIZE_QCIF = const(0x08) # COM7 output size QCIF 101 _OV7670_COM7_RGB = const(0x04) # COM7 pixel format RGB 102 _OV7670_COM7_YUV = const(0x00) # COM7 pixel format YUV 103 _OV7670_COM7_BAYER = const(0x01) # COM7 pixel format Bayer RAW 104 _OV7670_COM7_PBAYER = const(0x05) # COM7 pixel fmt proc Bayer RAW 105 _OV7670_COM7_COLORBAR = const(0x02) # COM7 color bar enable 106 _OV7670_REG_COM8 = const(0x13) # Common control 8 107 _OV7670_COM8_FASTAEC = const(0x80) # COM8 Enable fast AGC/AEC algo, 108 _OV7670_COM8_AECSTEP = const(0x40) # COM8 AEC step size unlimited 109 _OV7670_COM8_BANDING = const(0x20) # COM8 Banding filter enable 110 _OV7670_COM8_AGC = const(0x04) # COM8 AGC (auto gain) enable 111 _OV7670_COM8_AWB = const(0x02) # COM8 AWB (auto white balance) 112 _OV7670_COM8_AEC = const(0x01) # COM8 AEC (auto exposure) enable 113 _OV7670_REG_COM9 = const(0x14) # Common control 9 - max AGC value 114 _OV7670_REG_COM10 = const(0x15) # Common control 10 115 _OV7670_COM10_HSYNC = const(0x40) # COM10 HREF changes to HSYNC 116 _OV7670_COM10_PCLK_HB = const(0x20) # COM10 Suppress PCLK on hblank 117 _OV7670_COM10_HREF_REV = const(0x08) # COM10 HREF reverse 118 _OV7670_COM10_VS_EDGE = const(0x04) # COM10 VSYNC chg on PCLK rising 119 _OV7670_COM10_VS_NEG = const(0x02) # COM10 VSYNC negative 120 _OV7670_COM10_HS_NEG = const(0x01) # COM10 HSYNC negative 121 _OV7670_REG_HSTART = const(0x17) # Horiz frame start high bits 122 _OV7670_REG_HSTOP = const(0x18) # Horiz frame end high bits 123 _OV7670_REG_VSTART = const(0x19) # Vert frame start high bits 124 _OV7670_REG_VSTOP = const(0x1A) # Vert frame end high bits 125 _OV7670_REG_PSHFT = const(0x1B) # Pixel delay select 126 _OV7670_REG_MIDH = const(0x1C) # Manufacturer ID high byte 127 _OV7670_REG_MIDL = const(0x1D) # Manufacturer ID low byte 128 _OV7670_REG_MVFP = const(0x1E) # Mirror / vert-flip enable 129 _OV7670_MVFP_MIRROR = const(0x20) # MVFP Mirror image 130 _OV7670_MVFP_VFLIP = const(0x10) # MVFP Vertical flip 131 _OV7670_REG_LAEC = const(0x1F) # Reserved 132 _OV7670_REG_ADCCTR0 = const(0x20) # ADC control 133 _OV7670_REG_ADCCTR1 = const(0x21) # Reserved 134 _OV7670_REG_ADCCTR2 = const(0x22) # Reserved 135 _OV7670_REG_ADCCTR3 = const(0x23) # Reserved 136 _OV7670_REG_AEW = const(0x24) # AGC/AEC upper limit 137 _OV7670_REG_AEB = const(0x25) # AGC/AEC lower limit 138 _OV7670_REG_VPT = const(0x26) # AGC/AEC fast mode op region 139 _OV7670_REG_BBIAS = const(0x27) # B channel signal output bias 140 _OV7670_REG_GbBIAS = const(0x28) # Gb channel signal output bias 141 _OV7670_REG_EXHCH = const(0x2A) # Dummy pixel insert MSB 142 _OV7670_REG_EXHCL = const(0x2B) # Dummy pixel insert LSB 143 _OV7670_REG_RBIAS = const(0x2C) # R channel signal output bias 144 _OV7670_REG_ADVFL = const(0x2D) # Insert dummy lines MSB 145 _OV7670_REG_ADVFH = const(0x2E) # Insert dummy lines LSB 146 _OV7670_REG_YAVE = const(0x2F) # Y/G channel average value 147 _OV7670_REG_HSYST = const(0x30) # HSYNC rising edge delay 148 _OV7670_REG_HSYEN = const(0x31) # HSYNC falling edge delay 149 _OV7670_REG_HREF = const(0x32) # HREF control 150 _OV7670_REG_CHLF = const(0x33) # Array current control 151 _OV7670_REG_ARBLM = const(0x34) # Array ref control - reserved 152 _OV7670_REG_ADC = const(0x37) # ADC control - reserved 153 _OV7670_REG_ACOM = const(0x38) # ADC & analog common - reserved 154 _OV7670_REG_OFON = const(0x39) # ADC offset control - reserved 155 _OV7670_REG_TSLB = const(0x3A) # Line buffer test option 156 _OV7670_TSLB_NEG = const(0x20) # TSLB Negative image enable 157 _OV7670_TSLB_YLAST = const(0x04) # TSLB UYVY or VYUY, see COM13 158 _OV7670_TSLB_AOW = const(0x01) # TSLB Auto output window 159 _OV7670_REG_COM11 = const(0x3B) # Common control 11 160 _OV7670_COM11_NIGHT = const(0x80) # COM11 Night mode 161 _OV7670_COM11_NMFR = const(0x60) # COM11 Night mode frame rate mask 162 _OV7670_COM11_HZAUTO = const(0x10) # COM11 Auto detect 50/60 Hz 163 _OV7670_COM11_BAND = const(0x08) # COM11 Banding filter val select 164 _OV7670_COM11_EXP = const(0x02) # COM11 Exposure timing control 165 _OV7670_REG_COM12 = const(0x3C) # Common control 12 166 _OV7670_COM12_HREF = const(0x80) # COM12 Always has HREF 167 _OV7670_REG_COM13 = const(0x3D) # Common control 13 168 _OV7670_COM13_GAMMA = const(0x80) # COM13 Gamma enable 169 _OV7670_COM13_UVSAT = const(0x40) # COM13 UV saturation auto adj 170 _OV7670_COM13_UVSWAP = const(0x01) # COM13 UV swap, use w TSLB[3] 171 _OV7670_REG_COM14 = const(0x3E) # Common control 14 172 _OV7670_COM14_DCWEN = const(0x10) # COM14 DCW & scaling PCLK enable 173 _OV7670_REG_EDGE = const(0x3F) # Edge enhancement adjustment 174 _OV7670_REG_COM15 = const(0x40) # Common control 15 175 _OV7670_COM15_RMASK = const(0xC0) # COM15 Output range mask 176 _OV7670_COM15_R10F0 = const(0x00) # COM15 Output range 10 to F0 177 _OV7670_COM15_R01FE = const(0x80) # COM15 01 to FE 178 _OV7670_COM15_R00FF = const(0xC0) # COM15 00 to FF 179 _OV7670_COM15_RGBMASK = const(0x30) # COM15 RGB 555/565 option mask 180 _OV7670_COM15_RGB = const(0x00) # COM15 Normal RGB out 181 _OV7670_COM15_RGB565 = const(0x10) # COM15 RGB 565 output 182 _OV7670_COM15_RGB555 = const(0x30) # COM15 RGB 555 output 183 _OV7670_REG_COM16 = const(0x41) # Common control 16 184 _OV7670_COM16_AWBGAIN = const(0x08) # COM16 AWB gain enable 185 _OV7670_REG_COM17 = const(0x42) # Common control 17 186 _OV7670_COM17_AECWIN = const(0xC0) # COM17 AEC window must match COM4 187 _OV7670_COM17_CBAR = const(0x08) # COM17 DSP Color bar enable 188 _OV7670_REG_AWBC1 = const(0x43) # Reserved 189 _OV7670_REG_AWBC2 = const(0x44) # Reserved 190 _OV7670_REG_AWBC3 = const(0x45) # Reserved 191 _OV7670_REG_AWBC4 = const(0x46) # Reserved 192 _OV7670_REG_AWBC5 = const(0x47) # Reserved 193 _OV7670_REG_AWBC6 = const(0x48) # Reserved 194 _OV7670_REG_REG4B = const(0x4B) # UV average enable 195 _OV7670_REG_DNSTH = const(0x4C) # De-noise strength 196 _OV7670_REG_MTX1 = const(0x4F) # Matrix coefficient 1 197 _OV7670_REG_MTX2 = const(0x50) # Matrix coefficient 2 198 _OV7670_REG_MTX3 = const(0x51) # Matrix coefficient 3 199 _OV7670_REG_MTX4 = const(0x52) # Matrix coefficient 4 200 _OV7670_REG_MTX5 = const(0x53) # Matrix coefficient 5 201 _OV7670_REG_MTX6 = const(0x54) # Matrix coefficient 6 202 _OV7670_REG_BRIGHT = const(0x55) # Brightness control 203 _OV7670_REG_CONTRAS = const(0x56) # Contrast control 204 _OV7670_REG_CONTRAS_CENTER = const(0x57) # Contrast center 205 _OV7670_REG_MTXS = const(0x58) # Matrix coefficient sign 206 _OV7670_REG_LCC1 = const(0x62) # Lens correction option 1 207 _OV7670_REG_LCC2 = const(0x63) # Lens correction option 2 208 _OV7670_REG_LCC3 = const(0x64) # Lens correction option 3 209 _OV7670_REG_LCC4 = const(0x65) # Lens correction option 4 210 _OV7670_REG_LCC5 = const(0x66) # Lens correction option 5 211 _OV7670_REG_MANU = const(0x67) # Manual U value 212 _OV7670_REG_MANV = const(0x68) # Manual V value 213 _OV7670_REG_GFIX = const(0x69) # Fix gain control 214 _OV7670_REG_GGAIN = const(0x6A) # G channel AWB gain 215 _OV7670_REG_DBLV = const(0x6B) # PLL & regulator control 216 _OV7670_REG_AWBCTR3 = const(0x6C) # AWB control 3 217 _OV7670_REG_AWBCTR2 = const(0x6D) # AWB control 2 218 _OV7670_REG_AWBCTR1 = const(0x6E) # AWB control 1 219 _OV7670_REG_AWBCTR0 = const(0x6F) # AWB control 0 220 _OV7670_REG_SCALING_XSC = const(0x70) # Test pattern X scaling 221 _OV7670_REG_SCALING_YSC = const(0x71) # Test pattern Y scaling 222 _OV7670_REG_SCALING_DCWCTR = const(0x72) # DCW control 223 _OV7670_REG_SCALING_PCLK_DIV = const(0x73) # DSP scale control clock divide 224 _OV7670_REG_REG74 = const(0x74) # Digital gain control 225 _OV7670_REG_REG76 = const(0x76) # Pixel correction 226 _OV7670_REG_SLOP = const(0x7A) # Gamma curve highest seg slope 227 _OV7670_REG_GAM_BASE = const(0x7B) # Gamma register base (1 of 15) 228 _OV7670_GAM_LEN = const(15) # Number of gamma registers 229 _OV7670_R76_BLKPCOR = const(0x80) # REG76 black pixel corr enable 230 _OV7670_R76_WHTPCOR = const(0x40) # REG76 white pixel corr enable 231 _OV7670_REG_RGB444 = const(0x8C) # RGB 444 control 232 _OV7670_R444_ENABLE = const(0x02) # RGB444 enable 233 _OV7670_R444_RGBX = const(0x01) # RGB444 word format 234 _OV7670_REG_DM_LNL = const(0x92) # Dummy line LSB 235 _OV7670_REG_LCC6 = const(0x94) # Lens correction option 6 236 _OV7670_REG_LCC7 = const(0x95) # Lens correction option 7 237 _OV7670_REG_HAECC1 = const(0x9F) # Histogram-based AEC/AGC ctrl 1 238 _OV7670_REG_HAECC2 = const(0xA0) # Histogram-based AEC/AGC ctrl 2 239 _OV7670_REG_SCALING_PCLK_DELAY = const(0xA2) # Scaling pixel clock delay 240 _OV7670_REG_BD50MAX = const(0xA5) # 50 Hz banding step limit 241 _OV7670_REG_HAECC3 = const(0xA6) # Histogram-based AEC/AGC ctrl 3 242 _OV7670_REG_HAECC4 = const(0xA7) # Histogram-based AEC/AGC ctrl 4 243 _OV7670_REG_HAECC5 = const(0xA8) # Histogram-based AEC/AGC ctrl 5 244 _OV7670_REG_HAECC6 = const(0xA9) # Histogram-based AEC/AGC ctrl 6 245 _OV7670_REG_HAECC7 = const(0xAA) # Histogram-based AEC/AGC ctrl 7 246 _OV7670_REG_BD60MAX = const(0xAB) # 60 Hz banding step limit 247 _OV7670_REG_ABLC1 = const(0xB1) # ABLC enable 248 _OV7670_REG_THL_ST = const(0xB3) # ABLC target 249 _OV7670_REG_SATCTR = const(0xC9) # Saturation control 250 251 _OV7670_REG_LAST = const(_OV7670_REG_SATCTR) # Maximum register address 252 253 # Manual output format, RGB, use RGB565 and full 0-255 output range 254 _OV7670_rgb = bytes( 255 [ 256 _OV7670_REG_COM7, 257 _OV7670_COM7_RGB, 258 _OV7670_REG_RGB444, 259 0, 260 _OV7670_REG_COM15, 261 _OV7670_COM15_RGB565 | _OV7670_COM15_R00FF, 262 ] 263 ) 264 265 # Manual output format, YUV, use full output range 266 _OV7670_yuv = bytes( 267 [ 268 _OV7670_REG_COM7, 269 _OV7670_COM7_YUV, 270 _OV7670_REG_COM15, 271 _OV7670_COM15_R00FF, 272 ] 273 ) 274 275 _OV7670_init = bytes( 276 [ 277 _OV7670_REG_TSLB, 278 _OV7670_TSLB_YLAST, # No auto window 279 _OV7670_REG_COM10, 280 _OV7670_COM10_VS_NEG, # -VSYNC (req by SAMD PCC) 281 _OV7670_REG_SLOP, 282 0x20, 283 _OV7670_REG_GAM_BASE, 284 0x1C, 285 _OV7670_REG_GAM_BASE + 1, 286 0x28, 287 _OV7670_REG_GAM_BASE + 2, 288 0x3C, 289 _OV7670_REG_GAM_BASE + 3, 290 0x55, 291 _OV7670_REG_GAM_BASE + 4, 292 0x68, 293 _OV7670_REG_GAM_BASE + 5, 294 0x76, 295 _OV7670_REG_GAM_BASE + 6, 296 0x80, 297 _OV7670_REG_GAM_BASE + 7, 298 0x88, 299 _OV7670_REG_GAM_BASE + 8, 300 0x8F, 301 _OV7670_REG_GAM_BASE + 9, 302 0x96, 303 _OV7670_REG_GAM_BASE + 10, 304 0xA3, 305 _OV7670_REG_GAM_BASE + 11, 306 0xAF, 307 _OV7670_REG_GAM_BASE + 12, 308 0xC4, 309 _OV7670_REG_GAM_BASE + 13, 310 0xD7, 311 _OV7670_REG_GAM_BASE + 14, 312 0xE8, 313 _OV7670_REG_COM8, 314 _OV7670_COM8_FASTAEC | _OV7670_COM8_AECSTEP | _OV7670_COM8_BANDING, 315 _OV7670_REG_GAIN, 316 0x00, 317 _OV7670_COM2_SSLEEP, 318 0x00, 319 _OV7670_REG_COM4, 320 0x00, 321 _OV7670_REG_COM9, 322 0x20, # Max AGC value 323 _OV7670_REG_BD50MAX, 324 0x05, 325 _OV7670_REG_BD60MAX, 326 0x07, 327 _OV7670_REG_AEW, 328 0x75, 329 _OV7670_REG_AEB, 330 0x63, 331 _OV7670_REG_VPT, 332 0xA5, 333 _OV7670_REG_HAECC1, 334 0x78, 335 _OV7670_REG_HAECC2, 336 0x68, 337 0xA1, 338 0x03, # Reserved register? 339 _OV7670_REG_HAECC3, 340 0xDF, # Histogram-based AEC/AGC setup 341 _OV7670_REG_HAECC4, 342 0xDF, 343 _OV7670_REG_HAECC5, 344 0xF0, 345 _OV7670_REG_HAECC6, 346 0x90, 347 _OV7670_REG_HAECC7, 348 0x94, 349 _OV7670_REG_COM8, 350 _OV7670_COM8_FASTAEC 351 | _OV7670_COM8_AECSTEP 352 | _OV7670_COM8_BANDING 353 | _OV7670_COM8_AGC 354 | _OV7670_COM8_AEC, 355 _OV7670_REG_COM5, 356 0x61, 357 _OV7670_REG_COM6, 358 0x4B, 359 0x16, 360 0x02, # Reserved register? 361 _OV7670_REG_MVFP, 362 0x07, # 0x07, 363 _OV7670_REG_ADCCTR1, 364 0x02, 365 _OV7670_REG_ADCCTR2, 366 0x91, 367 0x29, 368 0x07, # Reserved register? 369 _OV7670_REG_CHLF, 370 0x0B, 371 0x35, 372 0x0B, # Reserved register? 373 _OV7670_REG_ADC, 374 0x1D, 375 _OV7670_REG_ACOM, 376 0x71, 377 _OV7670_REG_OFON, 378 0x2A, 379 _OV7670_REG_COM12, 380 0x78, 381 0x4D, 382 0x40, # Reserved register? 383 0x4E, 384 0x20, # Reserved register? 385 _OV7670_REG_GFIX, 386 0x5D, 387 _OV7670_REG_REG74, 388 0x19, 389 0x8D, 390 0x4F, # Reserved register? 391 0x8E, 392 0x00, # Reserved register? 393 0x8F, 394 0x00, # Reserved register? 395 0x90, 396 0x00, # Reserved register? 397 0x91, 398 0x00, # Reserved register? 399 _OV7670_REG_DM_LNL, 400 0x00, 401 0x96, 402 0x00, # Reserved register? 403 0x9A, 404 0x80, # Reserved register? 405 0xB0, 406 0x84, # Reserved register? 407 _OV7670_REG_ABLC1, 408 0x0C, 409 0xB2, 410 0x0E, # Reserved register? 411 _OV7670_REG_THL_ST, 412 0x82, 413 0xB8, 414 0x0A, # Reserved register? 415 _OV7670_REG_AWBC1, 416 0x14, 417 _OV7670_REG_AWBC2, 418 0xF0, 419 _OV7670_REG_AWBC3, 420 0x34, 421 _OV7670_REG_AWBC4, 422 0x58, 423 _OV7670_REG_AWBC5, 424 0x28, 425 _OV7670_REG_AWBC6, 426 0x3A, 427 0x59, 428 0x88, # Reserved register? 429 0x5A, 430 0x88, # Reserved register? 431 0x5B, 432 0x44, # Reserved register? 433 0x5C, 434 0x67, # Reserved register? 435 0x5D, 436 0x49, # Reserved register? 437 0x5E, 438 0x0E, # Reserved register? 439 _OV7670_REG_LCC3, 440 0x04, 441 _OV7670_REG_LCC4, 442 0x20, 443 _OV7670_REG_LCC5, 444 0x05, 445 _OV7670_REG_LCC6, 446 0x04, 447 _OV7670_REG_LCC7, 448 0x08, 449 _OV7670_REG_AWBCTR3, 450 0x0A, 451 _OV7670_REG_AWBCTR2, 452 0x55, 453 _OV7670_REG_MTX1, 454 0x80, 455 _OV7670_REG_MTX2, 456 0x80, 457 _OV7670_REG_MTX3, 458 0x00, 459 _OV7670_REG_MTX4, 460 0x22, 461 _OV7670_REG_MTX5, 462 0x5E, 463 _OV7670_REG_MTX6, 464 0x80, # 0x40? 465 _OV7670_REG_AWBCTR1, 466 0x11, 467 _OV7670_REG_AWBCTR0, 468 0x9F, # Or use 0x9E for advance AWB 469 _OV7670_REG_BRIGHT, 470 0x00, 471 _OV7670_REG_CONTRAS, 472 0x40, 473 _OV7670_REG_CONTRAS_CENTER, 474 0x80, # 0x40? 475 ] 476 ) 477 478 _window = [ 479 [9, 162, 2, 2], # SIZE_DIV1 640x480 VGA 480 [10, 174, 4, 2], # SIZE_DIV2 320x240 QVGA 481 [11, 186, 2, 2], # SIZE_DIV4 160x120 QQVGA 482 [12, 210, 0, 2], # SIZE_DIV8 80x60 ... 483 [15, 252, 3, 2], # SIZE_DIV16 40x30 484 ] 485 486 487 class OV7670: # pylint: disable=too-many-instance-attributes 488 """Library for the OV7670 digital camera""" 489 490 def __init__( 491 self, 492 i2c_bus, 493 data0, 494 clock, 495 vsync, 496 href, 497 shutdown=None, 498 reset=None, 499 mclk=None, 500 mclk_frequency=16_000_000, 501 colorspace=OV7670_COLOR_RGB, 502 i2c_address=0x21, 503 ): # pylint: disable=too-many-arguments 504 """ 505 Args: 506 i2c_bus (busio.I2C): The I2C bus used to configure the OV7670 507 i2c_address (int): The I2C address of the camera 508 data0 (microcontroller.Pin): The first of 8 parallel data capture pins 509 clock (microcontroller.Pin): The pixel clock from the OV7670 510 vsync (microcontroller.Pin): The vsync signal from the OV7670 511 href (microcontroller.Pin): The href signal from the OV7670 512 shutdown: The microcontroller.Pin that controls the camera's \ 513 shutdown signal, also called the powerdown or enable pin, or \ 514 None 515 reset: The microcontroller.Pin that controls the camera's reset \ 516 signal, or enable pin, or None 517 mclk: The pin on which to create a master clock signal, or None 518 mclk_frequency: The frequency of the master clock to generate, \ 519 ignored if mclk is None 520 colorspace: The colorspace to operate in 521 size: The size of image to capture 522 """ 523 # Initialize the master clock 524 if mclk: 525 self._mclk_pwm = pwmio.PWMOut(mclk, frequency=mclk_frequency) 526 self._mclk_pwm.duty_cycle = 32768 527 else: 528 self._mclk_pwm = None 529 530 if shutdown: 531 self._shutdown = digitalio.DigitalInOut(shutdown) 532 self._shutdown.switch_to_output(True) 533 time.sleep(0.001) 534 self._shutdown.switch_to_output(False) 535 time.sleep(0.3) 536 else: 537 self._shutdown = None 538 539 if reset: 540 self._reset = digitalio.DigitalInOut(reset) 541 self._reset.switch_to_output(False) 542 time.sleep(0.001) 543 self._reset.switch_to_output(True) 544 545 self._i2c_device = I2CDevice(i2c_bus, i2c_address) 546 547 if not reset: 548 self._write_register(_OV7670_REG_COM7, _OV7670_COM7_RESET) 549 550 time.sleep(0.001) 551 552 self._colorspace = None 553 self.colorspace = colorspace 554 555 self._write_list(_OV7670_init) 556 557 self._size = None 558 self.size = OV7670_SIZE_DIV8 559 560 self._test_pattern = None 561 self.test_pattern = OV7670_TEST_PATTERN_NONE 562 563 self._flip_x = False 564 self._flip_y = False 565 566 self._night = OV7670_NIGHT_MODE_OFF 567 568 self._imagecapture = imagecapture.ParallelImageCapture( 569 data0=data0, clock=clock, vsync=vsync, href=href 570 ) 571 572 def capture(self, buf): 573 """Capture an image into the buffer.""" 574 self._imagecapture.capture(buf) 575 576 @property 577 def mclk_frequency(self): 578 """Get the actual frequency the generated mclk, or None""" 579 return self._mclk_pwm.frequency if self._mclk_pwm else None 580 581 @property 582 def width(self): 583 """Get the image width in pixels. A buffer of 2*width*height bytes \ 584 stores a whole image.""" 585 return 640 >> self._size 586 587 @property 588 def height(self): 589 """Get the image height in pixels. A buffer of 2*width*height bytes \ 590 stores a whole image.""" 591 return 480 >> self._size 592 593 @property 594 def colorspace(self): 595 """Get or set the colorspace""" 596 return self._colorspace 597 598 @colorspace.setter 599 def colorspace(self, colorspace): 600 self._colorspace = colorspace 601 self._write_list(_OV7670_rgb if colorspace == OV7670_COLOR_RGB else _OV7670_yuv) 602 603 def deinit(self): 604 """Deinitialize the camera""" 605 if self._mclk_pwm: 606 self._mclk_pwm.deinit() 607 if self._shutdown: 608 self._shutdown.deinit() 609 if self._reset: 610 self._reset.deinit() 611 612 @property 613 def size(self): 614 """Get or set the captured image size""" 615 return self._size 616 617 @size.setter 618 def size(self, size): 619 self._frame_control(size, *_window[size]) 620 self._size = size 621 622 @property 623 def test_pattern(self): 624 """Get or set the test pattern""" 625 return self._test_pattern 626 627 @test_pattern.setter 628 def test_pattern(self, pattern): 629 # Modify only test pattern bits (not scaling bits) 630 xsc = self._read_register(_OV7670_REG_SCALING_XSC) & ~0x80 631 ysc = self._read_register(_OV7670_REG_SCALING_YSC) & ~0x80 632 if pattern & 1: 633 xsc |= 0x80 634 if pattern & 3: 635 ysc |= 0x80 636 # Write modified result back to SCALING_XSC and SCALING_YSC 637 self._write_register(_OV7670_REG_SCALING_XSC, xsc) 638 self._write_register(_OV7670_REG_SCALING_YSC, ysc) 639 640 def _set_flip(self): 641 mvfp = self._read_register(_OV7670_REG_MVFP) 642 if self._flip_x: 643 mvfp |= _OV7670_MVFP_MIRROR 644 else: 645 mvfp &= ~_OV7670_MVFP_MIRROR 646 if self._flip_y: 647 mvfp |= _OV7670_MVFP_VFLIP 648 else: 649 mvfp &= ~_OV7670_MVFP_VFLIP 650 self._write_register(_OV7670_REG_MVFP, mvfp) 651 652 @property 653 def flip_x(self): 654 """Get or set the X-flip flag""" 655 return self._flip_x 656 657 @flip_x.setter 658 def flip_x(self, value): 659 self._flip_x = bool(value) 660 self._set_flip() 661 662 @property 663 def flip_y(self): 664 """Get or set the Y-flip flag""" 665 return self._flip_y 666 667 @flip_y.setter 668 def flip_y(self, value): 669 self._flip_y = bool(value) 670 self._set_flip() 671 672 @property 673 def night(self): 674 """Get or set the night-vision mode""" 675 return self._night 676 677 @night.setter 678 def night(self, value): 679 com11 = self._read_register(_OV7670_REG_COM11) 680 com11 = (com11 & 0b00011111) | value 681 self._write_register(_OV7670_REG_COM11, com11) 682 self._night = value 683 684 @property 685 def product_id(self): 686 """Get the product id (PID) register""" 687 return self._read_register(_OV7670_REG_PID) 688 689 @property 690 def product_version(self): 691 """Get the version (VER) register""" 692 return self._read_register(_OV7670_REG_VER) 693 694 def _write_list(self, reg_list): 695 for i in range(0, len(reg_list), 2): 696 self._write_register(reg_list[i], reg_list[i + 1]) 697 time.sleep(0.001) 698 699 def _write_register(self, reg, value): 700 b = bytearray(2) 701 b[0] = reg 702 b[1] = value 703 with self._i2c_device as i2c: 704 i2c.write(b) 705 706 def _read_register(self, reg): 707 b = bytearray(1) 708 b[0] = reg 709 with self._i2c_device as i2c: 710 i2c.write(b) 711 i2c.readinto(b) 712 return b[0] 713 714 def _frame_control( 715 self, size, vstart, hstart, edge_offset, pclk_delay 716 ): # pylint: disable=too-many-arguments 717 718 # Enable downsampling if sub-VGA, and zoom if 1:16 scale 719 value = _OV7670_COM3_DCWEN if (size > OV7670_SIZE_DIV1) else 0 720 if size == OV7670_SIZE_DIV16: 721 value |= _OV7670_COM3_SCALEEN 722 self._write_register(_OV7670_REG_COM3, value) 723 724 # Enable PCLK division if sub-VGA 2,4,8,16 = 0x19,1A,1B,1C 725 value = (0x18 + size) if (size > OV7670_SIZE_DIV1) else 0 726 self._write_register(_OV7670_REG_COM14, value) 727 728 # Horiz/vert downsample ratio, 1:8 max (H,V are always equal for now) 729 value = size if (size <= OV7670_SIZE_DIV8) else OV7670_SIZE_DIV8 730 self._write_register(_OV7670_REG_SCALING_DCWCTR, value * 0x11) 731 732 # Pixel clock divider if sub-VGA 733 value = (0xF0 + size) if (size > OV7670_SIZE_DIV1) else 0x08 734 self._write_register(_OV7670_REG_SCALING_PCLK_DIV, value) 735 736 # Apply 0.5 digital zoom at 1:16 size (others are downsample only) 737 value = 0x40 if (size == OV7670_SIZE_DIV16) else 0x20 # 0.5, 1.0 738 739 # Read current SCALING_XSC and SCALING_YSC register values because 740 # test pattern settings are also stored in those registers and we 741 # don't want to corrupt anything there. 742 xsc = self._read_register(_OV7670_REG_SCALING_XSC) 743 ysc = self._read_register(_OV7670_REG_SCALING_YSC) 744 xsc = (xsc & 0x80) | value # Modify only scaling bits (not test pattern) 745 ysc = (ysc & 0x80) | value 746 # Write modified result back to SCALING_XSC and SCALING_YSC 747 self._write_register(_OV7670_REG_SCALING_XSC, xsc) 748 self._write_register(_OV7670_REG_SCALING_YSC, ysc) 749 750 # Window size is scattered across multiple registers. 751 # Horiz/vert stops can be automatically calc'd from starts. 752 vstop = vstart + 480 753 hstop = (hstart + 640) % 784 754 self._write_register(_OV7670_REG_HSTART, hstart >> 3) 755 self._write_register(_OV7670_REG_HSTOP, hstop >> 3) 756 self._write_register( 757 _OV7670_REG_HREF, 758 (edge_offset << 6) | ((hstop & 0b111) << 3) | (hstart & 0b111), 759 ) 760 self._write_register(_OV7670_REG_VSTART, vstart >> 2) 761 self._write_register(_OV7670_REG_VSTOP, vstop >> 2) 762 self._write_register(_OV7670_REG_VREF, ((vstop & 0b11) << 2) | (vstart & 0b11)) 763 764 self._write_register(_OV7670_REG_SCALING_PCLK_DELAY, pclk_delay)