drv_ov5640.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-08-03 thread-liu the first version
  9. */
  10. #include "board.h"
  11. #if defined(BSP_USING_DCMI)
  12. #include "drv_mfx.h"
  13. #include <dfs_posix.h>
  14. #include "drv_ov5640.h"
  15. //#define DRV_DEBUG
  16. //#define CAMERA_DUMP
  17. #define LOG_TAG "drv.ov5640"
  18. #include <drv_log.h>
  19. #define CHIP_ADDRESS 0x3C /* OV5640 address */
  20. #define I2C_NAME "i2c2"
  21. #define JPEG_BUF_SIZE 8 * 1024
  22. #define JPEG_LINE_SIZE 1 * 1024
  23. #if defined(__CC_ARM) || defined(__CLANG_ARM)
  24. __attribute__((at(0x2FFCC000))) static rt_int32_t JPEG_DATA_BUF[JPEG_BUF_SIZE];
  25. #elif defined(__GNUC__)
  26. static rt_int32_t JPEG_DATA_BUF[JPEG_BUF_SIZE] __attribute__((section(".Dcmi0Section")));
  27. #elif defined(__ICCARM__)
  28. #pragma location = 0x2FFCC000
  29. __no_init static rt_int32_t JPEG_DATA_BUF[JPEG_BUF_SIZE];
  30. #endif
  31. #if defined(__CC_ARM) || defined(__CLANG_ARM)
  32. __attribute__((at(0x2FFDC000))) static rt_int32_t JPEG_LINE_BUF[2][JPEG_LINE_SIZE];
  33. #elif defined(__GNUC__)
  34. static rt_int32_t JPEG_LINE_BUF[2][JPEG_LINE_SIZE] __attribute__((section(".Dcmi1Section")));
  35. #elif defined(__ICCARM__)
  36. #pragma location = 0x2FFDC000
  37. __no_init static rt_int32_t JPEG_LINE_BUF[2][JPEG_LINE_SIZE];
  38. #endif
  39. volatile rt_uint32_t jpeg_data_len = 0;
  40. volatile rt_uint8_t jpeg_data_ok = 0;
  41. struct rt_i2c_bus_device *i2c_bus = RT_NULL;
  42. extern DCMI_HandleTypeDef dcmi;
  43. extern DMA_HandleTypeDef hdma_dcmi;
  44. #if defined(CAMERA_DUMP)
  45. #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
  46. static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
  47. {
  48. unsigned char *buf = (unsigned char *)ptr;
  49. int i, j;
  50. for (i = 0; i < buflen; i += 16)
  51. {
  52. rt_kprintf("%08x:", i);
  53. for (j = 0; j < 16; j++)
  54. {
  55. if (i + j < buflen)
  56. {
  57. rt_kprintf("%02x", buf[i + j]);
  58. }
  59. else
  60. {
  61. rt_kprintf(" ");
  62. }
  63. }
  64. rt_kprintf(" ");
  65. for (j = 0; j < 16; j++)
  66. {
  67. if (i + j < buflen)
  68. {
  69. rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
  70. }
  71. }
  72. rt_kprintf("\n");
  73. }
  74. }
  75. #endif
  76. static rt_err_t read_reg(struct rt_i2c_bus_device *bus, rt_uint16_t reg, rt_uint8_t len, rt_uint8_t *buf)
  77. {
  78. struct rt_i2c_msg msg[2] = {0, 0};
  79. static rt_uint8_t i2c_reg[2] = {0, 0};
  80. RT_ASSERT(bus != RT_NULL);
  81. i2c_reg[0] = ((uint16_t)(reg >> 8) & 0xFF);
  82. i2c_reg[1] = ((uint16_t)(reg & 0xFF));
  83. msg[0].addr = CHIP_ADDRESS;
  84. msg[0].flags = RT_I2C_WR;
  85. msg[0].buf = i2c_reg;
  86. msg[0].len = 2;
  87. msg[1].addr = CHIP_ADDRESS;
  88. msg[1].flags = RT_I2C_RD;
  89. msg[1].len = len;
  90. msg[1].buf = buf;
  91. if (rt_i2c_transfer(bus, msg, 2) == 2)
  92. {
  93. return RT_EOK;
  94. }
  95. return RT_ERROR;
  96. }
  97. /* i2c write reg */
  98. static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint16_t reg, rt_uint8_t data)
  99. {
  100. rt_uint8_t buf[3];
  101. struct rt_i2c_msg msgs;
  102. RT_ASSERT(bus != RT_NULL);
  103. buf[0] = ((uint16_t)(reg >> 8) & 0xFF);
  104. buf[1] = ((uint16_t)(reg)&0xFF);
  105. buf[2] = data;
  106. msgs.addr = CHIP_ADDRESS;
  107. msgs.flags = RT_I2C_WR;
  108. msgs.buf = buf;
  109. msgs.len = 3;
  110. if (rt_i2c_transfer(bus, &msgs, 1) == 1)
  111. {
  112. return RT_EOK;
  113. }
  114. return RT_ERROR;
  115. }
  116. static rt_err_t ov5640_read_id(struct rt_i2c_bus_device *bus, rt_uint16_t *id)
  117. {
  118. rt_uint8_t read_value[2];
  119. read_reg(bus, 0x300A, 1, &read_value[0]);
  120. read_reg(bus, 0x300B, 1, &read_value[1]);
  121. *id = ((uint16_t)(read_value[0] << 8) & 0xFF00);
  122. *id |= ((uint16_t)(read_value[1]) & 0x00FF);
  123. if (*id != OV5640_ID)
  124. {
  125. LOG_E("ov5640 init error, id: 0x%04x", *id);
  126. return RT_ERROR;
  127. }
  128. LOG_I("ov5640 init success, id: 0x%04x", *id);
  129. return RT_EOK;
  130. }
  131. static rt_err_t ov5640_hard_reset(struct rt_i2c_bus_device *bus)
  132. {
  133. /* Camera sensor RESET sequence */
  134. rt_mfx_pin_mode(CAMERA_RST1, IO_MODE_OUTPUT);
  135. rt_mfx_pin_mode(CAMERA_XSDN, IO_MODE_OUTPUT);
  136. /* Assert the camera STANDBY pin (active high) */
  137. rt_mfx_pin_write(CAMERA_XSDN, BSP_IO_PIN_SET);
  138. /* Assert the camera RSTI pin (active low) */
  139. rt_mfx_pin_write(CAMERA_RST1, BSP_IO_PIN_RESET);
  140. rt_thread_delay(100); /* RST and XSDN signals asserted during 100ms */
  141. /* De-assert the camera STANDBY pin (active high) */
  142. rt_mfx_pin_write(CAMERA_XSDN, BSP_IO_PIN_RESET);
  143. rt_thread_delay(3); /* RST de-asserted and XSDN asserted during 3ms */
  144. /* De-assert the camera RSTI pin (active low) */
  145. rt_mfx_pin_write(CAMERA_RST1, BSP_IO_PIN_SET);
  146. rt_thread_delay(6); /* RST de-asserted during 3ms */
  147. return RT_EOK;
  148. }
  149. void OV5640_Flash_Ctrl(struct rt_i2c_bus_device *bus, rt_uint8_t sw)
  150. {
  151. write_reg(bus, 0x3016, 0X02);
  152. write_reg(bus, 0x301C, 0X02);
  153. if (sw)
  154. {
  155. write_reg(bus, 0X3019, 0X02);
  156. }
  157. else
  158. {
  159. write_reg(bus, 0X3019, 0X00);
  160. }
  161. }
  162. static rt_err_t ov5640_config(struct rt_i2c_bus_device *bus)
  163. {
  164. rt_uint32_t i = 0;
  165. rt_uint8_t value = 0;
  166. write_reg(bus, 0x3103, 0X11); /* system clock from pad, bit[1] */
  167. write_reg(bus, 0X3008, 0X82); /* soft reset */
  168. rt_thread_delay(10);
  169. for (i = 0; i < (sizeof(RGB565_Init) / 4); i++)
  170. {
  171. write_reg(bus, RGB565_Init[i][0], RGB565_Init[i][1]);
  172. rt_thread_delay(10);
  173. read_reg(bus, RGB565_Init[i][0], 1, &value);
  174. if (RGB565_Init[i][1] != value)
  175. {
  176. LOG_D("error reg value[0x%x]:0x%02x - 0x%02x", RGB565_Init[i][0], RGB565_Init[i][1], value);
  177. }
  178. }
  179. OV5640_Flash_Ctrl(bus, 1); /* open camera flash*/
  180. rt_thread_delay(3);
  181. OV5640_Flash_Ctrl(bus, 0); /* close camera flash*/
  182. return RT_EOK;
  183. }
  184. /* JPEG */
  185. void ov5640_jpeg_mode(struct rt_i2c_bus_device *bus)
  186. {
  187. rt_uint16_t i = 0;
  188. for (i = 0; i < (sizeof(OV5640_jpeg_reg_tbl) / 4); i++)
  189. {
  190. write_reg(bus, OV5640_jpeg_reg_tbl[i][0], OV5640_jpeg_reg_tbl[i][1]);
  191. }
  192. }
  193. /* RGB565 */
  194. void ov5640_rgb565_mode(struct rt_i2c_bus_device *bus)
  195. {
  196. rt_uint16_t i = 0;
  197. for (i = 0; i < (sizeof(ov5640_rgb565_reg_tbl) / 4); i++)
  198. {
  199. write_reg(bus, ov5640_rgb565_reg_tbl[i][0], ov5640_rgb565_reg_tbl[i][1]);
  200. }
  201. write_reg(bus, 0x3821, 0x06);
  202. }
  203. rt_uint8_t ov5640_focus_init(struct rt_i2c_bus_device *bus)
  204. {
  205. rt_uint16_t tickstart = 0 ,i = 0;
  206. rt_uint16_t addr = 0x8000;
  207. rt_uint8_t state = 0x8F;
  208. write_reg(bus, 0x3000, 0x20); //reset MCU
  209. for (i = 0; i < sizeof(OV5640_AF_Config); i++)
  210. {
  211. write_reg(bus, addr, OV5640_AF_Config[i]);
  212. addr++;
  213. }
  214. write_reg(bus, 0x3022, 0x00);
  215. write_reg(bus, 0x3023, 0x00);
  216. write_reg(bus, 0x3024, 0x00);
  217. write_reg(bus, 0x3025, 0x00);
  218. write_reg(bus, 0x3026, 0x00);
  219. write_reg(bus, 0x3027, 0x00);
  220. write_reg(bus, 0x3028, 0x00);
  221. write_reg(bus, 0x3029, 0x7f);
  222. write_reg(bus, 0x3000, 0x00);
  223. i = 0;
  224. tickstart = rt_tick_get();
  225. do
  226. {
  227. read_reg(bus, 0x3029, 1, &state);
  228. if (rt_tick_get() - tickstart > 1000)
  229. {
  230. return RT_ERROR;
  231. }
  232. } while (state != 0x70);
  233. return RT_EOK;
  234. }
  235. void ov5640_set_light(struct rt_i2c_bus_device *bus, rt_uint8_t mode)
  236. {
  237. rt_uint8_t i = 0;
  238. write_reg(bus, 0x3212, 0x03); //start group 3
  239. for (i = 0; i < 7; i++)
  240. {
  241. write_reg(bus, 0x3400 + i, OV5640_LIGHTMODE_TBL[mode][i]);
  242. }
  243. write_reg(bus, 0x3212, 0x13); //end group 3
  244. write_reg(bus, 0x3212, 0xa3); //launch group 3
  245. }
  246. /* sat:0~6 */
  247. void ov5640_color_saturation(struct rt_i2c_bus_device *bus, rt_uint8_t sat)
  248. {
  249. rt_uint8_t i = 0;
  250. write_reg(bus, 0x3212, 0x03); //start group 3
  251. write_reg(bus, 0x5381, 0x1c);
  252. write_reg(bus, 0x5382, 0x5a);
  253. write_reg(bus, 0x5383, 0x06);
  254. for (i = 0; i < 6; i++)
  255. {
  256. write_reg(bus, 0x5384 + i, OV5640_SATURATION_TBL[sat][i]);
  257. }
  258. write_reg(bus, 0x538b, 0x98);
  259. write_reg(bus, 0x538a, 0x01);
  260. write_reg(bus, 0x3212, 0x13); //end group 3
  261. write_reg(bus, 0x3212, 0xa3); //launch group 3
  262. }
  263. /* bright:0~8 */
  264. void ov5640_set_brightness(struct rt_i2c_bus_device *bus, rt_uint8_t bright)
  265. {
  266. rt_uint8_t brtval;
  267. if (bright < 4)
  268. {
  269. brtval = 4 - bright;
  270. }
  271. else
  272. {
  273. brtval = bright - 4;
  274. }
  275. write_reg(bus, 0x3212, 0x03); //start group 3
  276. write_reg(bus, 0x5587, brtval << 4);
  277. if (bright < 4)
  278. {
  279. write_reg(bus, 0x5588, 0x09);
  280. }
  281. else
  282. {
  283. write_reg(bus, 0x5588, 0x01);
  284. }
  285. write_reg(bus, 0x3212, 0x13); //end group 3
  286. write_reg(bus, 0x3212, 0xa3); //launch group 3
  287. }
  288. /* contrast:0~6 */
  289. void ov5640_contrast(struct rt_i2c_bus_device *bus, rt_uint8_t contrast)
  290. {
  291. rt_uint8_t reg0val = 0x00;
  292. rt_uint8_t reg1val = 0x20;
  293. switch (contrast)
  294. {
  295. case 0:
  296. reg1val = reg0val = 0X14;
  297. break;
  298. case 1:
  299. reg1val = reg0val = 0X18;
  300. break;
  301. case 2:
  302. reg1val = reg0val = 0X1C;
  303. break;
  304. case 4:
  305. reg0val = 0X10;
  306. reg1val = 0X24;
  307. break;
  308. case 5:
  309. reg0val = 0X18;
  310. reg1val = 0X28;
  311. break;
  312. case 6:
  313. reg0val = 0X1C;
  314. reg1val = 0X2C;
  315. break;
  316. }
  317. write_reg(bus, 0x3212, 0x03); //start group 3
  318. write_reg(bus, 0x5585, reg0val);
  319. write_reg(bus, 0x5586, reg1val);
  320. write_reg(bus, 0x3212, 0x13); //end group 3
  321. write_reg(bus, 0x3212, 0xa3); //launch group 3
  322. }
  323. /* sharp:0~33 */
  324. void ov5640_set_sharpness(struct rt_i2c_bus_device *bus, rt_uint8_t sharp)
  325. {
  326. if (sharp < 33)
  327. {
  328. write_reg(bus, 0x5308, 0x65);
  329. write_reg(bus, 0x5302, sharp);
  330. }
  331. else
  332. {
  333. write_reg(bus, 0x5308, 0x25);
  334. write_reg(bus, 0x5300, 0x08);
  335. write_reg(bus, 0x5301, 0x30);
  336. write_reg(bus, 0x5302, 0x10);
  337. write_reg(bus, 0x5303, 0x00);
  338. write_reg(bus, 0x5309, 0x08);
  339. write_reg(bus, 0x530a, 0x30);
  340. write_reg(bus, 0x530b, 0x04);
  341. write_reg(bus, 0x530c, 0x06);
  342. }
  343. }
  344. rt_uint8_t ov5640_focus_constant(struct rt_i2c_bus_device *bus)
  345. {
  346. rt_uint8_t temp = 0;
  347. rt_uint16_t tickstrat = 0;
  348. write_reg(bus, 0x3023, 0x01);
  349. write_reg(bus, 0x3022, 0x08);
  350. do
  351. {
  352. tickstrat = rt_tick_get();
  353. read_reg(bus, 0x3023, 1, &temp);
  354. if (rt_tick_get() - tickstrat > 1000)
  355. {
  356. return RT_ERROR;
  357. }
  358. } while (temp != 0x00);
  359. write_reg(bus, 0x3023, 0x01);
  360. write_reg(bus, 0x3022, 0x04);
  361. do
  362. {
  363. tickstrat = rt_tick_get();
  364. read_reg(bus, 0x3023, 1, &temp);
  365. if (rt_tick_get() - tickstrat > 1000)
  366. {
  367. return RT_ERROR;
  368. }
  369. } while (temp != 0x00);
  370. return 0;
  371. }
  372. rt_uint8_t ov5640_set_outsize(struct rt_i2c_bus_device *bus, rt_uint16_t offx, rt_uint16_t offy, rt_uint16_t width, rt_uint16_t height)
  373. {
  374. write_reg(bus, 0X3212, 0X03);
  375. write_reg(bus, 0x3808, width >> 8);
  376. write_reg(bus, 0x3809, width & 0xff);
  377. write_reg(bus, 0x380a, height >> 8);
  378. write_reg(bus, 0x380b, height & 0xff);
  379. write_reg(bus, 0x3810, offx >> 8);
  380. write_reg(bus, 0x3811, offx & 0xff);
  381. write_reg(bus, 0x3812, offy >> 8);
  382. write_reg(bus, 0x3813, offy & 0xff);
  383. write_reg(bus, 0X3212, 0X13);
  384. write_reg(bus, 0X3212, 0Xa3);
  385. return RT_EOK;
  386. }
  387. void rt_hw_camera_rx_callback(void)
  388. {
  389. rt_uint16_t i;
  390. rt_int32_t *pbuf = RT_NULL;
  391. pbuf = JPEG_DATA_BUF + jpeg_data_len;
  392. if (hdma_dcmi.Instance->CR & (1 << 19))
  393. {
  394. for (i = 0; i < JPEG_LINE_SIZE; i++)
  395. {
  396. pbuf[i] = JPEG_LINE_BUF[0][i];
  397. }
  398. jpeg_data_len += JPEG_LINE_SIZE;
  399. }
  400. else
  401. {
  402. for (i = 0; i < JPEG_LINE_SIZE; i++)
  403. {
  404. pbuf[i] = JPEG_LINE_BUF[1][i];
  405. }
  406. jpeg_data_len += JPEG_LINE_SIZE;
  407. }
  408. }
  409. /* After a frame of JPEG data has been collected. */
  410. void jpeg_data_process(void)
  411. {
  412. rt_uint16_t i, rlen;
  413. int *pbuf = RT_NULL;
  414. if (!jpeg_data_ok)
  415. {
  416. __HAL_DMA_DISABLE(&hdma_dcmi);
  417. rlen = JPEG_LINE_SIZE - __HAL_DMA_GET_COUNTER(&hdma_dcmi);
  418. pbuf = JPEG_DATA_BUF + jpeg_data_len;
  419. if (hdma_dcmi.Instance->CR & (1 << 19))
  420. {
  421. for (i = 0; i < rlen; i++)
  422. {
  423. pbuf[i] = JPEG_LINE_BUF[1][i];
  424. }
  425. }
  426. else
  427. {
  428. for (i = 0; i < rlen; i++)
  429. {
  430. pbuf[i] = JPEG_LINE_BUF[0][i];
  431. }
  432. }
  433. jpeg_data_len += rlen;
  434. jpeg_data_ok = 1;
  435. }
  436. if (jpeg_data_ok == 2)
  437. {
  438. __HAL_DMA_SET_COUNTER(&hdma_dcmi, JPEG_LINE_SIZE);
  439. __HAL_DMA_ENABLE(&hdma_dcmi);
  440. jpeg_data_ok = 0;
  441. jpeg_data_len = 0;
  442. }
  443. }
  444. int rt_hw_ov5640_init(void)
  445. {
  446. extern void rt_hw_dcmi_dma_config(rt_uint32_t dst_addr1, rt_uint32_t dst_addr2, rt_uint16_t len);
  447. static rt_uint16_t id = 0;
  448. rt_device_t dcmi_dev = RT_NULL;
  449. i2c_bus = rt_i2c_bus_device_find(I2C_NAME);
  450. if (i2c_bus == RT_NULL)
  451. {
  452. LOG_E("can't find %c deivce", I2C_NAME);
  453. return RT_ERROR;
  454. }
  455. ov5640_hard_reset(i2c_bus);
  456. ov5640_read_id(i2c_bus, &id);
  457. ov5640_config(i2c_bus);
  458. ov5640_rgb565_mode(i2c_bus); /* rgb565 mode */
  459. ov5640_focus_init(i2c_bus);
  460. ov5640_jpeg_mode(i2c_bus); /* jpeg mode */
  461. ov5640_set_light(i2c_bus, 0); /* auto mode */
  462. ov5640_color_saturation(i2c_bus, 3);
  463. ov5640_set_brightness(i2c_bus, 4); /* brigetness 0 */
  464. ov5640_contrast(i2c_bus, 3);
  465. ov5640_set_sharpness(i2c_bus, 33);
  466. ov5640_focus_constant(i2c_bus);
  467. /* dcmi init */
  468. dcmi_dev = rt_device_find("dcmi");
  469. if (dcmi_dev == RT_NULL)
  470. {
  471. LOG_E("can't find dcmi device!");
  472. return RT_ERROR;
  473. }
  474. rt_device_open(dcmi_dev, RT_DEVICE_FLAG_RDWR);
  475. rt_hw_dcmi_dma_config((rt_uint32_t)&JPEG_LINE_BUF[0], (rt_uint32_t)&JPEG_LINE_BUF[1], JPEG_LINE_SIZE);
  476. ov5640_set_outsize(i2c_bus, 4, 0, jpeg_picture_size[1][0], jpeg_picture_size[1][1]);
  477. return RT_EOK;
  478. }
  479. INIT_APP_EXPORT(rt_hw_ov5640_init);
  480. int camera_sample(int argc, char **argv)
  481. {
  482. int fd = -1;
  483. rt_uint32_t i, jpg_start, jpg_len;
  484. rt_uint16_t tickstart = 0;
  485. rt_uint8_t jpg_head = 0;
  486. rt_uint8_t *p = RT_NULL;
  487. if (argc != 2)
  488. {
  489. rt_kprintf("Usage:\n");
  490. rt_kprintf("camera_sample file.jpg\n");
  491. return -1;
  492. }
  493. /* start dcmi capture */
  494. __HAL_DMA_ENABLE(&hdma_dcmi);
  495. dcmi.Instance->CR |= DCMI_CR_CAPTURE;
  496. tickstart = rt_tick_get();
  497. while (1)
  498. {
  499. if (rt_tick_get() - tickstart > 1000)
  500. {
  501. LOG_E("picture capture overtime!");
  502. break;
  503. }
  504. if (jpeg_data_ok == 1)
  505. {
  506. dcmi.Instance->CR &= ~(DCMI_CR_CAPTURE);
  507. tickstart = rt_tick_get();
  508. while(dcmi.Instance->CR & 0x01)
  509. {
  510. if (rt_tick_get() - tickstart > 0x1000)
  511. {
  512. rt_kprintf("dcmi close failed!\n");
  513. jpeg_data_ok = 2;
  514. break;
  515. }
  516. }
  517. __HAL_DMA_DISABLE(&hdma_dcmi);
  518. p = (rt_uint8_t *)JPEG_DATA_BUF;
  519. jpg_len = 0;
  520. jpg_head = 0;
  521. for (i = 0; i < jpeg_data_len * 4; i++)
  522. {
  523. /* jpg head */
  524. if ((p[i] == 0xFF) && (p[i + 1] == 0xD8))
  525. {
  526. jpg_start = i;
  527. jpg_head = 1;
  528. }
  529. /* jpg end */
  530. if ((p[i] == 0xFF) && (p[i + 1] == 0xD9) && jpg_head)
  531. {
  532. jpg_len = i - jpg_start + 2; /* a picture len */
  533. break;
  534. }
  535. }
  536. if (jpg_len)
  537. {
  538. p += jpg_start;
  539. fd = open(argv[1], O_WRONLY | O_CREAT);
  540. if (fd < 0)
  541. {
  542. rt_kprintf("open file for recording failed!\n");
  543. return -RT_ERROR;
  544. }
  545. else
  546. {
  547. write(fd, p, jpg_len);
  548. close(fd);
  549. rt_kprintf("picture capture complate!\n");
  550. break;
  551. }
  552. }
  553. jpeg_data_ok = 2;
  554. }
  555. }
  556. return RT_EOK;
  557. }
  558. MSH_CMD_EXPORT(camera_sample, record picture to a jpg file);
  559. #endif