Skip to content

Commit 87e541b

Browse files
committed
drivers: video: ov2640 driver: Enhancing ov2640 driver
Enabling proper zoom/scaling for windowed resolutions; e.g. smaller than uxga That makes camera's ISP to downscale frame to a desired resolution Signed-off-by: Roman Pustobaiev <[email protected]>
1 parent aa6f87d commit 87e541b

File tree

1 file changed

+151
-47
lines changed

1 file changed

+151
-47
lines changed

drivers/video/ov2640.c

Lines changed: 151 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -151,18 +151,103 @@ LOG_MODULE_REGISTER(video_ov2640, CONFIG_VIDEO_LOG_LEVEL);
151151
#define REG32 0x32
152152
#define REG32_UXGA 0x36
153153

154-
/* Configuration arrays */
155-
#define SVGA_HSIZE (800)
156-
#define SVGA_VSIZE (600)
157-
158-
#define UXGA_HSIZE (1600)
159-
#define UXGA_VSIZE (1200)
154+
#define CIF_WIDTH 352
155+
#define CIF_HEIGHT 288
156+
#define HD_720_WIDTH 1280
157+
#define HD_720_HEIGHT 720
158+
#define HD_1080_WIDTH 1920
159+
#define HD_1080_HEIGHT 1080
160+
#define QCIF_WIDTH 176
161+
#define QCIF_HEIGHT 144
162+
#define QQCIF_WIDTH 88
163+
#define QQCIF_HEIGHT 72
164+
#define QQVGA_WIDTH 160
165+
#define QQVGA_HEIGHT 120
166+
#define QVGA_WIDTH 320
167+
#define QVGA_HEIGHT 240
168+
#define SVGA_WIDTH 800
169+
#define SVGA_HEIGHT 600
170+
#define SXGA_WIDTH 1280
171+
#define SXGA_HEIGHT 1024
172+
#define VGA_WIDTH 640
173+
#define VGA_HEIGHT 480
174+
#define UXGA_WIDTH 1600
175+
#define UXGA_HEIGHT 1200
176+
#define XGA_WIDTH 1024
177+
#define XGA_HEIGHT 768
160178

161179
struct ov2640_reg {
162180
uint8_t addr;
163181
uint8_t value;
164182
};
165183

