drv_ov2640.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-03-24 spaceman the first version
  9. */
  10. #include "board.h"
  11. #ifdef BSP_USING_OV2640
  12. #include <dfs_file.h>
  13. #include <unistd.h>
  14. #include <stdio.h>
  15. #include <sys/stat.h>
  16. #include <sys/statfs.h>
  17. #include "drv_dcmi.h"
  18. #include "drv_ov2640.h"
  19. #include "drv_ov2640_cfg.h"
  20. #define DRV_DEBUG
  21. //#define CAMERA_DUMP
  22. #define LOG_TAG "drv.ov2640"
  23. #include <drv_log.h>
  24. #define CHIP_ADDRESS 0x30 /* OV2640 address */
  25. // #define CHIP_ADDRESS 0x3C /* OV5640 address */
  26. #define I2C_NAME "i2c1"
  27. #define PWDN_PIN GET_PIN(D, 14)
  28. struct rt_i2c_bus_device *i2c_bus = RT_NULL;
  29. #if defined(CAMERA_DUMP)
  30. #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
  31. static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
  32. {
  33. unsigned char *buf = (unsigned char *)ptr;
  34. int i, j;
  35. for (i = 0; i < buflen; i += 16)
  36. {
  37. rt_kprintf("%08x:", i);
  38. for (j = 0; j < 16; j++)
  39. {
  40. if (i + j < buflen)
  41. {
  42. rt_kprintf("%02x", buf[i + j]);
  43. }
  44. else
  45. {
  46. rt_kprintf(" ");
  47. }
  48. }
  49. rt_kprintf(" ");
  50. for (j = 0; j < 16; j++)
  51. {
  52. if (i + j < buflen)
  53. {
  54. rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
  55. }
  56. }
  57. rt_kprintf("\n");
  58. }
  59. }
  60. #endif
  61. /* i2c read reg */
  62. static rt_err_t read_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
  63. {
  64. struct rt_i2c_msg msg[2] = {0, 0};
  65. RT_ASSERT(bus != RT_NULL);
  66. msg[0].addr = CHIP_ADDRESS;
  67. msg[0].flags = RT_I2C_WR;
  68. msg[0].buf = &reg;
  69. msg[0].len = 1;
  70. msg[1].addr = CHIP_ADDRESS;
  71. msg[1].flags = RT_I2C_RD;
  72. msg[1].len = len;
  73. msg[1].buf = buf;
  74. if (rt_i2c_transfer(bus, msg, 2) == 2)
  75. {
  76. return RT_EOK;
  77. }
  78. return -RT_ERROR;
  79. }
  80. /* i2c write reg */
  81. static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data)
  82. {
  83. rt_uint8_t buf[2];
  84. struct rt_i2c_msg msgs;
  85. RT_ASSERT(bus != RT_NULL);
  86. buf[0] = reg;
  87. buf[1] = data;
  88. msgs.addr = CHIP_ADDRESS;
  89. msgs.flags = RT_I2C_WR;
  90. msgs.buf = buf;
  91. msgs.len = 2;
  92. if (rt_i2c_transfer(bus, &msgs, 1) == 1)
  93. {
  94. return RT_EOK;
  95. }
  96. return -RT_ERROR;
  97. }
  98. static rt_err_t ov2640_read_id(struct rt_i2c_bus_device *bus, rt_uint16_t *id)
  99. {
  100. rt_uint8_t read_value[2];
  101. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_SENSOR); // 选择 SENSOR 寄存器组
  102. read_reg(bus, OV2640_SENSOR_PIDH, 1, &read_value[0]); // 读取ID高字节
  103. read_reg(bus, OV2640_SENSOR_PIDL, 1, &read_value[1]); // 读取ID低字节
  104. *id = ((rt_uint16_t)(read_value[0] << 8) & 0xFF00);
  105. *id |= ((rt_uint16_t)(read_value[1]) & 0x00FF);
  106. if ((*id != OV2640_ID1) && (*id != OV2640_ID2)) {
  107. LOG_E("ov2640 init error, id: 0x%04x", *id);
  108. return -RT_ERROR;
  109. }
  110. LOG_I("ov2640 init success, id: 0x%04x", *id);
  111. return RT_EOK;
  112. }
  113. static rt_err_t ov2640_reset(struct rt_i2c_bus_device *bus)
  114. {
  115. rt_pin_mode(PWDN_PIN, PIN_MODE_OUTPUT);
  116. rt_thread_mdelay(5); // 等待模块上电稳定,最少5ms,然后拉低PWDN
  117. rt_pin_write(PWDN_PIN, PIN_LOW); // PWDN 引脚输出低电平,不开启掉电模式,摄像头正常工作,此时摄像头模块的白色LED会点亮
  118. // 根据OV2640的上电时序,硬件复位的持续时间要>=3ms,反客的OV2640采用硬件RC复位,持续时间大概在6ms左右
  119. // 因此加入延时,等待硬件复位完成并稳定下来
  120. rt_thread_mdelay(5);
  121. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_SENSOR); // 选择 SENSOR 寄存器组
  122. write_reg(bus, OV2640_SENSOR_COM7, 0x80); // 启动软件复位
  123. // 根据OV2640的软件复位时序,软件复位执行后,要>=2ms方可执行SCCB配置,此处采用保守一点的参数,延时10ms
  124. rt_thread_mdelay(10);
  125. return RT_EOK;
  126. }
  127. static rt_err_t ov2640_config(struct rt_i2c_bus_device *bus, const rt_uint8_t (*configdata)[2])
  128. {
  129. rt_uint32_t i = 0;
  130. for (i = 0; configdata[i][0]; i++) {
  131. write_reg(bus, configdata[i][0], configdata[i][1]); // 进行参数配置
  132. }
  133. return RT_EOK;
  134. }
  135. void ov2640_set_pixformat(struct rt_i2c_bus_device *bus, rt_uint8_t pixformat)
  136. {
  137. const rt_uint8_t(*configdata)[2];
  138. uint32_t i; // 计数变量
  139. switch (pixformat) {
  140. case Pixformat_RGB565:
  141. configdata = OV2640_RGB565_Config;
  142. break;
  143. case Pixformat_JPEG:
  144. configdata = OV2640_JPEG_Config;
  145. break;
  146. default:
  147. break;
  148. }
  149. for (i = 0; configdata[i][0]; i++) {
  150. write_reg(bus, configdata[i][0], configdata[i][1]); // 进行参数配置
  151. }
  152. }
  153. rt_err_t ov2640_set_framesize(struct rt_i2c_bus_device *bus, rt_uint16_t width, rt_uint16_t height)
  154. {
  155. if ((width % 4) || (height % 4)) // 输出图像的大小一定要能被4整除
  156. {
  157. return -RT_ERROR; // 返回错误标志
  158. }
  159. write_reg(bus, OV2640_SEL_Registers,OV2640_SEL_DSP); // 选择 dsp寄存器组
  160. write_reg(bus, 0x5a, width / 4 & 0xff); // 实际图像输出的宽度(outw),7~0 bit,寄存器的值等于实际值/4
  161. write_reg(bus, 0x5b, height / 4 & 0xff); // 实际图像输出的高度(outh),7~0 bit,寄存器的值等于实际值/4
  162. write_reg(bus, 0x5c, (width / 4 >> 8 & 0x03) | (height / 4 >> 6 & 0x04)); // 设置zmhh的bit[2:0],也就是outh 的第 8 bit,outw 的第 9~8 bit,
  163. write_reg(bus, OV2640_DSP_RESET, 0x00); // 复位
  164. return RT_EOK; // 成功
  165. }
  166. rt_err_t ov2640_set_horizontal_mirror(struct rt_i2c_bus_device *bus, rt_uint8_t configstate)
  167. {
  168. rt_uint8_t ov2640_reg; // 寄存器的值
  169. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_SENSOR); // 选择 sensor 寄存器组
  170. read_reg(bus, OV2640_SENSOR_REG04, 1, &ov2640_reg); // 读取 0x04 的寄存器值
  171. // reg04,寄存器组4,寄存器地址为 0x04,该寄存器的bit[7],用于设置水平是否镜像
  172. if (configstate == OV2640_Enable) // 如果使能镜像
  173. {
  174. ov2640_reg |= 0x80; // bit[7]置1则镜像
  175. } else // 取消镜像
  176. {
  177. ov2640_reg &= ~0x80; // bit[7]置0则是正常模式
  178. }
  179. return write_reg(bus, OV2640_SENSOR_REG04, ov2640_reg); // 写入寄存器
  180. }
  181. rt_err_t ov2640_set_vertical_flip(struct rt_i2c_bus_device *bus, rt_uint8_t configstate)
  182. {
  183. rt_uint8_t ov2640_reg; // 寄存器的值
  184. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_SENSOR); // 选择 sensor 寄存器组
  185. read_reg(bus, OV2640_SENSOR_REG04, 1, &ov2640_reg); // 读取 0x04 的寄存器值
  186. // reg04,寄存器组4,寄存器地址为 0x04,该寄存器的第bit[6],用于设置水平是垂直翻转
  187. if (configstate == OV2640_Enable) {
  188. // 此处设置参考openmv的驱动
  189. // bit[4]具体的作用是什么手册没有说,如果垂直翻转之后,该位不置1的话,颜色会不对
  190. ov2640_reg |= 0x40 | 0x10; // bit[6]置1时,图像会垂直翻转
  191. } else // 取消翻转
  192. {
  193. ov2640_reg &= ~(0x40 | 0x10); // 将bit[6]和bit[4]都写0
  194. }
  195. return write_reg(bus, OV2640_SENSOR_REG04, ov2640_reg); // 写入寄存器
  196. }
  197. void ov2640_set_saturation(struct rt_i2c_bus_device *bus, rt_int8_t saturation)
  198. {
  199. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_DSP); // 选择 dsp寄存器组
  200. switch (saturation) {
  201. case 2:
  202. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  203. write_reg(bus, OV2640_DSP_BPDATA, 0x02);
  204. write_reg(bus, OV2640_DSP_BPADDR, 0x03);
  205. write_reg(bus, OV2640_DSP_BPDATA, 0x68);
  206. write_reg(bus, OV2640_DSP_BPDATA, 0x68);
  207. break;
  208. case 1:
  209. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  210. write_reg(bus, OV2640_DSP_BPDATA, 0x02);
  211. write_reg(bus, OV2640_DSP_BPADDR, 0x03);
  212. write_reg(bus, OV2640_DSP_BPDATA, 0x58);
  213. write_reg(bus, OV2640_DSP_BPDATA, 0x58);
  214. break;
  215. case 0:
  216. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  217. write_reg(bus, OV2640_DSP_BPDATA, 0x02);
  218. write_reg(bus, OV2640_DSP_BPADDR, 0x03);
  219. write_reg(bus, OV2640_DSP_BPDATA, 0x48);
  220. write_reg(bus, OV2640_DSP_BPDATA, 0x48);
  221. break;
  222. case -1:
  223. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  224. write_reg(bus, OV2640_DSP_BPDATA, 0x02);
  225. write_reg(bus, OV2640_DSP_BPADDR, 0x03);
  226. write_reg(bus, OV2640_DSP_BPDATA, 0x38);
  227. write_reg(bus, OV2640_DSP_BPDATA, 0x38);
  228. break;
  229. case -2:
  230. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  231. write_reg(bus, OV2640_DSP_BPDATA, 0x02);
  232. write_reg(bus, OV2640_DSP_BPADDR, 0x03);
  233. write_reg(bus, OV2640_DSP_BPDATA, 0x28);
  234. write_reg(bus, OV2640_DSP_BPDATA, 0x28);
  235. break;
  236. default:
  237. break;
  238. }
  239. }
  240. void ov2640_set_brightness(struct rt_i2c_bus_device *bus, rt_int8_t brightness)
  241. {
  242. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_DSP); // 选择 dsp寄存器组
  243. switch (brightness) {
  244. case 2:
  245. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  246. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  247. write_reg(bus, OV2640_DSP_BPADDR, 0x09);
  248. write_reg(bus, OV2640_DSP_BPDATA, 0x40);
  249. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  250. break;
  251. case 1:
  252. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  253. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  254. write_reg(bus, OV2640_DSP_BPADDR, 0x09);
  255. write_reg(bus, OV2640_DSP_BPDATA, 0x30);
  256. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  257. break;
  258. case 0:
  259. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  260. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  261. write_reg(bus, OV2640_DSP_BPADDR, 0x09);
  262. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  263. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  264. break;
  265. case -1:
  266. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  267. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  268. write_reg(bus, OV2640_DSP_BPADDR, 0x09);
  269. write_reg(bus, OV2640_DSP_BPDATA, 0x10);
  270. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  271. break;
  272. case -2:
  273. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  274. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  275. write_reg(bus, OV2640_DSP_BPADDR, 0x09);
  276. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  277. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  278. break;
  279. default:
  280. break;
  281. }
  282. }
  283. void ov2640_set_contrast(struct rt_i2c_bus_device *bus, rt_int8_t contrast)
  284. {
  285. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_DSP); // 选择 dsp寄存器组
  286. switch (contrast) {
  287. case 2:
  288. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  289. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  290. write_reg(bus, OV2640_DSP_BPADDR, 0x07);
  291. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  292. write_reg(bus, OV2640_DSP_BPADDR, 0x28);
  293. write_reg(bus, OV2640_DSP_BPDATA, 0x0c);
  294. write_reg(bus, OV2640_DSP_BPDATA, 0x06);
  295. break;
  296. case 1:
  297. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  298. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  299. write_reg(bus, OV2640_DSP_BPADDR, 0x07);
  300. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  301. write_reg(bus, OV2640_DSP_BPADDR, 0x24);
  302. write_reg(bus, OV2640_DSP_BPDATA, 0x16);
  303. write_reg(bus, OV2640_DSP_BPDATA, 0x06);
  304. break;
  305. case 0:
  306. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  307. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  308. write_reg(bus, OV2640_DSP_BPADDR, 0x07);
  309. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  310. write_reg(bus, OV2640_DSP_BPADDR, 0x20);
  311. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  312. write_reg(bus, OV2640_DSP_BPDATA, 0x06);
  313. break;
  314. case -1:
  315. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  316. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  317. write_reg(bus, OV2640_DSP_BPADDR, 0x07);
  318. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  319. write_reg(bus, OV2640_DSP_BPADDR, 0x1c);
  320. write_reg(bus, OV2640_DSP_BPDATA, 0x2a);
  321. write_reg(bus, OV2640_DSP_BPDATA, 0x06);
  322. break;
  323. case -2:
  324. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  325. write_reg(bus, OV2640_DSP_BPDATA, 0x04);
  326. write_reg(bus, OV2640_DSP_BPADDR, 0x07);
  327. write_reg(bus, OV2640_DSP_BPDATA, 0x20);
  328. write_reg(bus, OV2640_DSP_BPADDR, 0x18);
  329. write_reg(bus, OV2640_DSP_BPDATA, 0x34);
  330. write_reg(bus, OV2640_DSP_BPDATA, 0x06);
  331. break;
  332. default:
  333. break;
  334. }
  335. }
  336. void ov2640_set_effect(struct rt_i2c_bus_device *bus, rt_uint8_t effect_mode)
  337. {
  338. write_reg(bus, OV2640_SEL_Registers, OV2640_SEL_DSP); // 选择 dsp寄存器组
  339. switch (effect_mode) {
  340. case OV2640_Effect_Normal: // 正常模式
  341. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  342. write_reg(bus, OV2640_DSP_BPDATA, 0x00);
  343. write_reg(bus, OV2640_DSP_BPADDR, 0x05);
  344. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  345. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  346. break;
  347. case OV2640_Effect_Negative: // 负片模式,也就是颜色全部取反
  348. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  349. write_reg(bus, OV2640_DSP_BPDATA, 0x40);
  350. write_reg(bus, OV2640_DSP_BPADDR, 0x05);
  351. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  352. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  353. break;
  354. case OV2640_Effect_BW: // 黑白模式
  355. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  356. write_reg(bus, OV2640_DSP_BPDATA, 0x18);
  357. write_reg(bus, OV2640_DSP_BPADDR, 0x05);
  358. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  359. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  360. break;
  361. case OV2640_Effect_BW_Negative: // 黑白+负片模式
  362. write_reg(bus, OV2640_DSP_BPADDR, 0x00);
  363. write_reg(bus, OV2640_DSP_BPDATA, 0x58);
  364. write_reg(bus, OV2640_DSP_BPADDR, 0x05);
  365. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  366. write_reg(bus, OV2640_DSP_BPDATA, 0x80);
  367. break;
  368. default:
  369. break;
  370. }
  371. }
  372. int rt_hw_ov2640_init(void)
  373. {
  374. extern rt_err_t ov2640_dcmi_crop(uint16_t displey_xsize, uint16_t displey_ysize, uint16_t sensor_xsize, uint16_t sensor_ysize);
  375. static rt_uint16_t id = 0;
  376. rt_device_t dcmi_dev = RT_NULL;
  377. i2c_bus = rt_i2c_bus_device_find(I2C_NAME);
  378. if (i2c_bus == RT_NULL)
  379. {
  380. LOG_E("can't find %c deivce", I2C_NAME);
  381. return -RT_ERROR;
  382. }
  383. /* dcmi init */
  384. dcmi_dev = rt_device_find("dcmi");
  385. if (dcmi_dev == RT_NULL)
  386. {
  387. LOG_E("can't find dcmi device!");
  388. return -RT_ERROR;
  389. }
  390. rt_device_open(dcmi_dev, RT_DEVICE_FLAG_RDWR);
  391. ov2640_reset(i2c_bus);
  392. ov2640_read_id(i2c_bus, &id);
  393. ov2640_config(i2c_bus, OV2640_SVGA_Config); // 配置 SVGA模式 ------> 800*600, 最大帧率30帧
  394. // ov2640_config(i2c_bus, OV2640_UXGA_Config); // 配置 UXGA模式 ------> 1600*1200,最大帧率15帧
  395. ov2640_set_framesize(i2c_bus, OV2640_Width, OV2640_Height); // 设置OV2640输出的图像大小
  396. // 将OV2640输出图像裁剪成适应屏幕的大小
  397. struct stm32_dcmi_cropsize cropsize = {Display_Width, Display_Height, OV2640_Width, OV2640_Height};
  398. rt_device_control(dcmi_dev, DCMI_CTRL_CROP, &cropsize);
  399. ov2640_set_pixformat(i2c_bus, Pixformat_RGB565);
  400. // ov2640_set_pixformat(i2c_bus, Pixformat_JPEG);
  401. ov2640_set_saturation(i2c_bus, 0);
  402. ov2640_set_brightness(i2c_bus, 0);
  403. ov2640_set_contrast(i2c_bus, 0);
  404. ov2640_set_effect(i2c_bus, OV2640_Effect_Normal);
  405. return RT_EOK;
  406. }
  407. INIT_APP_EXPORT(rt_hw_ov2640_init);
  408. #ifdef DRV_DEBUG
  409. #ifdef FINSH_USING_MSH
  410. #ifdef BSP_USING_LCD_SPI
  411. #include "drv_lcd_spi.h"
  412. int camera_sample(int argc, char **argv)
  413. {
  414. rt_device_t dcmi_dev = RT_NULL;
  415. rt_uint8_t fps = 0;
  416. dcmi_dev = rt_device_find("dcmi");
  417. if (dcmi_dev == RT_NULL)
  418. {
  419. LOG_E("can't find dcmi device!");
  420. return -RT_ERROR;
  421. }
  422. struct stm32_dcmi* stm32_dcmi_dev = DCMI_DEVICE(dcmi_dev);
  423. // malloc dma memory
  424. struct rt_memheap* axi_sram = (struct rt_memheap*)rt_object_find("axi_sram", RT_Object_Class_MemHeap);
  425. void* buff_ptr = rt_memheap_alloc(axi_sram, OV2640_BufferSize);
  426. // 启动DMA连续传输
  427. struct stm32_dcmi_dma_transmitbuffer transmitbuffer = {(uint32_t)buff_ptr, OV2640_BufferSize};
  428. rt_device_control(dcmi_dev, DCMI_CTRL_TRANSMIT_CONTINUOUS, &transmitbuffer);
  429. while (1) {
  430. rt_sem_take(&stm32_dcmi_dev->cam_semaphore, RT_WAITING_FOREVER);
  431. // rt_device_control(dcmi_dev, DCMI_CTRL_SUSPEND, RT_NULL);
  432. // 将图像数据复制到屏幕
  433. lcd_copybuffer(0, 0, Display_Width, Display_Height, (uint16_t *)buff_ptr);
  434. // rt_device_control(dcmi_dev, DCMI_CTRL_RESUME, RT_NULL);
  435. rt_device_control(dcmi_dev, DCMI_CTRL_GET_FPS, &fps);
  436. LOG_D("fps: %d", fps);
  437. }
  438. rt_memheap_free(buff_ptr);
  439. }
  440. MSH_CMD_EXPORT(camera_sample, record picture to lcd);
  441. #endif /* BSP_USING_LCD_SPI */
  442. #endif /* FINSH_USING_MSH */
  443. #endif /* DRV_DEBUG */
  444. #endif