1 /*
2 * Copyright 2017-2018, 2020 NXP
3 * All rights reserved.
4 *
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_video_common.h"
10 #include "fsl_camera.h"
11 #include "fsl_camera_device.h"
12 #include "fsl_ov7725.h"
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17 #define OV7725_SCCB_ADDR 0x21U
18 #define OV7725_REVISION 0x7721U
19
20 #define OV7725_WriteReg(handle, reg, val) \
21 SCCB_WriteReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (val), \
22 ((ov7725_resource_t *)((handle)->resource))->i2cSendFunc)
23
24 #define OV7725_ReadReg(handle, reg, val) \
25 SCCB_ReadReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (val), \
26 ((ov7725_resource_t *)((handle)->resource))->i2cReceiveFunc)
27
28 #define OV7725_ModifyReg(handle, reg, clrMask, val) \
29 SCCB_ModifyReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (clrMask), (val), \
30 ((ov7725_resource_t *)((handle)->resource))->i2cReceiveFunc, \
31 ((ov7725_resource_t *)((handle)->resource))->i2cSendFunc)
32
33 #define OV7725_CHECK_RET(x) \
34 do \
35 { \
36 status = (x); \
37 if (kStatus_Success != status) \
38 { \
39 return status; \
40 } \
41 } while (false)
42
43 typedef struct _ov7725_clock_config
44 {
45 uint32_t frameRate_Hz;
46 uint32_t inputClk_Hz;
47 uint8_t clkrc; /*!< Register CLKRC. */
48 uint8_t com4; /*!< Register COM4. */
49 uint8_t dm_lnl; /*!< Register DM_LNL. */
50 } ov7725_clock_config_t;
51
52 typedef struct _ov7725_light_mode
53 {
54 uint8_t lightMode;
55 uint8_t com8;
56 uint8_t blue;
57 uint8_t red;
58 uint8_t com5;
59 } ov7725_light_mode_config_t;
60
61 typedef struct _ov7725_special_effect_config
62 {
63 uint8_t effect;
64 uint8_t sde;
65 uint8_t ufix;
66 uint8_t vfix;
67 } ov7725_special_effect_config_t;
68
69 typedef struct _ov7725_night_mode
70 {
71 uint8_t nightMode;
72 uint8_t com5;
73 } ov7725_night_mode_t;
74
75 typedef struct _ov7725_pixel_format_config
76 {
77 video_pixel_format_t fmt;
78 uint8_t com7;
79 } ov7725_pixel_format_config_t;
80
81 typedef status_t (*ov7725_cmd_func_t)(camera_device_handle_t *handle, int32_t arg);
82
83 typedef struct _ov7725_cmd_func_map
84 {
85 camera_device_cmd_t cmd;
86 ov7725_cmd_func_t func;
87 } ov7725_cmd_func_map_t;
88
89 typedef struct _ov7725_reg
90 {
91 uint8_t reg;
92 uint8_t val;
93 } ov7725_reg_t;
94
95 /*******************************************************************************
96 * Prototypes
97 ******************************************************************************/
98 status_t OV7725_Init(camera_device_handle_t *handle, const camera_config_t *config);
99
100 status_t OV7725_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig);
101
102 status_t OV7725_Deinit(camera_device_handle_t *handle);
103
104 status_t OV7725_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg);
105
106 status_t OV7725_Start(camera_device_handle_t *handle);
107
108 status_t OV7725_Stop(camera_device_handle_t *handle);
109
110 status_t OV7725_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect);
111
112 status_t OV7725_SetLightMode(camera_device_handle_t *handle, int32_t lightMode);
113
114 status_t OV7725_SetNightMode(camera_device_handle_t *handle, int32_t nightMode);
115
116 status_t OV7725_SetSaturation(camera_device_handle_t *handle, int32_t saturation);
117
118 status_t OV7725_SetContrast(camera_device_handle_t *handle, int32_t contrast);
119
120 status_t OV7725_SetBrightness(camera_device_handle_t *handle, int32_t brightness);
121
122 /*******************************************************************************
123 * Variables
124 ******************************************************************************/
125 const camera_device_operations_t ov7725_ops = {
126 .init = OV7725_Init,
127 .deinit = OV7725_Deinit,
128 .start = OV7725_Start,
129 .stop = OV7725_Stop,
130 .control = OV7725_Control,
131 .init_ext = OV7725_InitExt,
132 };
133
134 static const ov7725_clock_config_t ov7725ClockConfigs[] = {
135 /* FrameRate, inputClk, clkrc, com4, dm_lnl. */
136 {.frameRate_Hz = 30, .inputClk_Hz = 24000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x00},
137 {.frameRate_Hz = 15, .inputClk_Hz = 24000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x00},
138 {.frameRate_Hz = 25, .inputClk_Hz = 24000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x66},
139 {.frameRate_Hz = 14, .inputClk_Hz = 24000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x1a},
140 {.frameRate_Hz = 30, .inputClk_Hz = 26000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b},
141 {.frameRate_Hz = 15, .inputClk_Hz = 26000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x2b},
142 {.frameRate_Hz = 25, .inputClk_Hz = 26000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x99},
143 {.frameRate_Hz = 14, .inputClk_Hz = 26000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x46},
144 {.frameRate_Hz = 30, .inputClk_Hz = 13000000, .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x2b},
145 {.frameRate_Hz = 15, .inputClk_Hz = 13000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b},
146 {.frameRate_Hz = 25, .inputClk_Hz = 13000000, .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x99},
147 {.frameRate_Hz = 14, .inputClk_Hz = 13000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x46},
148 };
149
150 static const ov7725_special_effect_config_t ov7725SpecialEffectConfigs[] = {
151 /* Normal. */
152 {.effect = CAMERA_SPECIAL_EFFECT_NORMAL, .sde = 0x06, .ufix = 0x80, .vfix = 0x80},
153 /* B & W */
154 {.effect = CAMERA_SPECIAL_EFFECT_BW, .sde = 0x26, .ufix = 0x80, .vfix = 0x80},
155 /* Sepia. */
156 {.effect = CAMERA_SPECIAL_EFFECT_SEPIA, .sde = 0x1e, .ufix = 0x40, .vfix = 0xa0},
157 /* Bluish. */
158 {.effect = CAMERA_SPECIAL_EFFECT_BLUISH, .sde = 0x1e, .ufix = 0xa0, .vfix = 0x40},
159 /* Redish. */
160 {.effect = CAMERA_SPECIAL_EFFECT_REDISH, .sde = 0x1e, .ufix = 0x80, .vfix = 0x40},
161 /* Greenish. */
162 {.effect = CAMERA_SPECIAL_EFFECT_GREENISH, .sde = 0x1e, .ufix = 0x60, .vfix = 0x60},
163 /* Negtive. */
164 {.effect = CAMERA_SPECIAL_EFFECT_NEGTIVE, .sde = 0x46, .ufix = 0x00, .vfix = 0x00},
165 };
166
167 static const ov7725_light_mode_config_t ov7725LightModeConfigs[] = {
168 /* Auto. */
169 {.lightMode = CAMERA_LIGHT_MODE_AUTO, .com8 = 0xff, .blue = 0x80, .red = 0x80, .com5 = 0x65},
170 /* Sunny. */
171 {.lightMode = CAMERA_LIGHT_MODE_SUNNY, .com8 = 0xfd, .blue = 0x5a, .red = 0x5c, .com5 = 0x65},
172 /* Cloudy. */
173 {.lightMode = CAMERA_LIGHT_MODE_CLOUDY, .com8 = 0xfd, .blue = 0x58, .red = 0x60, .com5 = 0x65},
174 /* Office. */
175 {.lightMode = CAMERA_LIGHT_MODE_OFFICE, .com8 = 0xfd, .blue = 0x84, .red = 0x4c, .com5 = 0x65},
176 /* Home. */
177 {.lightMode = CAMERA_LIGHT_MODE_HOME, .com8 = 0xfd, .blue = 0x96, .red = 0x40, .com5 = 0x65},
178 /* Night. */
179 {.lightMode = CAMERA_LIGHT_MODE_NIGHT, .com8 = 0xff, .blue = 0x80, .red = 0x80, .com5 = 0xe5}};
180
181 static const ov7725_pixel_format_config_t ov7725PixelFormatConfigs[] = {
182 {.fmt = kVIDEO_PixelFormatYUYV, .com7 = (0)},
183 {.fmt = kVIDEO_PixelFormatRGB565, .com7 = (1 << 2) | (2)},
184 {.fmt = kVIDEO_PixelFormatXRGB1555, .com7 = (2 << 2) | (2)},
185 {.fmt = kVIDEO_PixelFormatXRGB4444, .com7 = (3 << 2) | (2)}};
186
187 static const ov7725_night_mode_t ov7725NightModeConfigs[] = {
188 {.nightMode = CAMERA_NIGHT_MODE_DISABLED, .com5 = 0},
189 {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY2, .com5 = 8 | (1 << 4)},
190 {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY4, .com5 = 8 | (2 << 4)},
191 {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY8, .com5 = 8 | (3 << 4)}};
192
193 static const ov7725_cmd_func_map_t ov7725CmdFuncMap[] = {
194 {
195 kCAMERA_DeviceLightMode,
196 OV7725_SetLightMode,
197 },
198 {
199 kCAMERA_DeviceSaturation,
200 OV7725_SetSaturation,
201 },
202 {
203 kCAMERA_DeviceBrightness,
204 OV7725_SetBrightness,
205 },
206 {
207 kCAMERA_DeviceContrast,
208 OV7725_SetContrast,
209 },
210 {
211 kCAMERA_DeviceSpecialEffect,
212 OV7725_SetSpecialEffect,
213 },
214 {
215 kCAMERA_DeviceNightMode,
216 OV7725_SetNightMode,
217 },
218 };
219
220 static const ov7725_reg_t ov7725InitRegs[] = {
221 {0x3d, 0x03},
222 {0x42, 0x7f},
223 {0x4d, 0x09},
224
225 /* DSP */
226 {0x64, 0xff},
227 {0x65, 0x20},
228 {0x66, 0x00},
229 {0x67, 0x48},
230 {0x0f, 0xc5},
231 {0x13, 0xff},
232
233 /* AEC/AGC/AWB */
234 {0x63, 0xe0},
235 {0x14, 0x11},
236 {0x22, 0x3f},
237 {0x23, 0x07},
238 {0x24, 0x40},
239 {0x25, 0x30},
240 {0x26, 0xa1},
241 {0x2b, 0x00},
242 {0x6b, 0xaa},
243 {0x0d, 0x41},
244
245 /* Sharpness. */
246 {0x90, 0x05},
247 {0x91, 0x01},
248 {0x92, 0x03},
249 {0x93, 0x00},
250
251 /* Matrix. */
252 {0x94, 0x90},
253 {0x95, 0x8a},
254 {0x96, 0x06},
255 {0x97, 0x0b},
256 {0x98, 0x95},
257 {0x99, 0xa0},
258 {0x9a, 0x1e},
259
260 /* Brightness. */
261 {0x9b, 0x08},
262 /* Contrast. */
263 {0x9c, 0x20},
264 /* UV */
265 {0x9e, 0x81},
266 /* DSE */
267 {0xa6, 0x04},
268
269 /* Gamma. */
270 {0x7e, 0x0c},
271 {0x7f, 0x16},
272 {0x80, 0x2a},
273 {0x81, 0x4e},
274 {0x82, 0x61},
275 {0x83, 0x6f},
276 {0x84, 0x7b},
277 {0x85, 0x86},
278 {0x86, 0x8e},
279 {0x87, 0x97},
280 {0x88, 0xa4},
281 {0x89, 0xaf},
282 {0x8a, 0xc5},
283 {0x8b, 0xd7},
284 {0x8c, 0xe8},
285 };
286
287 /*******************************************************************************
288 * Code
289 ******************************************************************************/
290
OV7725_DelayMs(uint32_t ms)291 static void OV7725_DelayMs(uint32_t ms)
292 {
293 VIDEO_DelayMs(ms);
294 }
295
OV7725_WriteRegs(camera_device_handle_t * handle,const ov7725_reg_t regs[],uint32_t num)296 static status_t OV7725_WriteRegs(camera_device_handle_t *handle, const ov7725_reg_t regs[], uint32_t num)
297 {
298 status_t status = kStatus_Success;
299
300 for (uint32_t i = 0; i < num; i++)
301 {
302 status = OV7725_WriteReg(handle, regs[i].reg, regs[i].val);
303
304 if (kStatus_Success != status)
305 {
306 break;
307 }
308 }
309
310 return status;
311 }
312
OV7725_SoftwareReset(camera_device_handle_t * handle)313 static status_t OV7725_SoftwareReset(camera_device_handle_t *handle)
314 {
315 return OV7725_WriteReg(handle, OV7725_COM7_REG, 0x80);
316 }
317
OV7725_SetClockConfig(camera_device_handle_t * handle,uint32_t frameRate_Hz,uint32_t inputClk_Hz)318 static status_t OV7725_SetClockConfig(camera_device_handle_t *handle, uint32_t frameRate_Hz, uint32_t inputClk_Hz)
319 {
320 status_t status;
321
322 for (uint32_t i = 0; i < ARRAY_SIZE(ov7725ClockConfigs); i++)
323 {
324 if ((ov7725ClockConfigs[i].frameRate_Hz == frameRate_Hz) && (ov7725ClockConfigs[i].inputClk_Hz == inputClk_Hz))
325 {
326 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_CLKRC_REG, ov7725ClockConfigs[i].clkrc));
327 OV7725_CHECK_RET(OV7725_ModifyReg(handle, OV7725_COM4_REG, 0xC0, ov7725ClockConfigs[i].com4));
328 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_EXHCL_REG, 0x00));
329 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_DM_LNL_REG, ov7725ClockConfigs[i].dm_lnl));
330 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_DM_LNH_REG, 0x00));
331 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFL_REG, 0x00));
332 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFH_REG, 0x00));
333 return OV7725_WriteReg(handle, OV7725_COM5_REG, 0x65);
334 }
335 }
336
337 return kStatus_InvalidArgument;
338 }
339
OV7725_SetPixelFormat(camera_device_handle_t * handle,video_pixel_format_t fmt)340 static status_t OV7725_SetPixelFormat(camera_device_handle_t *handle, video_pixel_format_t fmt)
341 {
342 for (uint8_t i = 0; i < ARRAY_SIZE(ov7725PixelFormatConfigs); i++)
343 {
344 if (ov7725PixelFormatConfigs[i].fmt == fmt)
345 {
346 return OV7725_ModifyReg(handle, OV7725_COM7_REG, 0x1FU, ov7725PixelFormatConfigs[i].com7);
347 }
348 }
349
350 return kStatus_InvalidArgument;
351 }
352
OV7725_Init(camera_device_handle_t * handle,const camera_config_t * config)353 status_t OV7725_Init(camera_device_handle_t *handle, const camera_config_t *config)
354 {
355 status_t status;
356 uint8_t pid = 0U, ver = 0U;
357 uint8_t com10 = 0;
358 uint8_t tmpReg;
359 uint16_t width, height;
360 uint16_t hstart, vstart, hsize;
361 ov7725_resource_t *resource = (ov7725_resource_t *)(handle->resource);
362
363 if ((kCAMERA_InterfaceNonGatedClock != config->interface) && (kCAMERA_InterfaceGatedClock != config->interface) &&
364 (kCAMERA_InterfaceCCIR656 != config->interface))
365 {
366 return kStatus_InvalidArgument;
367 }
368
369 width = FSL_VIDEO_EXTRACT_WIDTH(config->resolution);
370 height = FSL_VIDEO_EXTRACT_HEIGHT(config->resolution);
371
372 if ((width > 640U) || (height > 480U))
373 {
374 return kStatus_InvalidArgument;
375 }
376
377 resource->pullPowerDownPin(true);
378
379 /* Delay 1ms. */
380 OV7725_DelayMs(1);
381
382 resource->pullPowerDownPin(false);
383
384 /* Delay 1ms. */
385 OV7725_DelayMs(1);
386
387 resource->pullResetPin(false);
388
389 /* Delay 1ms. */
390 OV7725_DelayMs(1);
391
392 resource->pullResetPin(true);
393
394 /* Delay 1ms. */
395 OV7725_DelayMs(1);
396
397 /* Identify the device. */
398 status = OV7725_ReadReg(handle, OV7725_PID_REG, &pid);
399 if (kStatus_Success != status)
400 {
401 return status;
402 }
403
404 status = OV7725_ReadReg(handle, OV7725_VER_REG, &ver);
405 if (kStatus_Success != status)
406 {
407 return status;
408 }
409
410 if (OV7725_REVISION != (((uint32_t)pid << 8U) | (uint32_t)ver))
411 {
412 return kStatus_Fail;
413 }
414
415 /* Device identify OK, perform software reset. */
416 OV7725_CHECK_RET(OV7725_SoftwareReset(handle));
417
418 /* Delay 2ms. */
419 OV7725_DelayMs(2);
420
421 /* Start configuration */
422 status = OV7725_WriteRegs(handle, ov7725InitRegs, ARRAY_SIZE(ov7725InitRegs));
423 if (kStatus_Success != status)
424 {
425 return status;
426 }
427
428 /* Clock setting. */
429 status = OV7725_SetClockConfig(handle, config->framePerSec, resource->inputClockFreq_Hz);
430 if (kStatus_Success != status)
431 {
432 return status;
433 }
434
435 /* Pixel format setting. */
436 status = OV7725_SetPixelFormat(handle, config->pixelFormat);
437 if (kStatus_Success != status)
438 {
439 return status;
440 }
441
442 if (kCAMERA_InterfaceCCIR656 == config->interface)
443 {
444 status = OV7725_ModifyReg(handle, OV7725_COM7_REG, (1U << 5), (1U << 5));
445 width += 2U;
446 }
447 else
448 {
449 status = OV7725_ModifyReg(handle, OV7725_COM7_REG, (1U << 5), (0U << 5));
450 }
451
452 if (kStatus_Success != status)
453 {
454 return status;
455 }
456
457 if ((uint32_t)kCAMERA_HrefActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_HrefActiveHigh))
458 {
459 com10 |= OV7725_COM10_HREF_REVERSE_MASK;
460 }
461
462 if ((uint32_t)kCAMERA_VsyncActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_VsyncActiveHigh))
463 {
464 com10 |= OV7725_COM10_VSYNC_NEG_MASK;
465 }
466
467 if ((uint32_t)kCAMERA_DataLatchOnRisingEdge != (config->controlFlags & (uint32_t)kCAMERA_DataLatchOnRisingEdge))
468 {
469 com10 |= OV7725_COM10_PCLK_REVERSE_MASK;
470 }
471
472 if (kCAMERA_InterfaceNonGatedClock == config->interface)
473 {
474 com10 |= OV7725_COM10_PCLK_OUT_MASK;
475 }
476
477 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM10_REG, com10));
478
479 /* Don't swap output MSB/LSB. */
480 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM3_REG, 0x00));
481
482 /*
483 * Output drive capability
484 * 0: 1X
485 * 1: 2X
486 * 2: 3X
487 * 3: 4X
488 */
489 OV7725_CHECK_RET(OV7725_ModifyReg(handle, OV7725_COM2_REG, 0x03, 0x03));
490
491 /* Resolution and timing. */
492 hstart = 0x22U << 2U;
493 vstart = 0x07U << 1U;
494 hsize = width + 16U;
495
496 /* Set the window size. */
497 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HSTART_REG, (uint8_t)(hstart >> 2U)));
498 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HSIZE_REG, (uint8_t)(hsize >> 2U)));
499 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VSTART_REG, (uint8_t)(vstart >> 1U)));
500 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VSIZE_REG, (uint8_t)(height >> 1U)));
501 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HOUTSIZE_REG, (uint8_t)(width >> 2U)));
502 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VOUTSIZE_REG, (uint8_t)(height >> 1U)));
503
504 tmpReg = (((uint8_t)vstart & 1U) << 6U) | (((uint8_t)hstart & 3U) << 4U) | (((uint8_t)height & 1U) << 2U) |
505 (((uint8_t)hsize & 3U) << 0U);
506
507 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HREF_REG, tmpReg));
508
509 return OV7725_WriteReg(handle, OV7725_EXHCH_REG, (((uint8_t)height & 1U) << 2U) | (((uint8_t)width & 3U) << 0U));
510 }
511
OV7725_SetSpecialEffect(camera_device_handle_t * handle,int32_t effect)512 status_t OV7725_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect)
513 {
514 uint8_t i;
515 status_t status;
516
517 for (i = 0; i < ARRAY_SIZE(ov7725SpecialEffectConfigs); i++)
518 {
519 if (effect == (int32_t)ov7725SpecialEffectConfigs[i].effect)
520 {
521 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_SDE_REG, ov7725SpecialEffectConfigs[i].sde));
522 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_UFIX_REG, ov7725SpecialEffectConfigs[i].ufix));
523 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VFIX_REG, ov7725SpecialEffectConfigs[i].vfix));
524
525 return OV7725_ModifyReg(handle, OV7725_DSP_CTRL1_REG, 1U << 5, 1U << 5);
526 }
527 }
528
529 /* No configuration found. */
530 return kStatus_InvalidArgument;
531 }
532
OV7725_SetContrast(camera_device_handle_t * handle,int32_t contrast)533 status_t OV7725_SetContrast(camera_device_handle_t *handle, int32_t contrast)
534 {
535 if ((contrast < -4) || (contrast > 4))
536 {
537 return kStatus_InvalidArgument;
538 }
539
540 contrast *= 4;
541 contrast += 0x20;
542
543 return OV7725_WriteReg(handle, OV7725_CNST_REG, (uint8_t)contrast);
544 }
545
OV7725_SetBrightness(camera_device_handle_t * handle,int32_t brightness)546 status_t OV7725_SetBrightness(camera_device_handle_t *handle, int32_t brightness)
547 {
548 status_t status;
549
550 if ((brightness < -4) || (brightness > 4))
551 {
552 return kStatus_InvalidArgument;
553 }
554
555 if (brightness >= 0)
556 {
557 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BRIGHT_REG, 0x08U + (0x10U * (uint8_t)brightness)));
558 return OV7725_WriteReg(handle, OV7725_SIGN_REG, 0x06);
559 }
560 else
561 {
562 brightness = -brightness - 1;
563 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BRIGHT_REG, 0x08U + (0x10U * (uint8_t)brightness)));
564 return OV7725_WriteReg(handle, OV7725_SIGN_REG, 0x0e);
565 }
566 }
567
OV7725_SetSaturation(camera_device_handle_t * handle,int32_t saturation)568 status_t OV7725_SetSaturation(camera_device_handle_t *handle, int32_t saturation)
569 {
570 status_t status;
571
572 if ((saturation < -4) || (saturation > 4))
573 {
574 return kStatus_InvalidArgument;
575 }
576
577 saturation += 4;
578 uint8_t val = (uint8_t)saturation * 0x10U;
579
580 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_USAT_REG, val));
581 return OV7725_WriteReg(handle, OV7725_VSAT_REG, val);
582 }
583
OV7725_SetLightMode(camera_device_handle_t * handle,int32_t lightMode)584 status_t OV7725_SetLightMode(camera_device_handle_t *handle, int32_t lightMode)
585 {
586 uint8_t i;
587 status_t status;
588
589 for (i = 0; i < ARRAY_SIZE(ov7725LightModeConfigs); i++)
590 {
591 if (lightMode == (int32_t)ov7725LightModeConfigs[i].lightMode)
592 {
593 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM8_REG, ov7725LightModeConfigs[i].com8));
594 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BLUE_REG, ov7725LightModeConfigs[i].blue));
595 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_RED_REG, ov7725LightModeConfigs[i].red));
596 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM5_REG, ov7725LightModeConfigs[i].com5));
597 OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFL_REG, 0));
598 return OV7725_WriteReg(handle, OV7725_ADVFH_REG, 0);
599 }
600 }
601
602 /* No configuration found. */
603 return kStatus_InvalidArgument;
604 }
605
OV7725_SetNightMode(camera_device_handle_t * handle,int32_t nightMode)606 status_t OV7725_SetNightMode(camera_device_handle_t *handle, int32_t nightMode)
607 {
608 uint8_t i;
609
610 for (i = 0; i < ARRAY_SIZE(ov7725NightModeConfigs); i++)
611 {
612 if (nightMode == (int32_t)ov7725NightModeConfigs[i].nightMode)
613 {
614 return OV7725_ModifyReg(handle, OV7725_COM5_REG, 0xF0, ov7725NightModeConfigs[i].com5);
615 }
616 }
617
618 /* No configuration found. */
619 return kStatus_InvalidArgument;
620 }
621
OV7725_Deinit(camera_device_handle_t * handle)622 status_t OV7725_Deinit(camera_device_handle_t *handle)
623 {
624 ((ov7725_resource_t *)(handle->resource))->pullPowerDownPin(true);
625
626 return kStatus_Success;
627 }
628
OV7725_Control(camera_device_handle_t * handle,camera_device_cmd_t cmd,int32_t arg)629 status_t OV7725_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg)
630 {
631 for (uint8_t i = 0; i < ARRAY_SIZE(ov7725CmdFuncMap); i++)
632 {
633 if (ov7725CmdFuncMap[i].cmd == cmd)
634 {
635 return ov7725CmdFuncMap[i].func(handle, arg);
636 }
637 }
638
639 return kStatus_InvalidArgument;
640 }
641
OV7725_Start(camera_device_handle_t * handle)642 status_t OV7725_Start(camera_device_handle_t *handle)
643 {
644 return kStatus_Success;
645 }
646
OV7725_Stop(camera_device_handle_t * handle)647 status_t OV7725_Stop(camera_device_handle_t *handle)
648 {
649 return kStatus_Success;
650 }
651
OV7725_InitExt(camera_device_handle_t * handle,const camera_config_t * config,const void * specialConfig)652 status_t OV7725_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig)
653 {
654 return OV7725_Init(handle, config);
655 }
656