Skip to content

Commit a27e1a2

Browse files
committed
video: stm32_dcmi: snapshot recover cleanup
Error recovery code done in callback for both modes. Timeout fixes/changes in snapshot. Two different timeouts. First is a timeout for the call to dequeue. Which can return before a snapshot completes. Additional calls to dequeue will continue to wait if necessary, for a frame to be received. A second timeout was added, which can be configured as parameter to DCMI. This handles cases where the snapshot start completes successfully, but does not return a frame in the prescribed time frame. It currently defaults to one second. Signed-off-by: Kurt Eckhardt <[email protected]>
1 parent dd4de94 commit a27e1a2

File tree

2 files changed

+87
-62
lines changed

2 files changed

+87
-62
lines changed

drivers/video/video_stm32_dcmi.c

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +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;
48+
uint32_t snapshot_start_time;
49+
bool snapshot_mode;
5050
};
5151

5252
struct video_stm32_dcmi_config {
@@ -56,15 +56,29 @@ struct video_stm32_dcmi_config {
5656
const struct device *sensor_dev;
5757
const struct stream dma;
5858
bool snapshot_mode;
59+
int snapshot_timeout;
5960
};
6061

6162
static void stm32_dcmi_process_dma_error(DCMI_HandleTypeDef *hdcmi)
6263
{
6364
struct video_stm32_dcmi_data *dev_data =
6465
CONTAINER_OF(hdcmi, struct video_stm32_dcmi_data, hdcmi);
6566

66-
dev_data->restart_dma = true;
67-
k_fifo_cancel_wait(&dev_data->fifo_out);
67+
LOG_WRN("Restart DMA after Error!");
68+
69+
/* Lets try to recover by stopping and restart */
70+
if (HAL_DCMI_Stop(&dev_data->hdcmi) != HAL_OK) {
71+
LOG_WRN("HAL_DCMI_Stop FAILED!");
72+
return;
73+
}
74+
75+
if (HAL_DCMI_Start_DMA(&dev_data->hdcmi,
76+
dev_data->snapshot_mode ? DCMI_MODE_SNAPSHOT : DCMI_MODE_CONTINUOUS,
77+
(uint32_t)dev_data->vbuf->buffer,
78+
dev_data->vbuf->size / 4) != HAL_OK) {
79+
LOG_WRN("Continuous: HAL_DCMI_Start_DMA FAILED!");
80+
return;
81+
}
6882
}
6983

7084
void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi)
@@ -85,6 +99,7 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
8599
dev_data->vbuf = NULL;
86100
vbuf->timestamp = k_uptime_get_32();
87101
k_fifo_put(&dev_data->fifo_out, vbuf);
102+
LOG_DBG("event SH put: %p", vbuf);
88103
return;
89104
}
90105

@@ -270,7 +285,7 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable,
270285
return 0;
271286
}
272287

