Skip to content

Commit 9f81952

Browse files
committed
drivers: video Add OV7675 changes to OV767x
drivers: video Add OV7675 changes to OV767x Add in the changes required to support OV7675 camera. Signed-off-by: Mike S <[email protected]>
1 parent bf7b023 commit 9f81952

File tree

5 files changed

+237
-59
lines changed

5 files changed

+237
-59
lines changed

drivers/video/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c)
1818
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c)
1919
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov767x.c)
2020
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV9655 ov9655.c)
21+
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7675 ov767x.c)
2122
zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c)
2223
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c)
2324
zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_IMAGER video_emul_imager.c)

drivers/video/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ source "drivers/video/Kconfig.ov5640"
8080

8181
source "drivers/video/Kconfig.ov7670"
8282

83+
source "drivers/video/Kconfig.ov7675"
84+
8385
source "drivers/video/Kconfig.ov9655"
8486

8587
source "drivers/video/Kconfig.gc2145"

drivers/video/Kconfig.ov7675

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2024 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config VIDEO_OV7675
5+
bool "OV7675 CMOS digital image sensor"
6+
select I2C
7+
depends on DT_HAS_OVTI_OV7675_ENABLED
8+
default y
9+
help
10+
Enable driver for OV7675 CMOS digital image sensor device.

drivers/video/ov767x.c

