Skip to content

Commit 3d08ce6

Browse files
committed
video: stm32_dcmi: support for CROP/Snapshot
Added support to video_stm32_dcmi for the new set and get selection. These implementations simply forward the message to the underlying camera object if they support these messages. Also added support for a snapshot mode instead of always using continuous capture mode. Tried to make it semi-transparent when you desire it to be The stm32_dcmi code now also allows you to work with only one buffer. This will force it into snapshot mode. likewise if you call the video_set_stream and have not added any buffers yet, it will also set it into this mode. You can also specify to use snapshot mode, in the device tree, like: ``` &dcmi { snapshot-mode; }; ``` This commit also has some recovery from DMA errors in snapshot mode, in addition it appears to recover in many of the cases in continuous mode as well. At least it is a start to resolve some of the hangs. Updated: video_stm32_dcmi_get_caps. Signed-off-by: Kurt Eckhardt <[email protected]>
1 parent dece779 commit 3d08ce6

File tree

2 files changed

+143
-21
lines changed

2 files changed

+143
-21
lines changed

drivers/video/video_stm32_dcmi.c

Lines changed: 139 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424

2525
LOG_MODULE_REGISTER(video_stm32_dcmi, CONFIG_VIDEO_LOG_LEVEL);
2626

27-
#if CONFIG_VIDEO_BUFFER_POOL_NUM_MAX < 2
28-
#error "The minimum required number of buffers for video_stm32 is 2"
27+
#if CONFIG_VIDEO_BUFFER_POOL_NUM_MAX < 1
28+
#error "The minimum required number of buffers for video_stm32 is 1"
2929
#endif
3030

3131
typedef void (*irq_config_func_t)(const struct device *dev);
@@ -45,6 +45,8 @@ struct video_stm32_dcmi_data {
4545
struct k_fifo fifo_in;
4646
struct k_fifo fifo_out;
4747
struct video_buffer *vbuf;
48+
bool snapshot_mode : 1;
49+
bool restart_dma : 1;
4850
};
4951

5052
struct video_stm32_dcmi_config {
@@ -53,11 +55,22 @@ struct video_stm32_dcmi_config {
5355
const struct pinctrl_dev_config *pctrl;
5456
const struct device *sensor_dev;
5557
const struct stream dma;
58+
bool snapshot_mode;
5659
};
5760

61+
static void stm32_dcmi_process_dma_error(DCMI_HandleTypeDef *hdcmi)
62+
{
63+
struct video_stm32_dcmi_data *dev_data =
64+
CONTAINER_OF(hdcmi, struct video_stm32_dcmi_data, hdcmi);
65+
66+
dev_data->restart_dma = true;
67+
k_fifo_cancel_wait(&dev_data->fifo_out);
68+
}
69+
5870
void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi)
5971
{
60-
LOG_WRN("%s", __func__);
72+
LOG_WRN("%s %p", __func__, hdcmi);
73+
stm32_dcmi_process_dma_error(hdcmi);
6174
}
6275

6376
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
@@ -66,8 +79,17 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
6679
CONTAINER_OF(hdcmi, struct video_stm32_dcmi_data, hdcmi);
6780
struct video_buffer *vbuf;
6881

69-
HAL_DCMI_Suspend(hdcmi);
82+
if (dev_data->snapshot_mode) {
83+
/* we remove the buffer from the camera and add it to fifo_out */
84+
vbuf = dev_data->vbuf;
85+
dev_data->vbuf = NULL;
86+
vbuf->timestamp = k_uptime_get_32();
87+
k_fifo_put(&dev_data->fifo_out, vbuf);
88+
return;
89+
}
7090

91+
/* Not in snapshot_mode */
92+
HAL_DCMI_Suspend(hdcmi);
7193
vbuf = k_fifo_get(&dev_data->fifo_in, K_NO_WAIT);
7294

