hpm_ov7725.c 7.0 KB

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