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