7395
if (vbuf == NULL) {
@@ -94,21 +116,18 @@ static void stm32_dcmi_isr(const struct device *dev)
94116
static void dcmi_dma_callback(const struct device *dev, void *arg, uint32_t channel, int status)
95117
{
96118
DMA_HandleTypeDef *hdma = arg;
119+
DCMI_HandleTypeDef *hdcmi = (DCMI_HandleTypeDef *)hdma->Parent;
97120

98121
ARG_UNUSED(dev);
99122

100123
if (status < 0) {
101124
LOG_ERR("DMA callback error with channel %d.", channel);
125+
stm32_dcmi_process_dma_error(hdcmi);
102126
}
103127

104128
HAL_DMA_IRQHandler(hdma);
105129
}
106130

107-
void HAL_DMA_ErrorCallback(DMA_HandleTypeDef *hdma)
108-
{
109-
LOG_WRN("%s", __func__);
110-
}
111-
112131
static int stm32_dma_init(const struct device *dev)
113132
{
114133
struct video_stm32_dcmi_data *data = dev->data;
@@ -259,22 +278,29 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable,
259278
return 0;
260279
}
261280

262-
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
281+
if (!config->snapshot_mode && (CONFIG_VIDEO_BUFFER_POOL_NUM_MAX != 1)) {
282+
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
263283

264-
if (data->vbuf == NULL) {
265-
LOG_ERR("Failed to dequeue a DCMI buffer.");
266-
return -ENOMEM;
284+
if (data->vbuf == NULL) {
285+
data->snapshot_mode = true;
286+
LOG_WRN("No buffers, assume snapshot mode.");
287+
}
267288
}
268289

269290
/* Set the frame control */
270291
data->hdcmi.Instance->CR &= ~(DCMI_CR_FCRC_0 | DCMI_CR_FCRC_1);
271292
data->hdcmi.Instance->CR |= STM32_DCMI_GET_CAPTURE_RATE(data->capture_rate);
272293

273-
err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
274-
(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);
275-
if (err != HAL_OK) {
276-
LOG_ERR("Failed to start DCMI DMA");
277-
return -EIO;
294+
/* don't start the DCMI DMA if we are in Snapshot mode */
295+
if (!data->snapshot_mode) {
296+
err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
297+
(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);
298+
if (err != HAL_OK) {
299+
LOG_ERR("Failed to start DCMI DMA");
300+
return -EIO;
301+
}
302+
} else {
303+
LOG_DBG("Snapshot mode active");
278304
}
279305

280306
return video_stream_start(config->sensor_dev, type);
@@ -297,28 +323,96 @@ static int video_stm32_dcmi_enqueue(const struct device *dev, struct video_buffe
297323
return 0;
298324
}
299325

326+
static int video_stm32_restart_dma_after_error(struct video_stm32_dcmi_data *data) {
327+
LOG_DBG("Restart DMA after Error!");
328+
/* Lets try to recover by stopping and maybe restart */
329+
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
330+
LOG_WRN("HAL_DCMI_Stop FAILED!");
331+
}
332+
333+
if (data->snapshot_mode) {
334+
if (data->vbuf != NULL) {
335+
k_fifo_put(&data->fifo_in, data->vbuf);
336+
data->vbuf = NULL;
337+
}
338+
} else {
339+
/* error on last transfer try to restart it */
340+
if (HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
341+
(uint32_t)data->vbuf->buffer,
342+
data->vbuf->size / 4) != HAL_OK) {
343+
LOG_WRN("Snapshot: HAL_DCMI_Start_DMA FAILED!");
344+
return -EIO;
345+
}
346+
}
347+
data->restart_dma = false;
348+
return 0;
349+
}
350+
300351
static int video_stm32_dcmi_dequeue(const struct device *dev, struct video_buffer **vbuf,
301352
k_timeout_t timeout)
302353
{
303354
struct video_stm32_dcmi_data *data = dev->data;
355+
int err;
356+
357+
if (data->snapshot_mode) {
358+
/* See if we were already called and have an active buffer */
359+
if (data->vbuf == NULL) {
360+
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
361+
if (data->vbuf == NULL) {
362+
LOG_WRN("Snapshot: No Buffers available!");
363+
return -ENOMEM;
364+
}
365+
366+
if (HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_SNAPSHOT,
367+
(uint32_t)data->vbuf->buffer,
368+
data->vbuf->size / 4) != HAL_OK) {
369+
LOG_WRN("Snapshot: HAL_DCMI_Start_DMA FAILED!");
370+
return -EIO;
371+
}
372+
} else {
373+
LOG_DBG("Snapshot: restart after timeout");
374+
}
375+
} else {
376+
err = video_stm32_restart_dma_after_error(data);
377+
if (err < 0) {
378+
return err;
379+
}
380+
}
304381

305382
*vbuf = k_fifo_get(&data->fifo_out, timeout);
383+
384+
if (data->restart_dma) {
385+
err = video_stm32_restart_dma_after_error(data);
386+
if (err < 0) {
387+
return err;
388+
}
389+
}
390+
306391
if (*vbuf == NULL) {
307392
return -EAGAIN;
308393
}
309394

395+
if (data->snapshot_mode) {
396+
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
397+
LOG_WRN("Snapshot: HAL_DCMI_Stop FAILED!");
398+
}
399+
}
310400
return 0;
311401
}
312402

