• 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     {COM3,          COM3_SWAP_YUV},
12     {COM7,          COM7_RES_VGA | COM7_FMT_RGB565},
13 
14     {COM4,          0x01}, /* bypass PLL */
15     {CLKRC,         0xC0}, /* Res/Bypass pre-scalar */
16 
17     /*
18      * VGA Window Size
19      */
20     {HSTART,        0x23},
21     {HSIZE,         0xA0},
22     {VSTART,        0x07},
23     {VSIZE,         0xF0},
24     {HREF,          0x00},
25 
26     /*
27      * Scale down to VGA Resolution
28      */
29     {HOUTSIZE,      0xA0},
30     {VOUTSIZE,      0xF0},
31 
32     {COM12,         0x03},
33     {EXHCH,         0x00},
34     {TGT_B,         0x7F},
35     {FIXGAIN,       0x09},
36     {AWB_CTRL0,     0xE0},
37     {DSP_CTRL1,     0xFF},
38 
39     {DSP_CTRL2,     DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN},
40 
41     {DSP_CTRL3,     0x00},
42     {DSP_CTRL4,     0x00},
43     {DSPAUTO,       0xFF},
44 
45     {COM8,          0xF0},
46     {COM6,          0xC5},
47     {COM9,          0x11},
48     {COM10,         COM10_VSYNC_NEG | COM10_PCLK_MASK}, /* Invert VSYNC and MASK PCLK */
49     {BDBASE,        0x7F},
50     {DBSTEP,        0x03},
51     {AEW,           0x70},
52     {AEB,           0x43},
53     {VPT,           0xA1},
54     {EXHCL,         0x00},
55     {AWB_CTRL3,     0xAA},
56     {COM8,          0xFF},
57 
58     /*
59      * Gamma
60      */
61     {GAM1,          0x0C},
62     {GAM2,          0x16},
63     {GAM3,          0x2A},
64     {GAM4,          0x4E},
65     {GAM5,          0x61},
66     {GAM6,          0x6F},
67     {GAM7,          0x7B},
68     {GAM8,          0x86},
69     {GAM9,          0x8E},
70     {GAM10,         0x97},
71     {GAM11,         0xA4},
72     {GAM12,         0xAF},
73     {GAM13,         0xC5},
74     {GAM14,         0xD7},
75     {GAM15,         0xE8},
76 
77     {SLOP,          0x20},
78     {EDGE1,         0x05},
79     {EDGE2,         0x03},
80     {EDGE3,         0x00},
81     {DNSOFF,        0x01},
82 
83     {MTX1,          0xB0},
84     {MTX2,          0x9D},
85     {MTX3,          0x13},
86     {MTX4,          0x16},
87     {MTX5,          0x7B},
88     {MTX6,          0x91},
89     {MTX_CTRL,      0x1E},
90 
91     {BRIGHTNESS,    0x08},
92     {CONTRAST,      0x30},
93     {UVADJ0,        0x81},
94     {SDE,           (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)},
95 
96     /*
97      * For 30 fps/60Hz
98      */
99     {DM_LNL,        0x00},
100     {DM_LNH,        0x00},
101     {BDBASE,        0x7F},
102     {DBSTEP,        0x03},
103 
104     /*
105      * Lens Correction, should be tuned with real camera module
106      */
107     {LC_RADI,       0x10},
108     {LC_COEF,       0x10},
109     {LC_COEFB,      0x14},
110     {LC_COEFR,      0x17},
111     {LC_CTR,        0x05},
112     {COM5,          0xF5},
113 };
114 
ov7725_read_register(camera_context_t * context,uint8_t reg,uint8_t * buf)115 hpm_stat_t ov7725_read_register(camera_context_t *context, uint8_t reg, uint8_t *buf)
116 {
117     return i2c_master_address_read(context->ptr, OV7725_I2C_ADDR, &reg, 1, buf, 1);
118 }
119 
ov7725_write_register(camera_context_t * context,uint8_t reg,uint8_t val)120 hpm_stat_t ov7725_write_register(camera_context_t *context, uint8_t reg, uint8_t val)
121 {
122     return i2c_master_address_write(context->ptr, OV7725_I2C_ADDR, &reg, 1, &val, 1);
123 }
124 
ov7725_restore_default_values(camera_context_t * context)125 void ov7725_restore_default_values(camera_context_t *context)
126 {
127     uint32_t i;
128     for (i = 0; i < (ARRAY_SIZE(ov7725_default_regs)); i++) {
129         ov7725_write_register(context, ov7725_default_regs[i][0], ov7725_default_regs[i][1]);
130     }
131 }
132 
ov7725_software_reset(camera_context_t * context)133 hpm_stat_t ov7725_software_reset(camera_context_t *context)
134 {
135     hpm_stat_t stat = status_success;
136 
137     stat = ov7725_write_register(context, COM7, COM7_RESET);
138     if (stat != status_success) {
139         return stat;
140     }
141 
142     return stat;
143 }
144 
ov7725_check_chip_id(camera_context_t * context)145 hpm_stat_t ov7725_check_chip_id(camera_context_t *context)
146 {
147     hpm_stat_t stat = status_success;
148     uint8_t val_h = 0;
149     uint8_t val_l = 0;
150 
151     HPM_CHECK_RET(ov7725_read_register(context, OV7725_CHIP_ID_HIGH_BYTE_ADDR, &val_h));
152     HPM_CHECK_RET(ov7725_read_register(context, OV7725_CHIP_ID_LOW_BYTE_ADDR, &val_l));
153 
154     if (val_h != OV7725_CHIP_ID_HIGH_BYTE_VALUE) {
155         return status_fail;
156     }
157 
158     if (val_l != OV7725_CHIP_ID_LOW_BYTE_VALUE) {
159         return status_fail;
160     }
161 
162     return stat;
163 }
164 
ov7725_set_framesize(camera_context_t * context,uint16_t width,uint16_t height)165 static hpm_stat_t ov7725_set_framesize(camera_context_t *context, uint16_t width, uint16_t height)
166 {
167     hpm_stat_t stat = status_success;
168     uint32_t hstart = 0x22U << 2;
169     uint32_t vstart = 0x7U << 1;
170     uint32_t hsize = width + 16;
171 
172     stat |= ov7725_write_register(context, HSTART, hstart >> 2);
173     stat |= ov7725_write_register(context, HSIZE, hsize >> 2);
174     stat |= ov7725_write_register(context, VSTART, vstart >> 1);
175     stat |= ov7725_write_register(context, VSIZE, height >> 1);
176 
177     stat |= ov7725_write_register(context, HOUTSIZE, width >> 2);
178     stat |= ov7725_write_register(context, VOUTSIZE, height >> 1);
179 
180     stat |= ov7725_write_register(context, HREF,
181             ((vstart & 1) << 6) | ((hstart & 3) << 4) | ((height & 1) << 2) | ((hsize & 3) << 0));
182 
183     stat = ov7725_write_register(context, EXHCH, ((height & 0x1) << 2) | (width & 0x3));
184     if (stat != status_success) {
185         return stat;
186     }
187     return stat;
188 }
189 
ov7725_set_pixel_format(camera_context_t * context,display_pixel_format_t pixel_format)190 hpm_stat_t ov7725_set_pixel_format(camera_context_t *context, display_pixel_format_t pixel_format)
191 {
192     hpm_stat_t stat = status_success;
193     uint8_t val = 0;
194 
195     stat |= ov7725_read_register(context, COM7, &val);
196     val &= ~0x1F;
197     switch (pixel_format) {
198     case display_pixel_format_rgb565:
199         val |= COM7_FMT_RGB565;
200         break;
201     case display_pixel_format_rgb444:
202         val |= COM7_FMT_RGB444;
203         break;
204     default:
205         stat = status_invalid_argument;
206         break;
207     }
208     if (stat != status_success) {
209         return stat;
210     }
211 
212     stat |= ov7725_write_register(context, COM7, val);
213     if (stat != status_success) {
214         return stat;
215     }
216     return stat;
217 }
218 
ov7725_init(camera_context_t * context,camera_config_t * ov_config)219 hpm_stat_t ov7725_init(camera_context_t *context, camera_config_t *ov_config)
220 {
221     hpm_stat_t stat = status_success;
222 
223     ov7725_restore_default_values(context);
224 
225     stat |= ov7725_write_register(context, CLKRC, 0x2);
226     stat |= ov7725_write_register(context, COM4, 0x41);
227     stat |= ov7725_write_register(context, EXHCL, 0);
228     stat |= ov7725_write_register(context, DM_LNL, 0);
229     stat |= ov7725_write_register(context, DM_LNH, 0);
230     stat |= ov7725_write_register(context, ADVFL, 0);
231     stat |= ov7725_write_register(context, ADVFH, 0);
232     stat |= ov7725_write_register(context, COM5, 0x65);
233     stat |= ov7725_write_register(context, COM10, 0);
234     stat |= ov7725_write_register(context, COM3, 0);
235     stat |= ov7725_write_register(context, COM2, 0x3);
236     stat |= ov7725_set_framesize(context, ov_config->width, ov_config->height);
237     stat |= ov7725_set_pixel_format(context, ov_config->pixel_format);
238     if (stat != status_success) {
239         return stat;
240     }
241 
242     return stat;
243 }
244 
ov7725_power_up(camera_context_t * context)245 void ov7725_power_up(camera_context_t *context)
246 {
247     assert((context->delay_ms != NULL) && (context->write_rst != NULL) && (context->write_pwdn != NULL));
248 
249     context->write_rst(OV7725_RST_ACTIVE);
250     context->write_pwdn(OV7725_PWDN_ACTIVE);
251     context->delay_ms(5);
252     context->write_pwdn(OV7725_PWDN_INACTIVE);
253     context->delay_ms(2);
254     context->write_rst(OV7725_RST_INACTIVE);
255     context->delay_ms(20);
256 }
257