• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_ov7725.h"
9 
10 static const uint8_t ov7725_default_regs[][2] = {
11     {COM4,          0x41}, /* bypass PLL */
12 
13     /*
14      * VGA Window Size
15      */
16     {HSTART,        0x22},
17     {HSIZE,         0xa4},
18     {VSTART,        0x07},
19     {VSIZE,         0xf0},
20     {HREF,          0x00},
21 
22     /*
23      * Scale down to VGA Resolution
24      */
25     {HOUTSIZE,      0xA0},
26     {VOUTSIZE,      0xF0},
27 
28     {COM12,         0x03},
29     {EXHCH,         0x00},
30     {TGT_B,         0x7F},
31     {FIXGAIN,       0x09},
32     {AWB_CTRL0,     0xE0},
33     {DSP_CTRL1,     0xFF},
34     {DSP_CTRL2,     0x20},
35     {DSP_CTRL3,     0x00},
36     {DSP_CTRL4,     0x00},
37 
38     {COM8,          0xF8},
39     {COM6,          0xC5},
40     {COM9,          0x11},
41     {COM10,         COM10_VSYNC_NEG | COM10_PCLK_MASK}, /* Invert VSYNC and MASK PCLK */
42     {BDBASE,        0x7F},
43     {DBSTEP,        0x03},
44     {AEW,           0x70},
45     {AEB,           0x43},
46     {VPT,           0xA1},
47     {EXHCL,         0x00},
48     {AWB_CTRL3,     0xAA},
49     {COM8,          0xFF},
50 
51     /*
52      * Gamma
53      */
54     {GAM1,          0x0C},
55     {GAM2,          0x16},
56     {GAM3,          0x2A},
57     {GAM4,          0x4E},
58     {GAM5,          0x61},
59     {GAM6,          0x6F},
60     {GAM7,          0x7B},
61     {GAM8,          0x86},
62     {GAM9,          0x8E},
63     {GAM10,         0x97},
64     {GAM11,         0xA4},
65     {GAM12,         0xAF},
66     {GAM13,         0xC5},
67     {GAM14,         0xD7},
68     {GAM15,         0xE8},
69 
70     {SLOP,          0x20},
71     {EDGE1,         0x05},
72     {EDGE2,         0x03},
73     {EDGE3,         0x00},
74     {DNSOFF,        0x01},
75 
76     {MTX1,          0xB0},
77     {MTX2,          0x9D},
78     {MTX3,          0x13},
79     {MTX4,          0x16},
80     {MTX5,          0x7B},
81     {MTX6,          0x91},
82     {MTX_CTRL,      0x1E},
83 
84     {BRIGHTNESS,    0x08},
85     {CONTRAST,      0x20},
86     {UVADJ0,        0x81},
87     {SDE,           (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)},
88 
89     /*
90      * For 30 fps/60Hz
91      */
92     {DM_LNL,        0x00},
93     {DM_LNH,        0x00},
94     {BDBASE,        0x7F},
95     {DBSTEP,        0x03},
96 
97     /*
98      * Lens Correction, should be tuned with real camera module
99      */
100     {LC_RADI,       0x10},
101     {LC_COEF,       0x10},
102     {LC_COEFB,      0x14},
103     {LC_COEFR,      0x17},
104     {LC_CTR,        0x05},
105     {COM5,          0x65},
106 };
107 
108 
109 static const uint8_t ov7725_default_yuv_regs[][2] = {
110     {COM12,       0x03},
111     {HSTART,      0x22},
112     {HSIZE,       0xa4},
113     {VSTART,      0x07},
114     {VSIZE,       0xf0},
115     {HREF,        0x00},
116     {HOUTSIZE,    0xa0},
117     {VOUTSIZE,    0xf0},
118     {EXHCH,       0x00},
119     {CLKRC,       0x01},
120     {TGT_B,       0x7f},
121     {FIXGAIN,     0x09},
122     {AWB_CTRL0,   0xe0},
123     {DSP_CTRL1,   0xff},
124     {DSP_CTRL2,   0x20},
125     {DSP_CTRL3,   0x00},
126     {DSP_CTRL4,   0x48},
127     {COM8,        0xf0},
128     {COM4,        0x41}, /*           0x51/          0x61/          0x71 for different AEC/AGC window */
129     {COM6,        0xc5},
130     {COM9,        0x11},
131     {BDBASE,      0x7f},
132     {DBSTEP,      0x03},
133     {AEW,         0x40},
134     {AEB,         0x30},
135     {VPT,         0xa1},
136     {EXHCL,       0x00},
137     {AWB_CTRL3,   0xaa},
138     {COM8,        0xff},
139     {EDGE1,       0x05},
140     {DNSOFF,      0x01},
141     {EDGE2,       0x03},
142     {EDGE3,       0x00},
143     {MTX1,        0xb0},
144     {MTX2,        0x9d},
145     {MTX3,        0x13},
146     {MTX4,        0x16},
147     {MTX5,        0x7b},
148     {MTX6,        0x91},
149     {MTX_CTRL,    0x1e},
150     {BRIGHTNESS,  0x08},
151     {CONTRAST,    0x20},
152     {UVADJ0,      0x81},
153     {SDE,         0x06},
154     /* Gamma */
155     {GAM1,        0x0c},
156     {GAM2,        0x16},
157     {GAM3,        0x2a},
158     {GAM4,        0x4e},
159     {GAM5,        0x61},
160     {GAM6,        0x6f},
161     {GAM7,        0x7b},
162     {GAM8,        0x86},
163     {GAM9,        0x8e},
164     {GAM10,       0x97},
165     {GAM11,       0xa4},
166     {GAM12,       0xaf},
167     {GAM13,       0xc5},
168     {GAM14,       0xd7},
169     {GAM15,       0xe8},
170     {SLOP,        0x20},
171     /* for 30 fps,0Hz */
172     {DM_LNL,      0x00},
173     {BDBASE,      0x7f},
174     {DBSTEP,      0x03},
175 
176     /* Lens Correcon, should be tuned with real camera module */
177     {LC_RADI,     0x10},
178     {LC_COEF,     0x10},
179     {LC_COEFB,    0x14},
180     {LC_COEFR,    0x17},
181     {LC_CTR,      0x05},
182     {COM5,        0x65},
183 };
184 
ov7725_read_register(camera_context_t * context,uint8_t reg,uint8_t * buf)185 hpm_stat_t ov7725_read_register(camera_context_t *context, uint8_t reg, uint8_t *buf)
186 {
187     hpm_stat_t stat = i2c_master_write(context->ptr, context->i2c_device_addr, &reg, 1);
188     if (stat != status_success) {
189         return stat;
190     }
191     return i2c_master_read(context->ptr, context->i2c_device_addr, buf, 1);
192 
193 }
194 
ov7725_write_register(camera_context_t * context,uint8_t reg,uint8_t val)195 hpm_stat_t ov7725_write_register(camera_context_t *context, uint8_t reg, uint8_t val)
196 {
197     return i2c_master_address_write(context->ptr, context->i2c_device_addr, &reg, 1, &val, 1);
198 }
199 
ov7725_load_settings(camera_context_t * context,uint8_t * reg_values,uint32_t count)200 hpm_stat_t ov7725_load_settings(camera_context_t *context, uint8_t *reg_values, uint32_t count)
201 {
202     hpm_stat_t stat = status_success;
203     for (uint32_t i = 0, j = 0; i < count; i++, j += 2) {
204         stat = ov7725_write_register(context, reg_values[j], reg_values[j+1]);
205         if (stat != status_success) {
206             break;
207         }
208     }
209     return stat;
210 }
211 
ov7725_software_reset(camera_context_t * context)212 hpm_stat_t ov7725_software_reset(camera_context_t *context)
213 {
214     hpm_stat_t stat = status_success;
215 
216     stat = ov7725_write_register(context, COM7, COM7_RESET);
217     if (stat != status_success) {
218         return stat;
219     }
220 
221     return stat;
222 }
223 
ov7725_check_chip_id(camera_context_t * context)224 hpm_stat_t ov7725_check_chip_id(camera_context_t *context)
225 {
226     hpm_stat_t stat = status_success;
227     uint8_t val_h = 0;
228     uint8_t val_l = 0;
229 
230     HPM_CHECK_RET(ov7725_read_register(context, OV7725_CHIP_ID_HIGH_BYTE_ADDR, &val_h));
231     HPM_CHECK_RET(ov7725_read_register(context, OV7725_CHIP_ID_LOW_BYTE_ADDR, &val_l));
232 
233     if (val_h != OV7725_CHIP_ID_HIGH_BYTE_VALUE) {
234         return status_fail;
235     }
236 
237     if (val_l != OV7725_CHIP_ID_LOW_BYTE_VALUE) {
238         return status_fail;
239     }
240 
241     return stat;
242 }
243 
ov7725_set_framesize(camera_context_t * context,uint16_t width,uint16_t height)244 static hpm_stat_t ov7725_set_framesize(camera_context_t *context, uint16_t width, uint16_t height)
245 {
246     hpm_stat_t stat = status_success;
247     uint32_t hstart = 0x22U << 2;
248     uint32_t vstart = 0x7U << 1;
249     uint32_t hsize = width + 16;
250 
251     stat |= ov7725_write_register(context, HSTART, hstart >> 2);
252     stat |= ov7725_write_register(context, HSIZE, hsize >> 2);
253     stat |= ov7725_write_register(context, VSTART, vstart >> 1);
254     stat |= ov7725_write_register(context, VSIZE, height >> 1);
255 
256     stat |= ov7725_write_register(context, HOUTSIZE, width >> 2);
257     stat |= ov7725_write_register(context, VOUTSIZE, height >> 1);
258 
259     stat |= ov7725_write_register(context, HREF,
260             ((vstart & 1) << 6) | ((hstart & 3) << 4) | ((height & 1) << 2) | ((hsize & 3) << 0));
261 
262     stat = ov7725_write_register(context, EXHCH, ((height & 0x1) << 2) | (width & 0x3));
263     if (stat != status_success) {
264         return stat;
265     }
266     return stat;
267 }
268 
ov7725_set_pixel_format(camera_context_t * context,display_pixel_format_t pixel_format)269 hpm_stat_t ov7725_set_pixel_format(camera_context_t *context, display_pixel_format_t pixel_format)
270 {
271     hpm_stat_t stat = status_success;
272     uint8_t val = 0;
273 
274     stat |= ov7725_read_register(context, COM7, &val);
275     val &= ~0x1F;
276     switch (pixel_format) {
277     case display_pixel_format_rgb565:
278         val |= COM7_FMT_RGB565;
279         break;
280     case display_pixel_format_rgb444:
281         val |= COM7_FMT_RGB444;
282         break;
283     case display_pixel_format_yuv422:
284     case display_pixel_format_y8:
285         val |= COM7_FMT_YUV;
286         break;
287     case display_pixel_format_raw8:
288         stat |= ov7725_write_register(context, DSP_CTRL4, DSP_CTRL4_RAW8);
289         val |= COM7_FMT_R_BAYER;
290         break;
291     default:
292         stat = status_invalid_argument;
293         break;
294     }
295     if (stat != status_success) {
296         return stat;
297     }
298 
299     stat |= ov7725_write_register(context, COM7, val);
300     if (stat != status_success) {
301         return stat;
302     }
303     return stat;
304 }
305 
ov7725_init(camera_context_t * context,camera_config_t * ov_config)306 hpm_stat_t ov7725_init(camera_context_t *context, camera_config_t *ov_config)
307 {
308     hpm_stat_t stat = status_success;
309 
310     switch (ov_config->pixel_format) {
311     case display_pixel_format_yuv422:
312     case display_pixel_format_y8:
313         ov7725_load_settings(context, (uint8_t *) ov7725_default_yuv_regs, ARRAY_SIZE(ov7725_default_yuv_regs));
314         break;
315     default:
316         ov7725_load_settings(context, (uint8_t *) ov7725_default_regs, ARRAY_SIZE(ov7725_default_regs));
317         stat |= ov7725_write_register(context, COM7, COM7_RES_VGA | COM7_FMT_RGB565);
318         stat |= ov7725_write_register(context, COM10, 0);
319         stat |= ov7725_write_register(context, COM3, 0);
320         break;
321     }
322 
323     stat |= ov7725_write_register(context, CLKRC, 0x2);
324     stat |= ov7725_write_register(context, COM4, 0x41);
325 
326     stat |= ov7725_set_framesize(context, ov_config->width, ov_config->height);
327     stat |= ov7725_set_pixel_format(context, ov_config->pixel_format);
328     if (stat != status_success) {
329         return stat;
330     }
331 
332     return stat;
333 }
334 
ov7725_power_up(camera_context_t * context)335 void ov7725_power_up(camera_context_t *context)
336 {
337     assert(context->delay_ms != NULL);
338 
339     if (context->write_rst) {
340         context->write_rst(OV7725_RST_ACTIVE);
341     }
342     if (context->write_pwdn) {
343         context->write_pwdn(OV7725_PWDN_ACTIVE);
344     }
345     context->delay_ms(5);
346     if (context->write_pwdn) {
347         context->write_pwdn(OV7725_PWDN_INACTIVE);
348     }
349     context->delay_ms(2);
350     if (context->write_rst) {
351         context->write_rst(OV7725_RST_INACTIVE);
352     }
353     context->delay_ms(20);
354 }
355