313403
static int video_stm32_dcmi_get_caps(const struct device *dev, struct video_caps *caps)
314404
{
315405
const struct video_stm32_dcmi_config *config = dev->config;
406+
int ret;
407+
408+
ret = video_get_caps(config->sensor_dev, caps);
316409

317410
/* DCMI produces full frames */
318-
caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT;
411+
caps->min_vbuf_count = config->snapshot_mode ? 1 : 2;
412+
caps->min_line_count = LINE_COUNT_HEIGHT;
413+
caps->max_line_count = LINE_COUNT_HEIGHT;
319414

320-
/* Forward the message to the sensor device */
321-
return video_get_caps(config->sensor_dev, caps);
415+
return ret;
322416
}
323417

324418
static int video_stm32_dcmi_enum_frmival(const struct device *dev, struct video_frmival_enum *fie)
@@ -417,6 +511,20 @@ static int video_stm32_dcmi_get_frmival(const struct device *dev, struct video_f
417511
return 0;
418512
}
419513

514+
static int video_stm32_dcmi_set_selection(const struct device *dev, struct video_selection *sel)
515+
{
516+
const struct video_stm32_dcmi_config *config = dev->config;
517+
518+
return video_set_selection(config->sensor_dev, sel);
519+
}
520+
521+
static int video_stm32_dcmi_get_selection(const struct device *dev, struct video_selection *sel)
522+
{
523+
const struct video_stm32_dcmi_config *config = dev->config;
524+
525+
return video_get_selection(config->sensor_dev, sel);
526+
}
527+
420528
static DEVICE_API(video, video_stm32_dcmi_driver_api) = {
421529
.set_format = video_stm32_dcmi_set_fmt,
422530
.get_format = video_stm32_dcmi_get_fmt,
@@ -427,6 +535,8 @@ static DEVICE_API(video, video_stm32_dcmi_driver_api) = {
427535
.enum_frmival = video_stm32_dcmi_enum_frmival,
428536
.set_frmival = video_stm32_dcmi_set_frmival,
429537
.get_frmival = video_stm32_dcmi_get_frmival,
538+
.set_selection = video_stm32_dcmi_set_selection,
539+
.get_selection = video_stm32_dcmi_get_selection,
430540
};
431541

432542
static void video_stm32_dcmi_irq_config_func(const struct device *dev)
@@ -509,6 +619,7 @@ static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = {
509619
.irq_config = video_stm32_dcmi_irq_config_func,
510620
.pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
511621
.sensor_dev = SOURCE_DEV(0),
622+
.snapshot_mode = DT_INST_PROP(0, snapshot_mode),
512623
DCMI_DMA_CHANNEL(0, PERIPHERAL, MEMORY)
513624
};
514625

@@ -539,6 +650,13 @@ static int video_stm32_dcmi_init(const struct device *dev)
539650
return err;
540651
}
541652

653+
/* See if we should initialize to only support snapshot mode or not */
654+
data->restart_dma = false;
655+
data->snapshot_mode = config->snapshot_mode;
656+
if (CONFIG_VIDEO_BUFFER_POOL_NUM_MAX == 1) {
657+
LOG_DBG("Only one buffer so snapshot mode only");
658+
data->snapshot_mode = true;
659+
}
542660
data->dev = dev;
543661
k_fifo_init(&data->fifo_in);
544662
k_fifo_init(&data->fifo_out);

dts/bindings/video/st,stm32-dcmi.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ properties:
4646
STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS |
4747
STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>;
4848
49+
snapshot-mode:
50+
type: boolean
51+
description: set the driver into snapshot mode, default is off.
52+
4953
child-binding:
5054
child-binding:
5155
include: video-interfaces.yaml

0 commit comments

Comments
 (0)