Skip to content

Commit 7e4c582

Browse files
author
Alain Volmat
committed
video: stm32-dcmi: implement frame interval handling
Implement the video API frame interval handling in order to control the framerate of capture. This allow to remove the capture-rate DT property as well. Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
1 parent b9a3eb3 commit 7e4c582

File tree

2 files changed

+128
-23
lines changed

2 files changed

+128
-23
lines changed

drivers/video/video_stm32_dcmi.c

Lines changed: 128 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct video_stm32_dcmi_data {
4141
const struct device *dev;
4242
DCMI_HandleTypeDef hdcmi;
4343
struct video_format fmt;
44+
int capture_rate;
4445
struct k_fifo fifo_in;
4546
struct k_fifo fifo_out;
4647
struct video_buffer *vbuf;
@@ -251,6 +252,12 @@ static int video_stm32_dcmi_get_fmt(const struct device *dev,
251252
return 0;
252253
}
253254

255+
#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \
256+
((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \
257+
(capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \
258+
(capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \
259+
DCMI_CR_ALL_FRAME)
260+
254261
static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable)
255262
{
256263
struct video_stm32_dcmi_data *data = dev->data;
@@ -282,6 +289,10 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable)
282289
return -ENOMEM;
283290
}
284291

292+
/* Set the frame control */
293+
data->hdcmi.Instance->CR &= ~(DCMI_CR_FCRC_0 | DCMI_CR_FCRC_1);
294+
data->hdcmi.Instance->CR |= STM32_DCMI_GET_CAPTURE_RATE(data->capture_rate);
295+
285296
err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
286297
(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);
287298
if (err != HAL_OK) {
@@ -351,13 +362,129 @@ static int video_stm32_dcmi_get_caps(const struct device *dev,
351362
return video_get_caps(config->sensor_dev, ep, caps);
352363
}
353364

365+
static int video_stm32_dcmi_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
366+
struct video_frmival_enum *fie)
367+
{
368+
const struct video_stm32_dcmi_config *config = dev->config;
369+
int ret;
370+
371+
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
372+
return -EINVAL;
373+
}
374+
375+
ret = video_stm32_dcmi_is_fmt_valid(fie->format->pixelformat, fie->format->pitch,
376+
fie->format->height);
377+
if (ret < 0) {
378+
return ret;
379+
}
380+
381+
ret = video_enum_frmival(config->sensor_dev, ep, fie);
382+
if (ret < 0) {
383+
return ret;
384+
}
385+
386+
/* Adapt the interval in order to report the frame drop capabilities */
387+
if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
388+
struct video_frmival discrete = fie->discrete;
389+
390+
fie->type = VIDEO_FRMIVAL_TYPE_STEPWISE;
391+
fie->stepwise.max = discrete;
392+
fie->stepwise.min.denominator = discrete.denominator;
393+
fie->stepwise.min.numerator = discrete.numerator * 4;
394+
fie->stepwise.step.denominator = discrete.denominator;
395+
fie->stepwise.step.numerator = discrete.numerator * 2;
396+
} else {
397+
fie->stepwise.min.numerator *= 4;
398+
fie->stepwise.step.numerator *= 2;
399+
}
400+
401+
return 0;
402+
}
403+
404+
#define STM32_DCMI_MAX_FRAME_DROP 4
405+
static int video_stm32_dcmi_set_frmival(const struct device *dev, enum video_endpoint_id ep,
406+
struct video_frmival *frmival)
407+
{
408+
const struct video_stm32_dcmi_config *config = dev->config;
409+
struct video_stm32_dcmi_data *data = dev->data;
410+
struct video_frmival_enum fie = {
411+
.format = &data->fmt,
412+
};
413+
struct video_frmival best_sensor_frmival;
414+
uint64_t best_diff_nsec = INT32_MAX;
415+
uint64_t diff_nsec = 0, a, b;
416+
int best_capture_rate = 1;
417+
418+
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
419+
return -EINVAL;
420+
}
421+
422+
/*
423+
* Try to figure out a frameinterval setting allow to reach as close as
424+
* possible to the request. At first without relying on DCMI frame control,
425+
* then enabling it
426+
*/
427+
for (int capture_rate = 1; capture_rate <= STM32_DCMI_MAX_FRAME_DROP; capture_rate *= 2) {
428+
/*
429+
* Take into consideration the drop done by the DCMI hence multiply
430+
* denominator by the rate introduced by the DCMI
431+
*/
432+
fie.discrete.numerator = frmival->numerator;
433+
fie.discrete.denominator = frmival->denominator * capture_rate;
434+
435+
a = video_frmival_nsec(&fie.discrete);
436+
video_closest_frmival(config->sensor_dev, ep, &fie);
437+
b = video_frmival_nsec(&fie.discrete);
438+
diff_nsec = a > b ? a - b : b - a;
439+
if (diff_nsec < best_diff_nsec) {
440+
best_diff_nsec = diff_nsec;
441+
best_sensor_frmival = fie.discrete;
442+
best_capture_rate = capture_rate;
443+
}
444+
if (diff_nsec == 0) {
445+
break;
446+
}
447+
}
448+
449+
/*
450+
* Give back the achieved frame interval achieved, ensuring to take into
451+
* consideration the DCMI frame control
452+
*/
453+
frmival->numerator = best_sensor_frmival.numerator * best_capture_rate;
454+
frmival->denominator = best_sensor_frmival.denominator;
455+
456+
data->capture_rate = best_capture_rate;
457+
458+
return video_set_frmival(config->sensor_dev, ep, &best_sensor_frmival);
459+
}
460+
461+
static int video_stm32_dcmi_get_frmival(const struct device *dev, enum video_endpoint_id ep,
462+
struct video_frmival *frmival)
463+
{
464+
const struct video_stm32_dcmi_config *config = dev->config;
465+
struct video_stm32_dcmi_data *data = dev->data;
466+
int ret;
467+
468+
ret = video_get_frmival(config->sensor_dev, ep, frmival);
469+
if (ret < 0) {
470+
return ret;
471+
}
472+
473+
frmival->numerator *= data->capture_rate;
474+
475+
return 0;
476+
}
477+
354478
static DEVICE_API(video, video_stm32_dcmi_driver_api) = {
355479
.set_format = video_stm32_dcmi_set_fmt,
356480
.get_format = video_stm32_dcmi_get_fmt,
357481
.set_stream = video_stm32_dcmi_set_stream,
358482
.enqueue = video_stm32_dcmi_enqueue,
359483
.dequeue = video_stm32_dcmi_dequeue,
360484
.get_caps = video_stm32_dcmi_get_caps,
485+
.enum_frmival = video_stm32_dcmi_enum_frmival,
486+
.set_frmival = video_stm32_dcmi_set_frmival,
487+
.get_frmival = video_stm32_dcmi_get_frmival,
361488
};
362489

