Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 90 additions & 128 deletions drivers/video/ov7670.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,12 @@
#include <zephyr/drivers/video-controls.h>
#include <zephyr/logging/log.h>

#include "video_common.h"
#include "video_ctrls.h"
#include "video_device.h"

LOG_MODULE_REGISTER(video_ov7670, CONFIG_VIDEO_LOG_LEVEL);

/* Initialization register structure */
struct ov7670_reg {
uint8_t reg;
uint8_t cmd;
};

struct ov7670_config {
struct i2c_dt_spec bus;
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
Expand All @@ -43,63 +38,7 @@ struct ov7670_data {
struct video_format fmt;
};

struct ov7670_resolution_cfg {
uint8_t com7;
uint8_t com3;
uint8_t com14;
uint8_t scaling_xsc;
uint8_t scaling_ysc;
uint8_t dcwctr;
uint8_t pclk_div;
uint8_t pclk_delay;
};

/* Resolution settings for camera, based on those present in MCUX SDK */
const struct ov7670_resolution_cfg OV7670_RESOLUTION_QCIF = {
.com7 = 0x2c,
.com3 = 0x00,
.com14 = 0x11,
.scaling_xsc = 0x3a,
.scaling_ysc = 0x35,
.dcwctr = 0x11,
.pclk_div = 0xf1,
.pclk_delay = 0x52
};

const struct ov7670_resolution_cfg OV7670_RESOLUTION_QVGA = {
.com7 = 0x14,
.com3 = 0x04,
.com14 = 0x19,
.scaling_xsc = 0x3a,
.scaling_ysc = 0x35,
.dcwctr = 0x11,
.pclk_div = 0xf1,
.pclk_delay = 0x02
};

const struct ov7670_resolution_cfg OV7670_RESOLUTION_CIF = {
.com7 = 0x24,
.com3 = 0x08,
.com14 = 0x11,
.scaling_xsc = 0x3a,
.scaling_ysc = 0x35,
.dcwctr = 0x11,
.pclk_div = 0xf1,
.pclk_delay = 0x02
};

const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = {
.com7 = 0x04,
.com3 = 0x00,
.com14 = 0x00,
.scaling_xsc = 0x3a,
.scaling_ysc = 0x35,
.dcwctr = 0x11,
.pclk_div = 0xf0,
.pclk_delay = 0x02
};


#define OV7670_REG8(addr) ((addr) | VIDEO_REG_ADDR8_DATA8)
/* OV7670 registers */
#define OV7670_PID 0x0A
#define OV7670_COM7 0x12
Expand Down Expand Up @@ -209,13 +148,14 @@ static const struct video_format_cap fmts[] = {
OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */
OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */
OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */
{0}};
{0}
};

/*
* This initialization table is based on the MCUX SDK driver for the OV7670.
* Note that this table assumes the camera is fed a 6MHz XCLK signal
*/
static const struct ov7670_reg ov7670_init_regtbl[] = {
static const struct video_reg8 ov7670_init_regtbl[] = {
{OV7670_MVFP, 0x00}, /* MVFP: Mirror/VFlip,Normal image */

/* configure the output timing */
Expand Down Expand Up @@ -369,6 +309,51 @@ static const struct ov7670_reg ov7670_init_regtbl[] = {
{0xb8, 0x0a},
};

/* Resolution settings for camera, based on those present in MCUX SDK */
static const struct video_reg8 ov7670_regs_qcif[] = {
{OV7670_COM7, 0x2c},
{OV7670_COM3, 0x00},
{OV7670_COM14, 0x11},
{OV7670_SCALING_XSC, 0x3a},
{OV7670_SCALING_YSC, 0x35},
{OV7670_SCALING_DCWCTR, 0x11},
{OV7670_SCALING_PCLK_DIV, 0xf1},
{OV7670_SCALING_PCLK_DELAY, 0x52},
};

static const struct video_reg8 ov7670_regs_qvga[] = {
{OV7670_COM7, 0x14},
{OV7670_COM3, 0x04},
{OV7670_COM14, 0x19},
{OV7670_SCALING_XSC, 0x3a},
{OV7670_SCALING_YSC, 0x35},
{OV7670_SCALING_DCWCTR, 0x11},
{OV7670_SCALING_PCLK_DIV, 0xf1},
{OV7670_SCALING_PCLK_DELAY, 0x02},
};

static const struct video_reg8 ov7670_regs_cif[] = {
{OV7670_COM7, 0x24},
{OV7670_COM3, 0x08},
{OV7670_COM14, 0x11},
{OV7670_SCALING_XSC, 0x3a},
{OV7670_SCALING_YSC, 0x35},
{OV7670_SCALING_DCWCTR, 0x11},
{OV7670_SCALING_PCLK_DIV, 0xf1},
{OV7670_SCALING_PCLK_DELAY, 0x02},
};

static const struct video_reg8 ov7670_regs_vga[] = {
{OV7670_COM7, 0x04},
{OV7670_COM3, 0x00},
{OV7670_COM14, 0x00},
{OV7670_SCALING_XSC, 0x3a},
{OV7670_SCALING_YSC, 0x35},
{OV7670_SCALING_DCWCTR, 0x11},
{OV7670_SCALING_PCLK_DIV, 0xf0},
{OV7670_SCALING_PCLK_DELAY, 0x02},
};

static int ov7670_get_caps(const struct device *dev, struct video_caps *caps)
{
caps->format_caps = fmts;
Expand All @@ -379,8 +364,7 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
{
const struct ov7670_config *config = dev->config;
struct ov7670_data *data = dev->data;
const struct ov7670_resolution_cfg *resolution;
int ret;
int ret = -ENOTSUP;
uint8_t i = 0U;

if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) {
Expand All @@ -397,67 +381,46 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)

/* Set output resolution */
while (fmts[i].pixelformat) {
if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height &&
fmts[i].pixelformat == fmt->pixelformat) {
if (fmts[i].width_min == fmt->width &&
fmts[i].height_min == fmt->height &&
fmts[i].pixelformat == fmt->pixelformat){
/* Set output format */
switch (fmts[i].width_min) {
case 176: /* QCIF */
resolution = &OV7670_RESOLUTION_QCIF;
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qcif,
ARRAY_SIZE(ov7670_regs_qcif));
break;
case 352: /* QCIF */
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_cif,
ARRAY_SIZE(ov7670_regs_cif));
break;
case 320: /* QVGA */
resolution = &OV7670_RESOLUTION_QVGA;
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
ARRAY_SIZE(ov7670_regs_qvga));
break;
case 352: /* CIF */
resolution = &OV7670_RESOLUTION_CIF;
case 640: /* VGA */
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_vga,
ARRAY_SIZE(ov7670_regs_vga));
break;
default: /* VGA */
resolution = &OV7670_RESOLUTION_VGA;
default: /* QVGA */
ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga,
ARRAY_SIZE(ov7670_regs_vga));
break;
}
/* Program resolution bytes settings */
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7,
resolution->com7);
if (ret < 0) {
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM3,
resolution->com3);
if (ret < 0) {
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM14,
resolution->com14);
if (ret < 0) {
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_XSC,
resolution->scaling_xsc);
if (ret < 0) {
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_YSC,
resolution->scaling_ysc);
if (ret < 0) {
LOG_ERR("Resolution not set!");
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_DCWCTR,
resolution->dcwctr);
if (ret < 0) {
return ret;
}
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DIV,
resolution->pclk_div);
if (ret < 0) {
return ret;
}
return i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DELAY,
resolution->pclk_delay);
}
i++;
}