Lines changed: 200 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ struct ov767x_config {
2424
struct i2c_dt_spec bus;
2525
uint32_t camera_model;
2626
const struct video_format_cap *fmts;
27-
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
27+
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) || \
28+
DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, reset_gpios)
2829
struct gpio_dt_spec reset;
2930
#endif
30-
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(pwdn_gpios)
31+
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) || \
32+
DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, pwdn_gpios)
3133
struct gpio_dt_spec pwdn;
3234
#endif
3335
};
@@ -132,6 +134,16 @@ struct ov767x_data {
132134
#define OV7670_HAECC5 0xA8
133135
#define OV7670_HAECC6 0xA9
134136

137+
/* Addition defines for OV7675 */
138+
#define OV7675_RGB444 0x8C /* REG444 */
139+
#define OV7675_COM3_DCW_EN 0x04 /* DCW enable */
140+
#define OV7670_COM1 0x04 /*Com Cntrl1 */
141+
#define OV7675_COM7_RGB_FMT 0x04 /* Output format RGB */
142+
#define OV7675_COM13_GAMMA_EN 0x80 /* Gamma enable */
143+
#define OV7675_COM13_UVSAT_AUTO 0x40 /* UV saturation level - UV auto adjustment. */
144+
#define OV7675_COM15_OUT_00_FF 0xC0 /* Output data range 00 to FF */
145+
#define OV7675_COM15_FMT_RGB565 0x10 /* Normal RGB 565 output */
146+
135147
/* OV7670 definitions */
136148
#define OV7670_PROD_ID 0x76
137149
#define OV7670_MVFP_HFLIP 0x20
@@ -141,11 +153,12 @@ struct ov767x_data {
141153
#define OV767X_MODEL_OV7675 7675
142154

143155
#define OV767X_VIDEO_FORMAT_CAP(width, height, format) \
144-
{ \
145-
.pixelformat = (format), .width_min = (width), .width_max = (width), \
146-
.height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \
147-
}
156+
{ \
157+
.pixelformat = (format), .width_min = (width), .width_max = (width), \
158+
.height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \
159+
}
148160

161+
#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670)
149162
static const struct video_format_cap ov7670_fmts[] = {
150163
OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */
151164
OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
@@ -157,6 +170,19 @@ static const struct video_format_cap ov7670_fmts[] = {
157170
OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */
158171
{0}
159172
};
173+
#endif
174+
175+
#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7675)
176+
static const struct video_format_cap ov7675_fmts[] = {
177+
OV767X_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565), /* QQVGA */
178+
OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
179+
OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */
180+
OV767X_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_YUYV), /* QQVGA */
181+
OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */
182+
OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */
183+
{0}
184+
};
185+
#endif
160186

161187
/*
162188
* This initialization table is based on the MCUX SDK driver for the OV7670.
@@ -167,7 +193,7 @@ static const struct video_reg8 ov767x_init_regtbl[] = {
167193

168194
/* configure the output timing */
169195
/* PCLK does not toggle during horizontal blank, one PCLK, one pixel */
170-
{OV7670_COM10, 0x20}, /* COM10 */
196+
{OV7670_COM10, 0x03}, /* COM10 */
171197
{OV7670_COM12, 0x00}, /* COM12,No HREF when VSYNC is low */
172198
/* Brightness Control, with signal -128 to +128, 0x00 is middle value */
173199
{OV7670_BRIGHT, 0x2f},
@@ -316,6 +342,37 @@ static const struct video_reg8 ov767x_init_regtbl[] = {
316342
{0xb8, 0x0a},
317343
};
318344

345+
static const struct video_reg8 ov767x_rgb565_regs[] = {
346+
{OV7670_COM7, OV7675_COM7_RGB_FMT}, /* Selects RGB mode */
347+
{OV7675_RGB444, 0x00}, /* No RGB444 please */
348+
{OV7670_COM1, 0x00}, /* CCIR601 */
349+
{OV7670_COM15, OV7675_COM15_OUT_00_FF | OV7675_COM15_FMT_RGB565},
350+
{OV7670_COM9, 0x38}, /* 16x gain ceiling; 0x8 is reserved bit */
351+
{0x4f, 0xb3}, /* "matrix coefficient 1" */
352+
{0x50, 0xb3}, /* "matrix coefficient 2" */
353+
{0x51, 0x00}, /* "matrix Coefficient 3" */
354+
{0x52, 0x3d}, /* "matrix coefficient 4" */
355+
{0x53, 0xa7}, /* "matrix coefficient 5" */
356+
{0x54, 0xe4}, /* "matrix coefficient 6" */
357+
{OV7670_COM13, OV7675_COM13_GAMMA_EN | OV7675_COM13_UVSAT_AUTO},
358+
};
359+
360+
/* TODO: These registers probably need to be fixed too. */
361+
static const struct video_reg8 ov767x_yuv422_regs[] = {
362+
{OV7670_COM7, 0x00}, /* Selects YUV mode */
363+
{OV7675_RGB444, 0x00}, /* No RGB444 please */
364+
{OV7670_COM1, 0x00}, /* CCIR601 */
365+
{OV7670_COM15, OV7675_COM15_OUT_00_FF},
366+
{OV7670_COM9, 0x48}, /* 32x gain ceiling; 0x8 is reserved bit */
367+
{0x4f, 0x80}, /* "matrix coefficient 1" */
368+
{0x50, 0x80}, /* "matrix coefficient 2" */
369+
{0x51, 0x00}, /* vb */
370+
{0x52, 0x22}, /* "matrix coefficient 4" */
371+
{0x53, 0x5e}, /* "matrix coefficient 5" */
372+
{0x54, 0x80}, /* "matrix coefficient 6" */
373+
{OV7670_COM13, OV7675_COM13_GAMMA_EN | OV7675_COM13_UVSAT_AUTO},
374+
};
375+
319376
/* Resolution settings for camera, based on those present in MCUX SDK */
320377
static const struct video_reg8 ov7670_regs_qcif[] = {
321378
{OV7670_COM7, 0x2c},
@@ -361,6 +418,39 @@ static const struct video_reg8 ov7670_regs_vga[] = {
361418
{OV7670_SCALING_PCLK_DELAY, 0x02},
362419
};
363420

421+
static const struct video_reg8 ov7675_regs_vga[] = {
422+
{OV7670_COM3, 0x00}, {OV7670_COM14, 0x00}, {0x72, 0x11}, /* downsample by 4 */
423+
{0x73, 0xf0}, /* divide by 4 */
424+
{OV7670_HSTART, 0x12}, {OV7670_HSTOP, 0x00}, {OV7670_HREF, 0xb6},
425+
{OV7670_VSTRT, 0x02}, {OV7670_VSTOP, 0x7a}, {OV7670_VREF, 0x00},
426+
};
427+
428+
static const struct video_reg8 ov7675_regs_qvga[] = {
429+
{OV7670_COM3, OV7675_COM3_DCW_EN},
430+
{OV7670_COM14, 0x11}, /* Divide by 2 */
431+
{0x72, 0x22}, /* This has no effect on OV7675 */
432+
{0x73, 0xf2}, /* This has no effect on OV7675 */
433+
{OV7670_HSTART, 0x15},
434+
{OV7670_HSTOP, 0x03},
435+
{OV7670_HREF, 0xC0},
436+
{OV7670_VSTRT, 0x03},
437+
{OV7670_VSTOP, 0x7B},
438+
{OV7670_VREF, 0xF0},
439+
};
440+
441+
static const struct video_reg8 ov7675_regs_qqvga[] = {
442+
{OV7670_COM3, OV7675_COM3_DCW_EN},
443+
{OV7670_COM14, 0x11}, /* Divide by 2 */
444+
{0x72, 0x22}, /* This has no effect on OV7675*/
445+
{0x73, 0xf2}, /* This has no effect on OV7675*/
446+
{OV7670_HSTART, 0x16},
447+
{OV7670_HSTOP, 0x04},
448+
{OV7670_HREF, 0xa4},
449+
{OV7670_VSTRT, 0x22},
450+
{OV7670_VSTOP, 0x7a},
451+
{OV7670_VREF, 0xfa},
452+
};
453+
364454
static int ov767x_get_caps(const struct device *dev, struct video_caps *caps)
365455
{
366456
const struct ov767x_config *config = dev->config;
@@ -369,8 +459,7 @@ static int ov767x_get_caps(const struct device *dev, struct video_caps *caps)
369459
return 0;
370460
}
371461

372-
#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670)
373-
static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
462+
static int ov767x_set_fmt(const struct device *dev, struct video_format *fmt)
374463
{
375464
const struct ov767x_config *config = dev->config;
376465
struct ov767x_data *data = dev->data;
@@ -382,66 +471,112 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
382471
return -ENOTSUP;
383472
}
384473

385-
/* Set output resolution */
386-
while (config->fmts[i].pixelformat) {
387-
if (config->fmts[i].width_min == fmt->width &&
388-
config->fmts[i].height_min == fmt->height &&
389-
config->fmts[i].pixelformat == fmt->pixelformat) {
390-
/* Set output format */
391-
switch (config->fmts[i].width_min) {
392-
case 176: /* QCIF */
393-
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qcif,
394-
ARRAY_SIZE(ov7670_regs_qcif));
395-
break;
396-
case 352: /* QCIF */
397-
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_cif,
398-
ARRAY_SIZE(ov7670_regs_cif));
399-
break;
400-
case 320: /* QVGA */
401-
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
402-
ARRAY_SIZE(ov7670_regs_qvga));
403-
break;
404-
case 640: /* VGA */
405-
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_vga,
406-
ARRAY_SIZE(ov7670_regs_vga));
407-
break;
408-
default: /* QVGA */
409-
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
410-
ARRAY_SIZE(ov7670_regs_vga));
411-
break;
412-
}
413-
if (ret < 0) {
414-
LOG_ERR("Resolution not set!");
415-
return ret;
416-
}
417-
}
418-
i++;
474+
if (!memcmp(&data->fmt, fmt, sizeof(data->fmt))) {
475+
/* nothing to do */
476+
return 0;
477+
}
478+
479+
/* Set RGB Format */
480+
if (fmt->pixelformat == VIDEO_PIX_FMT_RGB565) {
481+
ret = video_write_cci_multiregs8(&config->bus, ov767x_rgb565_regs,
482+
ARRAY_SIZE(ov767x_rgb565_regs));
483+
} else if (fmt->pixelformat == VIDEO_PIX_FMT_YUYV) {
484+
ret = video_write_cci_multiregs8(&config->bus, ov767x_yuv422_regs,
485+
ARRAY_SIZE(ov767x_yuv422_regs));
486+
} else {
487+
LOG_ERR("Image format not supported");
488+
ret = -ENOTSUP;
419489
}
420490