184+
struct ov2640_win_size {
185+
uint32_t width;
186+
uint32_t height;
187+
const struct ov2640_reg *regs;
188+
uint32_t regs_size;
189+
};
190+
191+
#define OV2640_ZOOM_CONFIG(x, y, v_div, h_div, pclk_div) \
192+
{CTRLI, \
193+
CTRLI_LP_DP | FIELD_PREP(GENMASK(5, 3), v_div) | FIELD_PREP(GENMASK(2, 0), h_div)}, \
194+
{ZMOW, FIELD_PREP(GENMASK(7, 0), (x) >> 2)}, \
195+
{ZMOH, FIELD_PREP(GENMASK(7, 0), (y) >> 2)}, \
196+
{ZMHH, FIELD_PREP(GENMASK(1, 0), (x) >> (8 + 2)) | \
197+
FIELD_PREP(GENMASK(2, 2), (y) >> (8 + 2))}, \
198+
{R_DVP_SP, pclk_div}, {RESET, 0x00}
199+
200+
static const struct ov2640_reg ov2640_qqvga_regs[] = {
201+
OV2640_ZOOM_CONFIG(QQVGA_WIDTH, QQVGA_HEIGHT, 3, 3, 8),
202+
};
203+
static const struct ov2640_reg ov2640_qcif_regs[] = {
204+
OV2640_ZOOM_CONFIG(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4),
205+
};
206+
static const struct ov2640_reg ov2640_240x240_regs[] = {
207+
OV2640_ZOOM_CONFIG(240, 240, 2, 2, 4),
208+
};
209+
static const struct ov2640_reg ov2640_qvga_regs[] = {
210+
OV2640_ZOOM_CONFIG(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4),
211+
};
212+
static const struct ov2640_reg ov2640_cif_regs[] = {
213+
OV2640_ZOOM_CONFIG(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8),
214+
};
215+
static const struct ov2640_reg ov2640_vga_regs[] = {
216+
OV2640_ZOOM_CONFIG(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2),
217+
};
218+
static const struct ov2640_reg ov2640_svga_regs[] = {
219+
OV2640_ZOOM_CONFIG(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2),
220+
};
221+
static const struct ov2640_reg ov2640_xga_regs[] = {
222+
OV2640_ZOOM_CONFIG(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2),
223+
{CTRLI, 0x00},
224+
};
225+
static const struct ov2640_reg ov2640_sxga_regs[] = {
226+
OV2640_ZOOM_CONFIG(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2),
227+
{CTRLI, 0x00},
228+
{R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE},
229+
};
230+
static const struct ov2640_reg ov2640_uxga_regs[] = {
231+
OV2640_ZOOM_CONFIG(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0),
232+
{CTRLI, 0x00},
233+
{R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE},
234+
};
235+
236+
#define OV2640_SIZE(w, h, r) {.width = w, .height = h, .regs = r, .regs_size = ARRAY_SIZE(r)}
237+
238+
static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
239+
OV2640_SIZE(QQVGA_WIDTH, QQVGA_HEIGHT, ov2640_qqvga_regs),
240+
OV2640_SIZE(QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs),
241+
OV2640_SIZE(240, 240, ov2640_240x240_regs),
242+
OV2640_SIZE(QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs),
243+
OV2640_SIZE(CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs),
244+
OV2640_SIZE(VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs),
245+
OV2640_SIZE(SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs),
246+
OV2640_SIZE(XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs),
247+
OV2640_SIZE(SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs),
248+
OV2640_SIZE(UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs),
249+
};
250+
166251
static const struct ov2640_reg default_regs[] = {
167252
{ BANK_SEL, BANK_SEL_DSP },
168253
{ 0x2c, 0xff },
@@ -376,20 +461,20 @@ static const struct ov2640_reg uxga_regs[] = {
376461
{ R_BYPASS, R_BYPASS_DSP_BYPAS },
377462

378463
{ RESET, RESET_DVP },
379-
{ HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */
380-
{ VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertical Size VSIZE[10:3] */
464+
{HSIZE8, (UXGA_WIDTH >> 3)}, /* Image Horizontal Size HSIZE[10:3] */
465+
{VSIZE8, (UXGA_HEIGHT >> 3)}, /* Image Vertical Size VSIZE[10:3] */
381466

382467
/* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */
383-
{ SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)},
468+
{SIZEL, ((UXGA_WIDTH >> 6) & 0x40) | ((UXGA_WIDTH & 0x7) << 3) | (UXGA_HEIGHT & 0x7)},
384469

385470
{ XOFFL, 0x00 }, /* OFFSET_X[7:0] */
386471
{ YOFFL, 0x00 }, /* OFFSET_Y[7:0] */
387-
{ HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */
388-
{ VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */
472+
{HSIZE, ((UXGA_WIDTH >> 2) & 0xFF)}, /* H_SIZE[7:0] real/4 */
473+
{VSIZE, ((UXGA_HEIGHT >> 2) & 0xFF)}, /* V_SIZE[7:0] real/4 */
389474

390475
/* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */
391-
{ VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) },
392-
{ TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */
476+
{VHYX, ((UXGA_HEIGHT >> 3) & 0x80) | ((UXGA_WIDTH >> 7) & 0x08)},
477+
{TEST, (UXGA_WIDTH >> 4) & 0x80}, /* H_SIZE[9] */
393478

394479
{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
395480
CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
@@ -400,7 +485,6 @@ static const struct ov2640_reg uxga_regs[] = {
400485
{ R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04},
401486

402487
{ R_BYPASS, R_BYPASS_DSP_EN },
403-
{ RESET, 0x00 },
404488
{0, 0},
405489
};
406490

@@ -472,29 +556,31 @@ struct ov2640_data {
472556
}
473557

474558
static const struct video_format_cap fmts[] = {
475-
OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565), /* QQVGA */
476-
OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */
477-
OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_RGB565), /* HQVGA */
478-
OV2640_VIDEO_FORMAT_CAP(240, 240, VIDEO_PIX_FMT_RGB565), /* 240x240 */
479-
OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
480-
OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */
481-
OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */
482-
OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_RGB565), /* SVGA */
483-
OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_RGB565), /* XVGA */
484-
OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_RGB565), /* SXGA */
485-
OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_RGB565), /* UXGA */
486-
OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_JPEG), /* QQVGA */
487-
OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_JPEG), /* QCIF */
488-
OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_JPEG), /* HQVGA */
489-
OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_JPEG), /* QVGA */
490-
OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_JPEG), /* CIF */
491-
OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_JPEG), /* VGA */
492-
OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_JPEG), /* SVGA */
493-
OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_JPEG), /* XVGA */
494-
OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_JPEG), /* SXGA */
495-
OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_JPEG), /* UXGA */
496-
{ 0 }
497-
};
559+
OV2640_VIDEO_FORMAT_CAP(QQVGA_WIDTH, QQVGA_HEIGHT,
560+
VIDEO_PIX_FMT_RGB565), /* 160 x 120 QQVGA */
561+
OV2640_VIDEO_FORMAT_CAP(QCIF_WIDTH, QCIF_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 176 x 144 QCIF */
562+
OV2640_VIDEO_FORMAT_CAP(240, 240, VIDEO_PIX_FMT_RGB565),
563+
OV2640_VIDEO_FORMAT_CAP(QVGA_WIDTH, QVGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 320 x 240 QVGA */
564+
OV2640_VIDEO_FORMAT_CAP(CIF_WIDTH, CIF_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 352 x 288 CIF */
565+
OV2640_VIDEO_FORMAT_CAP(VGA_WIDTH, VGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 640 x 480 VGA */
566+
OV2640_VIDEO_FORMAT_CAP(SVGA_WIDTH, SVGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 800 x 600 SVGA */
567+
OV2640_VIDEO_FORMAT_CAP(XGA_WIDTH, XGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* 1024 x 768 XVGA */
568+
OV2640_VIDEO_FORMAT_CAP(SXGA_WIDTH, SXGA_HEIGHT,
569+
VIDEO_PIX_FMT_RGB565), /* 1280 x 1024 SXGA */
570+
OV2640_VIDEO_FORMAT_CAP(UXGA_WIDTH, UXGA_HEIGHT,
571+
VIDEO_PIX_FMT_RGB565), /* 1600 x 1200 UXGA */
572+
OV2640_VIDEO_FORMAT_CAP(QQVGA_WIDTH, QQVGA_HEIGHT,
573+
VIDEO_PIX_FMT_JPEG), /* 160 x 120 QQVGA */
574+
OV2640_VIDEO_FORMAT_CAP(QCIF_WIDTH, QCIF_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 176 x 144 QCIF */
575+
OV2640_VIDEO_FORMAT_CAP(CIF_WIDTH, CIF_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 352 x 288 CIF */
576+
OV2640_VIDEO_FORMAT_CAP(240, 240, VIDEO_PIX_FMT_JPEG),
577+
OV2640_VIDEO_FORMAT_CAP(QVGA_WIDTH, QVGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 320 x 240 QVGA */
578+
OV2640_VIDEO_FORMAT_CAP(VGA_WIDTH, VGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 640 x 480 VGA */
579+
OV2640_VIDEO_FORMAT_CAP(SVGA_WIDTH, SVGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 800 x 600 SVGA */
580+
OV2640_VIDEO_FORMAT_CAP(XGA_WIDTH, XGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 1024 x 768 XVGA */
581+
OV2640_VIDEO_FORMAT_CAP(SXGA_WIDTH, SXGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 1280 x 1024 SXGA */
582+
OV2640_VIDEO_FORMAT_CAP(UXGA_WIDTH, UXGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* 1600 x 1200 UXGA */
583+
{0}};
498584

499585
static int ov2640_write_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr,
500586
uint8_t value)
@@ -775,6 +861,17 @@ static int ov2640_set_vertical_flip(const struct device *dev, int enable)
775861
return ret;
776862
}
777863

864+
static const struct ov2640_win_size *ov2640_select_win(uint32_t width, uint32_t height)
865+
{
866+
for (int i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
867+
if (ov2640_supported_win_sizes[i].width >= width &&
868+
ov2640_supported_win_sizes[i].height >= height) {
869+
return &ov2640_supported_win_sizes[i];
870+
}
871+
}
872+
return NULL;
873+
}
874+
778875
static int ov2640_set_resolution(const struct device *dev,
779876
uint16_t img_width, uint16_t img_height)
780877
{
@@ -784,23 +881,30 @@ static int ov2640_set_resolution(const struct device *dev,
784881
uint16_t w = img_width;
785882
uint16_t h = img_height;
786883

884+
const struct ov2640_win_size *win = ov2640_select_win(w, h);
885+
886+
if (win == NULL) {
887+
LOG_ERR("Couldn't find window size for desired resolution setting");
888+
return -EINVAL;
889+
}
890+
LOG_INF("Selected resolution %ux%u", win->width, win->height);
891+
892+
/* Write DSP input registers */
893+
ret = ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs));
894+
if (ret < 0) {
895+
return ret;
896+
}
897+
787898
/* Disable DSP */
788899
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
789900
ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_BYPAS);
790901

791-
/* Write output width */
792-
ret |= ov2640_write_reg(&cfg->i2c, ZMOW, (w >> 2) & 0xFF); /* OUTW[7:0] (real/4) */
793-
ret |= ov2640_write_reg(&cfg->i2c, ZMOH, (h >> 2) & 0xFF); /* OUTH[7:0] (real/4) */
794-
ret |= ov2640_write_reg(&cfg->i2c, ZMHH, ((h >> 8) & 0x04) |
795-
((w>>10) & 0x03)); /* OUTH[8]/OUTW[9:8] */
902+
ret |= ov2640_write_all(dev, win->regs, win->regs_size);
796903

797904
/* Set CLKRC */
798905
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
799906
ret |= ov2640_write_reg(&cfg->i2c, CLKRC, cfg->clock_rate_control);
800907

801-
/* Write DSP input registers */
802-
ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs));
803-
804908
/* Enable DSP */
805909
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
806910
ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_EN);
@@ -1004,8 +1108,8 @@ static int ov2640_init(const struct device *dev)
10041108
/* set default/init format SVGA RGB565 */
10051109
struct video_format fmt = {
10061110
.pixelformat = VIDEO_PIX_FMT_RGB565,
1007-
.width = SVGA_HSIZE,
1008-
.height = SVGA_VSIZE,
1111+
.width = SVGA_WIDTH,
1112+
.height = SVGA_HEIGHT,
10091113
};
10101114

10111115
#if DT_INST_NODE_HAS_PROP(0, reset_gpios)

0 commit comments

Comments
 (0)