363490
static void video_stm32_dcmi_irq_config_func(const struct device *dev)
@@ -389,12 +516,6 @@ static void video_stm32_dcmi_irq_config_func(const struct device *dev)
389516

390517
PINCTRL_DT_INST_DEFINE(0);
391518

392-
#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \
393-
((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \
394-
(capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \
395-
(capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \
396-
DCMI_CR_ALL_FRAME)
397-
398519
#define STM32_DCMI_GET_BUS_WIDTH(bus_width) \
399520
((bus_width) == 8 ? DCMI_EXTEND_DATA_8B : \
400521
(bus_width) == 10 ? DCMI_EXTEND_DATA_10B : \
@@ -424,9 +545,6 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = {
424545
.VSPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0),
425546
vsync_active, 0) ?
426547
DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW,
427-
.CaptureRate = STM32_DCMI_GET_CAPTURE_RATE(
428-
DT_PROP_OR(DT_DRV_INST(inst), capture_rate,
429-
1)),
430548
.ExtendedDataMode = STM32_DCMI_GET_BUS_WIDTH(
431549
DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0),
432550
bus_width, 8)),
@@ -482,6 +600,7 @@ static int video_stm32_dcmi_init(const struct device *dev)
482600
data->dev = dev;
483601
k_fifo_init(&data->fifo_in);
484602
k_fifo_init(&data->fifo_out);
603+
data->capture_rate = 1;
485604

486605
/* Run IRQ init */
487606
config->irq_config(dev);

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

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,6 @@ properties:
3535
interrupts:
3636
required: true
3737

38-
capture-rate:
39-
type: int
40-
enum:
41-
- 1
42-
- 2
43-
- 4
44-
default: 1
45-
description: |
46-
The DCMI can capture all frames or alternate frames. If it is not specified,
47-
the default is all frames.
48-
1 Capture all frames.
49-
2 Capture alternate frames.
50-
4 Capture one frame every 4 frames.
51-
5238
dmas:
5339
required: true
5440
description: |

0 commit comments

Comments
 (0)