421491
if (ret < 0) {
422-
LOG_ERR("Resolution not supported!");
492+
LOG_ERR("Format not set!");
423493
return ret;
424494
}
425495

426-
return 0;
427-
}
428-
#endif
429-
430-
static int ov767x_set_fmt(const struct device *dev, struct video_format *fmt)
431-
{
432-
int ret;
496+
/* Set output resolution */
497+
if (config->camera_model == OV767X_MODEL_OV7670) {
498+
while (config->fmts[i].pixelformat) {
499+
if (config->fmts[i].width_min == fmt->width &&
500+
config->fmts[i].height_min == fmt->height &&
501+
config->fmts[i].pixelformat == fmt->pixelformat) {
502+
/* Set output format */
503+
switch (config->fmts[i].width_min) {
504+
case 176: /* QCIF */
505+
ret = video_write_cci_multiregs8(
506+
&config->bus, ov7670_regs_qcif,
507+
ARRAY_SIZE(ov7670_regs_qcif));
508+
break;
509+
case 352: /* QCIF */
510+
ret = video_write_cci_multiregs8(
511+
&config->bus, ov7670_regs_cif,
512+
ARRAY_SIZE(ov7670_regs_cif));
513+
break;
514+
case 320: /* QVGA */
515+
ret = video_write_cci_multiregs8(
516+
&config->bus, ov7670_regs_qvga,
517+
ARRAY_SIZE(ov7670_regs_qvga));
518+
break;
519+
case 640: /* VGA */
520+
ret = video_write_cci_multiregs8(
521+
&config->bus, ov7670_regs_vga,
522+
ARRAY_SIZE(ov7670_regs_vga));
523+
break;
524+
default: /* QVGA */
525+
ret = video_write_cci_multiregs8(
526+
&config->bus, ov7670_regs_qvga,
527+
ARRAY_SIZE(ov7670_regs_vga));
528+
break;
529+
}
530+
if (ret < 0) {
531+
LOG_ERR("Resolution not set!");
532+
return ret;
533+
}
534+
}
535+
i++;
536+
}
537+
}
433538

434-
if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) {
435-
LOG_ERR("Only RGB565 and YUYV supported!");
436-
return -ENOTSUP;
539+
if (config->camera_model == OV767X_MODEL_OV7675) {
540+
while (config->fmts[i].pixelformat) {
541+
if (config->fmts[i].width_min == fmt->width &&
542+
config->fmts[i].height_min == fmt->height &&
543+
config->fmts[i].pixelformat == fmt->pixelformat) {
544+
/* Set output format */
545+
switch (config->fmts[i].width_min) {
546+
case 160: /* QQVGA */
547+
ret = video_write_cci_multiregs8(
548+
&config->bus, ov7675_regs_qqvga,
549+
ARRAY_SIZE(ov7675_regs_qqvga));
550+
break;
551+
case 320: /* QVGA */
552+
ret = video_write_cci_multiregs8(
553+
&config->bus, ov7675_regs_qvga,
554+
ARRAY_SIZE(ov7675_regs_qvga));
555+
break;
556+
case 640: /* VGA */
557+
ret = video_write_cci_multiregs8(
558+
&config->bus, ov7675_regs_vga,
559+
ARRAY_SIZE(ov7675_regs_vga));
560+
break;
561+
default: /* QVGA */
562+
ret = video_write_cci_multiregs8(
563+
&config->bus, ov7675_regs_qvga,
564+
ARRAY_SIZE(ov7675_regs_qvga));
565+
break;
566+
}
567+
if (ret < 0) {
568+
LOG_ERR("Resolution not set!");
569+
return ret;
570+
}
571+
}
572+
i++;
573+
}
437574
}
438575

439-
#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670)
440-
ret = ov7670_set_fmt(dev, fmt);
441576
if (ret < 0) {
577+
LOG_ERR("Resolution not supported!");
442578
return ret;
443579
}
444-
#endif
445580

446581
return 0;
447582
}
@@ -486,7 +621,8 @@ static int ov767x_init(const struct device *dev)
486621
return -ENODEV;
487622
}
488623

489-
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios)
624+
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) || \
625+
DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, pwdn_gpios)
490626
/* Power up camera module */
491627
if (config->pwdn.port != NULL) {
492628
if (!gpio_is_ready_dt(&config->pwdn)) {
@@ -500,7 +636,8 @@ static int ov767x_init(const struct device *dev)
500636
}
501637
#endif
502638

503-
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios)
639+
#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) || \
640+
DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, reset_gpios)
504641
/* Reset camera module */
505642
if (config->reset.port != NULL) {
506643
if (!gpio_is_ready_dt(&config->reset)) {
@@ -629,3 +766,7 @@ static DEVICE_API(video, ov767x_api) = {
629766
#undef DT_DRV_COMPAT
630767
#define DT_DRV_COMPAT ovti_ov7670
631768
DT_INST_FOREACH_STATUS_OKAY_VARGS(OV767X_INIT, 7670)
769+
770+
#undef DT_DRV_COMPAT
771+
#define DT_DRV_COMPAT ovti_ov7675
772+
DT_INST_FOREACH_STATUS_OKAY_VARGS(OV767X_INIT, 7675)

0 commit comments

Comments
 (0)