Skip to content

Commit edcc6b6

Browse files
committed
drivers: video: ov7670 driver changes in prep for adding OV7675
drivers: video: ov7670 driver changes in prep for adding OV7675 drivers: video: ov7670 driver changes in prep for adding OV7675 Updates ov7670.c in prep for incorporation of OV7675. See previous PR. Includes revisions requested by reviewers (9/25). Signed-off-by: Michael Smorto <[email protected]>
1 parent 0e3cd5b commit edcc6b6

File tree

1 file changed

+122
-155
lines changed

1 file changed

+122
-155
lines changed

drivers/video/ov7670.c

Lines changed: 122 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,18 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
#define DT_DRV_COMPAT ovti_ov7670
8-
97
#include <zephyr/drivers/gpio.h>
108
#include <zephyr/drivers/i2c.h>
119
#include <zephyr/drivers/video.h>
1210
#include <zephyr/drivers/video-controls.h>
1311
#include <zephyr/logging/log.h>
1412

13+
#include "video_common.h"
1514
#include "video_ctrls.h"
1615
#include "video_device.h"
1716

1817
LOG_MODULE_REGISTER(video_ov7670, CONFIG_VIDEO_LOG_LEVEL);
1918

20-
/* Initialization register structure */
21-
struct ov7670_reg {
22-
uint8_t reg;
23-
uint8_t cmd;
24-
};
25-
2619
struct ov7670_config {
2720
struct i2c_dt_spec bus;
2821
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
@@ -43,63 +36,7 @@ struct ov7670_data {
4336
struct video_format fmt;
4437
};
4538

46-
struct ov7670_resolution_cfg {
47-
uint8_t com7;
48-
uint8_t com3;
49-
uint8_t com14;
50-
uint8_t scaling_xsc;
51-
uint8_t scaling_ysc;
52-
uint8_t dcwctr;
53-
uint8_t pclk_div;
54-
uint8_t pclk_delay;
55-
};
56-
57-
/* Resolution settings for camera, based on those present in MCUX SDK */
58-
const struct ov7670_resolution_cfg OV7670_RESOLUTION_QCIF = {
59-
.com7 = 0x2c,
60-
.com3 = 0x00,
61-
.com14 = 0x11,
62-
.scaling_xsc = 0x3a,
63-
.scaling_ysc = 0x35,
64-
.dcwctr = 0x11,
65-
.pclk_div = 0xf1,
66-
.pclk_delay = 0x52
67-
};
68-
69-
const struct ov7670_resolution_cfg OV7670_RESOLUTION_QVGA = {
70-
.com7 = 0x14,
71-
.com3 = 0x04,
72-
.com14 = 0x19,
73-
.scaling_xsc = 0x3a,
74-
.scaling_ysc = 0x35,
75-
.dcwctr = 0x11,
76-
.pclk_div = 0xf1,
77-
.pclk_delay = 0x02
78-
};
79-
80-
const struct ov7670_resolution_cfg OV7670_RESOLUTION_CIF = {
81-
.com7 = 0x24,
82-
.com3 = 0x08,
83-
.com14 = 0x11,
84-
.scaling_xsc = 0x3a,
85-
.scaling_ysc = 0x35,
86-
.dcwctr = 0x11,
87-
.pclk_div = 0xf1,
88-
.pclk_delay = 0x02
89-
};
90-
91-
const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = {
92-
.com7 = 0x04,
93-
.com3 = 0x00,
94-
.com14 = 0x00,
95-
.scaling_xsc = 0x3a,
96-
.scaling_ysc = 0x35,
97-
.dcwctr = 0x11,
98-
.pclk_div = 0xf0,
99-
.pclk_delay = 0x02
100-
};
101-
102-
39+
#define OV7670_REG8(addr) ((addr) | VIDEO_REG_ADDR8_DATA8)
10340
/* OV7670 registers */
10441
#define OV7670_PID 0x0A
10542
#define OV7670_COM7 0x12
@@ -190,32 +127,21 @@ const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = {
190127
#define OV7670_HAECC6 0xA9
191128

192129
/* OV7670 definitions */
193-
#define OV7670_PROD_ID 0x76
130+
#define OV7670_PROD_ID 0x76
194131
#define OV7670_MVFP_HFLIP 0x20
195132
#define OV7670_MVFP_VFLIP 0x10
196133

197-
#define OV7670_VIDEO_FORMAT_CAP(width, height, format) \
134+
#define OV767X_VIDEO_FORMAT_CAP(width, height, format) \
198135
{ \
199136
.pixelformat = (format), .width_min = (width), .width_max = (width), \
200137
.height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \
201138
}
202139

203-
static const struct video_format_cap fmts[] = {
204-
OV7670_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */
205-
OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
206-
OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */
207-
OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */
208-
OV7670_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_YUYV), /* QCIF */
209-
OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */
210-
OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */
211-
OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */
212-
{0}};
213-
214140
/*
215141
* This initialization table is based on the MCUX SDK driver for the OV7670.
216142
* Note that this table assumes the camera is fed a 6MHz XCLK signal
217143
*/
218-
static const struct ov7670_reg ov7670_init_regtbl[] = {
144+
static const struct video_reg8 ov7670_init_regtbl[] = {
219145
{OV7670_MVFP, 0x00}, /* MVFP: Mirror/VFlip,Normal image */
220146

221147
/* configure the output timing */
@@ -369,8 +295,66 @@ static const struct ov7670_reg ov7670_init_regtbl[] = {
369295
{0xb8, 0x0a},
370296
};
371297

298+
/* Resolution settings for camera, based on those present in MCUX SDK */
299+
static const struct video_reg8 ov7670_regs_qcif[] = {
300+
{OV7670_COM7, 0x2c},
301+
{OV7670_COM3, 0x00},
302+
{OV7670_COM14, 0x11},
303+
{OV7670_SCALING_XSC, 0x3a},
304+
{OV7670_SCALING_YSC, 0x35},
305+
{OV7670_SCALING_DCWCTR, 0x11},
306+
{OV7670_SCALING_PCLK_DIV, 0xf1},
307+
{OV7670_SCALING_PCLK_DELAY, 0x52},
308+
};
309+
310+
static const struct video_reg8 ov7670_regs_qvga[] = {
311+
{OV7670_COM7, 0x14},
312+
{OV7670_COM3, 0x04},
313+
{OV7670_COM14, 0x19},
314+
{OV7670_SCALING_XSC, 0x3a},
315+
{OV7670_SCALING_YSC, 0x35},
316+
{OV7670_SCALING_DCWCTR, 0x11},
317+
{OV7670_SCALING_PCLK_DIV, 0xf1},
318+
{OV7670_SCALING_PCLK_DELAY, 0x02},
319+
};
320+
321+
static const struct video_reg8 ov7670_regs_cif[] = {
322+
{OV7670_COM7, 0x24},
323+
{OV7670_COM3, 0x08},
324+
{OV7670_COM14, 0x11},
325+
{OV7670_SCALING_XSC, 0x3a},
326+
{OV7670_SCALING_YSC, 0x35},
327+
{OV7670_SCALING_DCWCTR, 0x11},
328+
{OV7670_SCALING_PCLK_DIV, 0xf1},
329+
{OV7670_SCALING_PCLK_DELAY, 0x02},
330+
};
331+
332+
static const struct video_reg8 ov7670_regs_vga[] = {
333+
{OV7670_COM7, 0x04},
334+
{OV7670_COM3, 0x00},
335+
{OV7670_COM14, 0x00},
336+
{OV7670_SCALING_XSC, 0x3a},
337+
{OV7670_SCALING_YSC, 0x35},
338+
{OV7670_SCALING_DCWCTR, 0x11},
339+
{OV7670_SCALING_PCLK_DIV, 0xf0},
340+
{OV7670_SCALING_PCLK_DELAY, 0x02},
341+
};
342+
343+
static const struct video_format_cap fmts[] = {
344+
OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */
345+
OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
346+
OV767X_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */
347+
OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */
348+
OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_YUYV), /* QCIF */
349+
OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */
350+
OV767X_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */
351+
OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */
352+
{0}
353+
};
354+
372355
static int ov7670_get_caps(const struct device *dev, struct video_caps *caps)
373356
{
357+
374358
caps->format_caps = fmts;
375359
return 0;
376360
}
@@ -379,9 +363,8 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
379363
{
380364
const struct ov7670_config *config = dev->config;
381365
struct ov7670_data *data = dev->data;
382-
const struct ov7670_resolution_cfg *resolution;
383366
int ret;
384-
uint8_t i = 0U;
367+
uint8_t icount = 0U;
385368

386369
if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) {
387370
LOG_ERR("Only RGB565 and YUYV supported!");
@@ -395,69 +378,46 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
395378

396379
memcpy(&data->fmt, fmt, sizeof(data->fmt));
397380

381+
uint32_t a, b, c;
382+
398383
/* Set output resolution */
399-
while (fmts[i].pixelformat) {
400-
if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height &&
401-
fmts[i].pixelformat == fmt->pixelformat) {
384+
ret = -ENOTSUP;
385+
icount = 0;
386+
while (fmts[icount].pixelformat) {
387+
a = fmts[icount].width_min;
388+
b = fmts[icount].height_min;
389+
c = fmts[icount].pixelformat;
390+
if (a == fmt->width && b == fmt->height && c == fmt->pixelformat) {
402391
/* Set output format */
403-
switch (fmts[i].width_min) {
392+
switch (fmts[icount].width_min) {
404393
case 176: /* QCIF */
405-
resolution = &OV7670_RESOLUTION_QCIF;
406-
break;
407-
case 320: /* QVGA */
408-
resolution = &OV7670_RESOLUTION_QVGA;
394+
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qcif,
395+
ARRAY_SIZE(ov7670_regs_qcif));
409396
break;
410-
case 352: /* CIF */
411-
resolution = &OV7670_RESOLUTION_CIF;
397+
case 352: /* QCIF */
398+
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_cif,
399+
ARRAY_SIZE(ov7670_regs_cif));
412400
break;
413-
default: /* VGA */
414-
resolution = &OV7670_RESOLUTION_VGA;
401+
case 320: /* QVGA */
402+
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
403+
ARRAY_SIZE(ov7670_regs_qvga));
404+
case 640: /* VGA */
405+
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_vga,
406+
ARRAY_SIZE(ov7670_regs_vga));
407+
default: /* QVGA */
408+
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
409+
ARRAY_SIZE(ov7670_regs_vga));
415410
break;
416411
}
417-
/* Program resolution bytes settings */
418-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7,
419-
resolution->com7);
420412
if (ret < 0) {
413+
LOG_ERR("Resolution not set!");
421414
return ret;
422415
}
423-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM3,
424-
resolution->com3);
425-
if (ret < 0) {
426-
return ret;
427-
}
428-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM14,
429-
resolution->com14);
430-
if (ret < 0) {
431-
return ret;
432-
}
433-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_XSC,
434-
resolution->scaling_xsc);
435-
if (ret < 0) {
436-
return ret;
437-
}
438-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_YSC,
439-
resolution->scaling_ysc);
440-
if (ret < 0) {
441-
return ret;
442-
}
443-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_DCWCTR,
444-
resolution->dcwctr);
445-
if (ret < 0) {
446-
return ret;
447-
}
448-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DIV,
449-
resolution->pclk_div);
450-
if (ret < 0) {
451-
return ret;
452-
}
453-
return i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DELAY,
454-
resolution->pclk_delay);
455416
}
456-
i++;
417+
icount++;
457418
}
458419