LOG_ERR("Unsupported format");
return -ENOTSUP;
if (ret < 0) {
LOG_ERR("Resolution not supported!");
return ret;
}

return 0;
}

static int ov7670_get_fmt(const struct device *dev, struct video_format *fmt)
Expand Down Expand Up @@ -487,14 +450,13 @@ static int ov7670_init_controls(const struct device *dev)
static int ov7670_init(const struct device *dev)
{
const struct ov7670_config *config = dev->config;
int ret, i;
int ret;
uint8_t pid;
struct video_format fmt = {
.pixelformat = VIDEO_PIX_FMT_RGB565,
.width = 320,
.height = 240,
};
const struct ov7670_reg *reg;

if (!i2c_is_ready_dt(&config->bus)) {
/* I2C device is not ready, return */
Expand Down Expand Up @@ -559,7 +521,7 @@ static int ov7670_init(const struct device *dev)
}

/* Reset camera registers */
ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7, 0x80);
ret = video_write_cci_reg(&config->bus, OV7670_REG8(OV7670_COM7), 0x80);
if (ret < 0) {
LOG_ERR("Could not reset camera: %d", ret);
return ret;
Expand All @@ -573,12 +535,10 @@ static int ov7670_init(const struct device *dev)
}

/* Write initialization values to OV7670 */
for (i = 0; i < ARRAY_SIZE(ov7670_init_regtbl); i++) {
reg = &ov7670_init_regtbl[i];
ret = i2c_reg_write_byte_dt(&config->bus, reg->reg, reg->cmd);
if (ret < 0) {
return ret;
}
ret = video_write_cci_multiregs8(&config->bus, ov7670_init_regtbl,
ARRAY_SIZE(ov7670_init_regtbl));
if (ret < 0) {
return ret;
}

/* Initialize controls */
Expand Down Expand Up @@ -628,15 +588,17 @@ static DEVICE_API(video, ov7670_api) = {
#define OV7670_PWDN_GPIO(inst)
#endif

#define OV7670_INIT(inst) \
const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \
OV7670_RESET_GPIO(inst) \
OV7670_PWDN_GPIO(inst)}; \
struct ov7670_data ov7670_data_##inst; \
\
#define OV7670_INIT(inst) \
const struct ov7670_config ov7670_config_##inst = { \
.bus = I2C_DT_SPEC_INST_GET(inst), \
OV7670_RESET_GPIO(inst) \
OV7670_PWDN_GPIO(inst)}; \
\
struct ov7670_data ov7670_data_##inst; \
\
DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \
POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov7670_api); \
\
\
VIDEO_DEVICE_DEFINE(ov7670_##inst, DEVICE_DT_INST_GET(inst), NULL);

DT_INST_FOREACH_STATUS_OKAY(OV7670_INIT)
Loading