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, ®, 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, ®, 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