459-
LOG_ERR("Unsupported format");
460-
return -ENOTSUP;
420+
return ret;
461421
}
462422

463423
static int ov7670_get_fmt(const struct device *dev, struct video_format *fmt)
@@ -487,14 +447,13 @@ static int ov7670_init_controls(const struct device *dev)
487447
static int ov7670_init(const struct device *dev)
488448
{
489449
const struct ov7670_config *config = dev->config;
490-
int ret, i;
450+
int ret;
491451
uint8_t pid;
492452
struct video_format fmt = {
493453
.pixelformat = VIDEO_PIX_FMT_RGB565,
494454
.width = 320,
495455
.height = 240,
496456
};
497-
const struct ov7670_reg *reg;
498457

499458
if (!i2c_is_ready_dt(&config->bus)) {
500459
/* I2C device is not ready, return */
@@ -559,7 +518,7 @@ static int ov7670_init(const struct device *dev)
559518
}
560519

561520
/* Reset camera registers */
562-
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7, 0x80);
521+
ret = video_write_cci_reg(&config->bus, OV7670_REG8(OV7670_COM7), 0x80);
563522
if (ret < 0) {
564523
LOG_ERR("Could not reset camera: %d", ret);
565524
return ret;
@@ -573,12 +532,10 @@ static int ov7670_init(const struct device *dev)
573532
}
574533