273-
if (!config->snapshot_mode && (CONFIG_VIDEO_BUFFER_POOL_NUM_MAX != 1)) {
288+
if (!data->snapshot_mode && (CONFIG_VIDEO_BUFFER_POOL_NUM_MAX != 1)) {
274289
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
275290

276291
if (data->vbuf == NULL) {
@@ -302,7 +317,6 @@ static int video_stm32_dcmi_enqueue(const struct device *dev, struct video_buffe
302317
{
303318
struct video_stm32_dcmi_data *data = dev->data;
304319
const uint32_t buffer_size = data->fmt.pitch * data->fmt.height;
305-
306320
if (buffer_size > vbuf->size) {
307321
return -EINVAL;
308322
}
@@ -315,82 +329,88 @@ static int video_stm32_dcmi_enqueue(const struct device *dev, struct video_buffe
315329
return 0;
316330
}
317331

318-
static int video_stm32_restart_dma_after_error(struct video_stm32_dcmi_data *data)
332+
static int video_stm32_dcmi_snapshot(const struct device *dev, struct video_buffer **vbuf,
333+
k_timeout_t timeout)
319334
{
320-
LOG_DBG("Restart DMA after Error!");
321-
/* Lets try to recover by stopping and maybe restart */
322-
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
323-
LOG_WRN("HAL_DCMI_Stop FAILED!");
324-
}
335+
struct video_stm32_dcmi_data *data = dev->data;
336+
const struct video_stm32_dcmi_config *config = dev->config;
325337

326-
if (data->snapshot_mode) {
327-
if (data->vbuf != NULL) {
328-
k_fifo_put(&data->fifo_in, data->vbuf);
329-
data->vbuf = NULL;
338+
LOG_DBG("dequeue snapshot: %p %llu\n", data->vbuf, timeout.ticks);
339+
340+
/* See if we were already called and have an active buffer */
341+
if (data->vbuf == NULL) {
342+
/* check first to see if we already have a buffer returned */
343+
*vbuf = k_fifo_get(&data->fifo_out, K_NO_WAIT);
344+
if (*vbuf != NULL) {
345+
LOG_DBG("k_fifo_get returned: %p\n", *vbuf);
346+
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
347+
LOG_WRN("Snapshot: HAL_DCMI_Stop FAILED!");
348+
}
349+
return 0;
330350
}
331-
} else {
332-
/* error on last transfer try to restart it */
333-
if (HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
351+
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
352+
LOG_DBG("\tcamera buf: %p\n", data->vbuf);
353+
if (data->vbuf == NULL) {
354+
LOG_WRN("Snapshot: No Buffers available!");
355+
return -ENOMEM;
356+
}
357+
358+
if (HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_SNAPSHOT,
334359
(uint32_t)data->vbuf->buffer,
335360
data->vbuf->size / 4) != HAL_OK) {
336361
LOG_WRN("Snapshot: HAL_DCMI_Start_DMA FAILED!");
337362
return -EIO;
338363
}
364+
365+
/* remember when we started this request */
366+
data->snapshot_start_time = k_uptime_get_32();
339367
}
340-
data->restart_dma = false;
341-
return 0;
342-
}
343368

344-
static int video_stm32_dcmi_dequeue(const struct device *dev, struct video_buffer **vbuf,
345-
k_timeout_t timeout)
346-
{
347-
struct video_stm32_dcmi_data *data = dev->data;
348-
int err;
369+
*vbuf = k_fifo_get(&data->fifo_out, timeout);
370+
LOG_DBG("k_fifo_get returned: %p\n", *vbuf);
349371

350-
if (data->snapshot_mode) {
351-
/* See if we were already called and have an active buffer */
352-
if (data->vbuf == NULL) {
353-
data->vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
354-
if (data->vbuf == NULL) {
355-
LOG_WRN("Snapshot: No Buffers available!");
356-
return -ENOMEM;
372+
if (*vbuf == NULL) {
373+
uint32_t time_since_start_time =
374+
(uint32_t)(k_uptime_get_32() - data->snapshot_start_time);
375+
if (time_since_start_time > config->snapshot_timeout) {
376+
LOG_WRN("Snapshot: Timed out!");
377+
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
378+
LOG_WRN("Snapshot: HAL_DCMI_Stop FAILED!");
379+
}
380+
/* verify it did not come in during this procuessing */
381+
*vbuf = k_fifo_get(&data->fifo_out, K_NO_WAIT);
382+
if (*vbuf) {
383+
return 0;
357384
}
358385

359-
if (HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_SNAPSHOT,
360-
(uint32_t)data->vbuf->buffer,
361-
data->vbuf->size / 4) != HAL_OK) {
362-
LOG_WRN("Snapshot: HAL_DCMI_Start_DMA FAILED!");
363-
return -EIO;
386+
if (data->vbuf != NULL) {
387+
k_fifo_put(&data->fifo_in, data->vbuf);
388+
data->vbuf = NULL;
364389
}
365-
} else {
366-
LOG_DBG("Snapshot: restart after timeout");
367-
}
368-
} else {
369-
err = video_stm32_restart_dma_after_error(data);
370-
if (err < 0) {
371-
return err;
372390
}
373-
}
374-
375-
*vbuf = k_fifo_get(&data->fifo_out, timeout);
376391

377-
if (data->restart_dma) {
378-
err = video_stm32_restart_dma_after_error(data);
379-
if (err < 0) {
380-
return err;
381-
}
392+
return -EAGAIN;
382393
}
383394

384-
if (*vbuf == NULL) {
385-
return -EAGAIN;
395+
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
396+
LOG_WRN("Snapshot: HAL_DCMI_Stop FAILED!");
386397
}
398+
return 0;
399+
}
400+
401+
static int video_stm32_dcmi_dequeue(const struct device *dev, struct video_buffer **vbuf,
402+
k_timeout_t timeout)
403+
{
404+
struct video_stm32_dcmi_data *data = dev->data;
387405

388406
if (data->snapshot_mode) {
389-
if (HAL_DCMI_Stop(&data->hdcmi) != HAL_OK) {
390-
LOG_WRN("Snapshot: HAL_DCMI_Stop FAILED!");
391-
}
407+
return video_stm32_dcmi_snapshot(dev, vbuf, timeout);
392408
}
393-
return 0;
409+
410+
*vbuf = k_fifo_get(&data->fifo_out, timeout);
411+
LOG_DBG("k_fifo_get returned: %p\n", *vbuf);
412+
413+
return (*vbuf == NULL) ? -EAGAIN : 0;
394414
}
395415

396416
static int video_stm32_dcmi_get_caps(const struct device *dev, struct video_caps *caps)
@@ -616,6 +636,7 @@ static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = {
616636
.pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
617637
.sensor_dev = SOURCE_DEV(0),
618638
.snapshot_mode = DT_INST_PROP(0, snapshot_mode),
639+
.snapshot_timeout = DT_INST_PROP(0, snapshot_timeout),
619640
DCMI_DMA_CHANNEL(0, PERIPHERAL, MEMORY)
620641
};
621642

@@ -647,7 +668,6 @@ static int video_stm32_dcmi_init(const struct device *dev)
647668
}
648669

649670
/* See if we should initialize to only support snapshot mode or not */
650-
data->restart_dma = false;
651671
data->snapshot_mode = config->snapshot_mode;
652672
if (CONFIG_VIDEO_BUFFER_POOL_NUM_MAX == 1) {
653673
LOG_DBG("Only one buffer so snapshot mode only");

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ properties:
4848
4949
snapshot-mode:
5050
type: boolean
51-
description: set the driver into snapshot mode, default is off.
51+
description: Set DCMI to Snapshot mode, instead of the default Capture mode.
52+
53+
snapshot-timeout:
54+
type: int
55+
description: Set capture timeout in microseconds, default is 1000.
56+
default: 1000
5257

5358
child-binding:
5459
child-binding:

0 commit comments

Comments
 (0)