ov7670.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * This file is part of the OpenMV project.
  3. * author: Juan Schiavoni <juanjoseschiavoni@hotmail.com>
  4. * This work is licensed under the MIT license, see the file LICENSE for details.
  5. *
  6. * OV7725 driver.
  7. *
  8. */
  9. #include <stdint.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "sccb.h"
  13. #include "ov7670.h"
  14. #include "ov7670_regs.h"
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/task.h"
  17. #include <stdio.h>
  18. #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
  19. #include "esp32-hal-log.h"
  20. #else
  21. #include "esp_log.h"
  22. static const char* TAG = "ov7760";
  23. #endif
  24. static int ov7670_clkrc = 0x01;
  25. /*
  26. * The default register settings, as obtained from OmniVision. There
  27. * is really no making sense of most of these - lots of "reserved" values
  28. * and such.
  29. *
  30. * These settings give VGA YUYV.
  31. */
  32. struct regval_list {
  33. uint8_t reg_num;
  34. uint8_t value;
  35. };
  36. static struct regval_list ov7670_default_regs[] = {
  37. /* Sensor automatically sets output window when resolution changes. */
  38. {TSLB, 0x04},
  39. /* Frame rate 30 fps at 12 Mhz clock */
  40. {CLKRC, 0x00},
  41. {DBLV, 0x4A},
  42. {COM10, COM10_VSYNC_NEG | COM10_PCLK_FREE},
  43. /* Improve white balance */
  44. {COM4, 0x40},
  45. /* Improve color */
  46. {RSVD_B0, 0x84},
  47. /* Enable 50/60 Hz auto detection */
  48. {COM11, COM11_EXP|COM11_HZAUTO},
  49. /* Disable some delays */
  50. {HSYST, 0},
  51. {HSYEN, 0},
  52. {MVFP, MVFP_SUN},
  53. /* More reserved magic, some of which tweaks white balance */
  54. {AWBC1, 0x0a},
  55. {AWBC2, 0xf0},
  56. {AWBC3, 0x34},
  57. {AWBC4, 0x58},
  58. {AWBC5, 0x28},
  59. {AWBC6, 0x3a},
  60. {AWBCTR3, 0x0a},
  61. {AWBCTR2, 0x55},
  62. {AWBCTR1, 0x11},
  63. {AWBCTR0, 0x9e},
  64. {COM8, COM8_FAST_AUTO|COM8_STEP_UNLIMIT|COM8_AGC_EN|COM8_AEC_EN|COM8_AWB_EN},
  65. /* End marker is FF because in ov7670 the address of GAIN 0 and default value too. */
  66. {0xFF, 0xFF},
  67. };
  68. static struct regval_list ov7670_fmt_yuv422[] = {
  69. { COM7, 0x0 }, /* Selects YUV mode */
  70. { RGB444, 0 }, /* No RGB444 please */
  71. { COM1, 0 }, /* CCIR601 */
  72. { COM15, COM15_R00FF },
  73. { MVFP, MVFP_SUN },
  74. { COM9, 0x6A }, /* 128x gain ceiling; 0x8 is reserved bit */
  75. { MTX1, 0x80 }, /* "matrix coefficient 1" */
  76. { MTX2, 0x80 }, /* "matrix coefficient 2" */
  77. { MTX3, 0 }, /* vb */
  78. { MTX4, 0x22 }, /* "matrix coefficient 4" */
  79. { MTX5, 0x5e }, /* "matrix coefficient 5" */
  80. { MTX6, 0x80 }, /* "matrix coefficient 6" */
  81. { COM13, COM13_UVSAT },
  82. { 0xff, 0xff }, /* END MARKER */
  83. };
  84. static struct regval_list ov7670_fmt_rgb565[] = {
  85. { COM7, COM7_FMT_RGB565 }, /* Selects RGB mode */
  86. { RGB444, 0 }, /* No RGB444 please */
  87. { COM1, 0x0 }, /* CCIR601 */
  88. { COM15, COM15_RGB565 |COM15_R00FF },
  89. { MVFP, MVFP_SUN },
  90. { COM9, 0x6A }, /* 128x gain ceiling; 0x8 is reserved bit */
  91. { MTX1, 0xb3 }, /* "matrix coefficient 1" */
  92. { MTX2, 0xb3 }, /* "matrix coefficient 2" */
  93. { MTX3, 0 }, /* vb */
  94. { MTX4, 0x3d }, /* "matrix coefficient 4" */
  95. { MTX5, 0xa7 }, /* "matrix coefficient 5" */
  96. { MTX6, 0xe4 }, /* "matrix coefficient 6" */
  97. { COM13, COM13_UVSAT },
  98. { 0xff, 0xff }, /* END MARKER */
  99. };
  100. static struct regval_list ov7670_vga[] = {
  101. { COM3, 0x00 },
  102. { COM14, 0x00 },
  103. { SCALING_XSC, 0x3A },
  104. { SCALING_YSC, 0x35 },
  105. { SCALING_DCWCTR, 0x11 },
  106. { SCALING_PCLK_DIV, 0xF0 },
  107. { SCALING_PCLK_DELAY, 0x02 },
  108. { 0xff, 0xff },
  109. };
  110. static struct regval_list ov7670_qvga[] = {
  111. { COM3, 0x04 },
  112. { COM14, 0x19 },
  113. { SCALING_XSC, 0x3A },
  114. { SCALING_YSC, 0x35 },
  115. { SCALING_DCWCTR, 0x11 },
  116. { SCALING_PCLK_DIV, 0xF1 },
  117. { SCALING_PCLK_DELAY, 0x02 },
  118. { 0xff, 0xff },
  119. };
  120. static struct regval_list ov7670_qqvga[] = {
  121. { COM3, 0x04 }, //DCW enable
  122. { COM14, 0x1a }, //pixel clock divided by 4, manual scaling enable, DCW and PCLK controlled by register
  123. { SCALING_XSC, 0x3a },
  124. { SCALING_YSC, 0x35 },
  125. { SCALING_DCWCTR, 0x22 }, //downsample by 4
  126. { SCALING_PCLK_DIV, 0xf2 }, //pixel clock divided by 4
  127. { SCALING_PCLK_DELAY, 0x02 },
  128. { 0xff, 0xff },
  129. };
  130. /*
  131. * Write a list of register settings; ff/ff stops the process.
  132. */
  133. static int ov7670_write_array(sensor_t *sensor, struct regval_list *vals)
  134. {
  135. int ret = 0;
  136. while ( (vals->reg_num != 0xff || vals->value != 0xff) && (ret == 0) ) {
  137. ret = SCCB_Write(sensor->slv_addr, vals->reg_num, vals->value);
  138. ESP_LOGD(TAG, "reset reg %02X, W(%02X) R(%02X)", vals->reg_num,
  139. vals->value, SCCB_Read(sensor->slv_addr, vals->reg_num) );
  140. vals++;
  141. }
  142. return ret;
  143. }
  144. /*
  145. * Calculate the frame control registers.
  146. */
  147. static int ov7670_frame_control(sensor_t *sensor, int hstart, int hstop, int vstart, int vstop)
  148. {
  149. struct regval_list frame[7];
  150. frame[0].reg_num = HSTART;
  151. frame[0].value = (hstart >> 3);
  152. frame[1].reg_num = HSTOP;
  153. frame[1].value = (hstop >> 3);
  154. frame[2].reg_num = HREF;
  155. frame[2].value = (((hstop & 0x07) << 3) | (hstart & 0x07));
  156. frame[3].reg_num = VSTART;
  157. frame[3].value = (vstart >> 2);
  158. frame[4].reg_num = VSTOP;
  159. frame[4].value = (vstop >> 2);
  160. frame[5].reg_num = VREF;
  161. frame[5].value = (((vstop & 0x02) << 2) | (vstart & 0x02));
  162. /* End mark */
  163. frame[5].reg_num = 0xFF;
  164. frame[5].value = 0xFF;
  165. return ov7670_write_array(sensor, frame);
  166. }
  167. static int reset(sensor_t *sensor)
  168. {
  169. int ret;
  170. // Reset all registers
  171. SCCB_Write(sensor->slv_addr, COM7, COM7_RESET);
  172. // Delay 10 ms
  173. vTaskDelay(10 / portTICK_PERIOD_MS);
  174. ret = ov7670_write_array(sensor, ov7670_default_regs);
  175. // Delay
  176. vTaskDelay(30 / portTICK_PERIOD_MS);
  177. return ret;
  178. }
  179. static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
  180. {
  181. int ret;
  182. switch (pixformat) {
  183. case PIXFORMAT_RGB565:
  184. case PIXFORMAT_RGB888:
  185. ret = ov7670_write_array(sensor, ov7670_fmt_rgb565);
  186. break;
  187. case PIXFORMAT_YUV422:
  188. case PIXFORMAT_GRAYSCALE:
  189. default:
  190. ret = ov7670_write_array(sensor, ov7670_fmt_yuv422);
  191. break;
  192. }
  193. vTaskDelay(30 / portTICK_PERIOD_MS);
  194. /*
  195. * If we're running RGB565, we must rewrite clkrc after setting
  196. * the other parameters or the image looks poor. If we're *not*
  197. * doing RGB565, we must not rewrite clkrc or the image looks
  198. * *really* poor.
  199. *
  200. * (Update) Now that we retain clkrc state, we should be able
  201. * to write it unconditionally, and that will make the frame
  202. * rate persistent too.
  203. */
  204. if (pixformat == PIXFORMAT_RGB565) {
  205. ret = SCCB_Write(sensor->slv_addr, CLKRC, ov7670_clkrc);
  206. }
  207. return ret;
  208. }
  209. static int set_framesize(sensor_t *sensor, framesize_t framesize)
  210. {
  211. int ret;
  212. // store clkrc before changing window settings...
  213. ov7670_clkrc = SCCB_Read(sensor->slv_addr, CLKRC);
  214. switch (framesize){
  215. case FRAMESIZE_VGA:
  216. if( (ret = ov7670_write_array(sensor, ov7670_vga)) == 0 ) {
  217. /* These values from Omnivision */
  218. ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
  219. }
  220. break;
  221. case FRAMESIZE_QVGA:
  222. if( (ret = ov7670_write_array(sensor, ov7670_qvga)) == 0 ) {
  223. /* These values from Omnivision */
  224. ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
  225. }
  226. break;
  227. case FRAMESIZE_QQVGA:
  228. if( (ret = ov7670_write_array(sensor, ov7670_qqvga)) == 0 ) {
  229. /* These values from Omnivision */
  230. ret = ov7670_frame_control(sensor, 158, 14, 10, 490);
  231. }
  232. break;
  233. default:
  234. ret = -1;
  235. }
  236. vTaskDelay(30 / portTICK_PERIOD_MS);
  237. if (ret == 0) {
  238. sensor->status.framesize = framesize;
  239. }
  240. return ret;
  241. }
  242. static int set_colorbar(sensor_t *sensor, int enable)
  243. {
  244. uint8_t ret = 0;
  245. // Read register scaling_xsc
  246. uint8_t reg = SCCB_Read(sensor->slv_addr, SCALING_XSC);
  247. // Pattern to set color bar bit[0]=0 in every case
  248. reg = SCALING_XSC_CBAR(reg);
  249. // Write pattern to SCALING_XSC
  250. ret = SCCB_Write(sensor->slv_addr, SCALING_XSC, reg);
  251. // Read register scaling_ysc
  252. reg = SCCB_Read(sensor->slv_addr, SCALING_YSC);
  253. // Pattern to set color bar bit[0]=0 in every case
  254. reg = SCALING_YSC_CBAR(reg, enable);
  255. // Write pattern to SCALING_YSC
  256. ret = ret | SCCB_Write(sensor->slv_addr, SCALING_YSC, reg);
  257. // return 0 or 0xFF
  258. return ret;
  259. }
  260. static int set_whitebal(sensor_t *sensor, int enable)
  261. {
  262. // Read register COM8
  263. uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
  264. // Set white bal on/off
  265. reg = COM8_SET_AWB(reg, enable);
  266. // Write back register COM8
  267. return SCCB_Write(sensor->slv_addr, COM8, reg);
  268. }
  269. static int set_gain_ctrl(sensor_t *sensor, int enable)
  270. {
  271. // Read register COM8
  272. uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
  273. // Set white bal on/off
  274. reg = COM8_SET_AGC(reg, enable);
  275. // Write back register COM8
  276. return SCCB_Write(sensor->slv_addr, COM8, reg);
  277. }
  278. static int set_exposure_ctrl(sensor_t *sensor, int enable)
  279. {
  280. // Read register COM8
  281. uint8_t reg = SCCB_Read(sensor->slv_addr, COM8);
  282. // Set white bal on/off
  283. reg = COM8_SET_AEC(reg, enable);
  284. // Write back register COM8
  285. return SCCB_Write(sensor->slv_addr, COM8, reg);
  286. }
  287. static int set_hmirror(sensor_t *sensor, int enable)
  288. {
  289. // Read register MVFP
  290. uint8_t reg = SCCB_Read(sensor->slv_addr, MVFP);
  291. // Set mirror on/off
  292. reg = MVFP_SET_MIRROR(reg, enable);
  293. // Write back register MVFP
  294. return SCCB_Write(sensor->slv_addr, MVFP, reg);
  295. }
  296. static int set_vflip(sensor_t *sensor, int enable)
  297. {
  298. // Read register MVFP
  299. uint8_t reg = SCCB_Read(sensor->slv_addr, MVFP);
  300. // Set mirror on/off
  301. reg = MVFP_SET_FLIP(reg, enable);
  302. // Write back register MVFP
  303. return SCCB_Write(sensor->slv_addr, MVFP, reg);
  304. }
  305. static int init_status(sensor_t *sensor)
  306. {
  307. sensor->status.awb = 0;
  308. sensor->status.aec = 0;
  309. sensor->status.agc = 0;
  310. sensor->status.hmirror = 0;
  311. sensor->status.vflip = 0;
  312. sensor->status.colorbar = 0;
  313. return 0;
  314. }
  315. static int set_dummy(sensor_t *sensor, int val){ return -1; }
  316. static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val){ return -1; }
  317. int ov7670_detect(int slv_addr, sensor_id_t *id)
  318. {
  319. if (OV7670_SCCB_ADDR == slv_addr) {
  320. SCCB_Write(slv_addr, 0xFF, 0x01);//bank sensor
  321. uint16_t PID = SCCB_Read(slv_addr, 0x0A);
  322. if (OV7670_PID == PID) {
  323. id->PID = PID;
  324. id->VER = SCCB_Read(slv_addr, REG_VER);
  325. id->MIDL = SCCB_Read(slv_addr, REG_MIDL);
  326. id->MIDH = SCCB_Read(slv_addr, REG_MIDH);
  327. return PID;
  328. } else {
  329. ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
  330. }
  331. }
  332. return 0;
  333. }
  334. int ov7670_init(sensor_t *sensor)
  335. {
  336. // Set function pointers
  337. sensor->reset = reset;
  338. sensor->init_status = init_status;
  339. sensor->set_pixformat = set_pixformat;
  340. sensor->set_framesize = set_framesize;
  341. sensor->set_colorbar = set_colorbar;
  342. sensor->set_whitebal = set_whitebal;
  343. sensor->set_gain_ctrl = set_gain_ctrl;
  344. sensor->set_exposure_ctrl = set_exposure_ctrl;
  345. sensor->set_hmirror = set_hmirror;
  346. sensor->set_vflip = set_vflip;
  347. //not supported
  348. sensor->set_brightness= set_dummy;
  349. sensor->set_saturation= set_dummy;
  350. sensor->set_quality = set_dummy;
  351. sensor->set_gainceiling = set_gainceiling_dummy;
  352. sensor->set_aec2 = set_dummy;
  353. sensor->set_aec_value = set_dummy;
  354. sensor->set_special_effect = set_dummy;
  355. sensor->set_wb_mode = set_dummy;
  356. sensor->set_ae_level = set_dummy;
  357. sensor->set_dcw = set_dummy;
  358. sensor->set_bpc = set_dummy;
  359. sensor->set_wpc = set_dummy;
  360. sensor->set_awb_gain = set_dummy;
  361. sensor->set_agc_gain = set_dummy;
  362. sensor->set_raw_gma = set_dummy;
  363. sensor->set_lenc = set_dummy;
  364. sensor->set_sharpness = set_dummy;
  365. sensor->set_denoise = set_dummy;
  366. // Retrieve sensor's signature
  367. sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH);
  368. sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL);
  369. sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID);
  370. sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER);
  371. ESP_LOGD(TAG, "OV7670 Attached");
  372. return 0;
  373. }