575534
/* Write initialization values to OV7670 */
576-
for (i = 0; i < ARRAY_SIZE(ov7670_init_regtbl); i++) {
577-
reg = &ov7670_init_regtbl[i];
578-
ret = i2c_reg_write_byte_dt(&config->bus, reg->reg, reg->cmd);
579-
if (ret < 0) {
580-
return ret;
581-
}
535+
ret = video_write_cci_multiregs8(&config->bus, ov7670_init_regtbl,
536+
ARRAY_SIZE(ov7670_init_regtbl));
537+
if (ret < 0) {
538+
return ret;
582539
}
583540

584541
/* Initialize controls */
@@ -617,26 +574,36 @@ static DEVICE_API(video, ov7670_api) = {
617574
};
618575

619576
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
620-
#define OV7670_RESET_GPIO(inst) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}),
577+
#define OV7670_RESET_GPIO(n) .reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}),
621578
#else
622-
#define OV7670_RESET_GPIO(inst)
579+
#define OV7670_RESET_GPIO(n)
623580
#endif
624581

625582
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(pwdn_gpios)
626-
#define OV7670_PWDN_GPIO(inst) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}),
583+
#define OV7670_PWDN_GPIO(n) .pwdn = GPIO_DT_SPEC_INST_GET_OR(n, pwdn_gpios, {}),
627584
#else
628-
#define OV7670_PWDN_GPIO(inst)
585+
#define OV7670_PWDN_GPIO(n)
629586
#endif
630587

631-
#define OV7670_INIT(inst) \
632-
const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \
633-
OV7670_RESET_GPIO(inst) \
634-
OV7670_PWDN_GPIO(inst)}; \
635-
struct ov7670_data ov7670_data_##inst; \
636-
\
637-
DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \
638-
POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov7670_api); \
639-
\
640-
VIDEO_DEVICE_DEFINE(ov7670_##inst, DEVICE_DT_INST_GET(inst), NULL);
641-
588+
#define OV7670_INIT(n) \
589+
const struct ov7670_config ov7670_config_##n = { \
590+
.bus = I2C_DT_SPEC_INST_GET(n), \
591+
OV7670_RESET_GPIO(n) \
592+
OV7670_PWDN_GPIO(n)}; \
593+
\
594+
static struct ov7670_data ov7670_data_##n; \
595+
\
596+
DEVICE_DT_INST_DEFINE(n, \
597+
ov7670_init, \
598+
NULL, \
599+
&ov7670_data_##n, \
600+
&ov7670_config_##n, \
601+
POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
602+
&ov7670_api); \
603+
\
604+
VIDEO_DEVICE_DEFINE(ov7670_##n, DEVICE_DT_INST_GET(n), NULL); \
605+
606+
607+
#undef DT_DRV_COMPAT
608+
#define DT_DRV_COMPAT ovti_ov7670
642609
DT_INST_FOREACH_STATUS_OKAY(OV7670_INIT)

0 commit comments

Comments
 (0)