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>
This commit is contained in:
parent
df93e20414
commit
c1e7bdaa75
2 changed files with 128 additions and 23 deletions
|
@ -41,6 +41,7 @@ struct video_stm32_dcmi_data {
|
|||
const struct device *dev;
|
||||
DCMI_HandleTypeDef hdcmi;
|
||||
struct video_format fmt;
|
||||
int capture_rate;
|
||||
struct k_fifo fifo_in;
|
||||
struct k_fifo fifo_out;
|
||||
struct video_buffer *vbuf;
|
||||
|
@ -251,6 +252,12 @@ static int video_stm32_dcmi_get_fmt(const struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \
|
||||
((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \
|
||||
(capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \
|
||||
(capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \
|
||||
DCMI_CR_ALL_FRAME)
|
||||
|
||||
static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable)
|
||||
{
|
||||
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)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the frame control */
|
||||
data->hdcmi.Instance->CR &= ~(DCMI_CR_FCRC_0 | DCMI_CR_FCRC_1);
|
||||
data->hdcmi.Instance->CR |= STM32_DCMI_GET_CAPTURE_RATE(data->capture_rate);
|
||||
|
||||
err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
|
||||
(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);
|
||||
if (err != HAL_OK) {
|
||||
|
@ -351,6 +362,119 @@ static int video_stm32_dcmi_get_caps(const struct device *dev,
|
|||
return video_get_caps(config->sensor_dev, ep, caps);
|
||||
}
|
||||
|
||||
static int video_stm32_dcmi_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_frmival_enum *fie)
|
||||
{
|
||||
const struct video_stm32_dcmi_config *config = dev->config;
|
||||
int ret;
|
||||
|
||||
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = video_stm32_dcmi_is_fmt_valid(fie->format->pixelformat, fie->format->pitch,
|
||||
fie->format->height);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = video_enum_frmival(config->sensor_dev, ep, fie);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Adapt the interval in order to report the frame drop capabilities */
|
||||
if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
|
||||
struct video_frmival discrete = fie->discrete;
|
||||
|
||||
fie->type = VIDEO_FRMIVAL_TYPE_STEPWISE;
|
||||
fie->stepwise.max = discrete;
|
||||
fie->stepwise.min.denominator = discrete.denominator;
|
||||
fie->stepwise.min.numerator = discrete.numerator * 4;
|
||||
fie->stepwise.step.denominator = discrete.denominator;
|
||||
fie->stepwise.step.numerator = discrete.numerator * 2;
|
||||
} else {
|
||||
fie->stepwise.min.numerator *= 4;
|
||||
fie->stepwise.step.numerator *= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STM32_DCMI_MAX_FRAME_DROP 4
|
||||
static int video_stm32_dcmi_set_frmival(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_frmival *frmival)
|
||||
{
|
||||
const struct video_stm32_dcmi_config *config = dev->config;
|
||||
struct video_stm32_dcmi_data *data = dev->data;
|
||||
struct video_frmival_enum fie = {
|
||||
.format = &data->fmt,
|
||||
};
|
||||
struct video_frmival best_sensor_frmival;
|
||||
uint64_t best_diff_nsec = INT32_MAX;
|
||||
uint64_t diff_nsec = 0, a, b;
|
||||
int best_capture_rate = 1;
|
||||
|
||||
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to figure out a frameinterval setting allow to reach as close as
|
||||
* possible to the request. At first without relying on DCMI frame control,
|
||||
* then enabling it
|
||||
*/
|
||||
for (int capture_rate = 1; capture_rate <= STM32_DCMI_MAX_FRAME_DROP; capture_rate *= 2) {
|
||||
/*
|
||||
* Take into consideration the drop done by the DCMI hence multiply
|
||||
* denominator by the rate introduced by the DCMI
|
||||
*/
|
||||
fie.discrete.numerator = frmival->numerator;
|
||||
fie.discrete.denominator = frmival->denominator * capture_rate;
|
||||
|
||||
a = video_frmival_nsec(&fie.discrete);
|
||||
video_closest_frmival(config->sensor_dev, ep, &fie);
|
||||
b = video_frmival_nsec(&fie.discrete);
|
||||
diff_nsec = a > b ? a - b : b - a;
|
||||
if (diff_nsec < best_diff_nsec) {
|
||||
best_diff_nsec = diff_nsec;
|
||||
best_sensor_frmival = fie.discrete;
|
||||
best_capture_rate = capture_rate;
|
||||
}
|
||||
if (diff_nsec == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Give back the achieved frame interval achieved, ensuring to take into
|
||||
* consideration the DCMI frame control
|
||||
*/
|
||||
frmival->numerator = best_sensor_frmival.numerator * best_capture_rate;
|
||||
frmival->denominator = best_sensor_frmival.denominator;
|
||||
|
||||
data->capture_rate = best_capture_rate;
|
||||
|
||||
return video_set_frmival(config->sensor_dev, ep, &best_sensor_frmival);
|
||||
}
|
||||
|
||||
static int video_stm32_dcmi_get_frmival(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_frmival *frmival)
|
||||
{
|
||||
const struct video_stm32_dcmi_config *config = dev->config;
|
||||
struct video_stm32_dcmi_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
ret = video_get_frmival(config->sensor_dev, ep, frmival);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
frmival->numerator *= data->capture_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_API(video, video_stm32_dcmi_driver_api) = {
|
||||
.set_format = video_stm32_dcmi_set_fmt,
|
||||
.get_format = video_stm32_dcmi_get_fmt,
|
||||
|
@ -358,6 +482,9 @@ static DEVICE_API(video, video_stm32_dcmi_driver_api) = {
|
|||
.enqueue = video_stm32_dcmi_enqueue,
|
||||
.dequeue = video_stm32_dcmi_dequeue,
|
||||
.get_caps = video_stm32_dcmi_get_caps,
|
||||
.enum_frmival = video_stm32_dcmi_enum_frmival,
|
||||
.set_frmival = video_stm32_dcmi_set_frmival,
|
||||
.get_frmival = video_stm32_dcmi_get_frmival,
|
||||
};
|
||||
|
||||
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)
|
|||
|
||||
PINCTRL_DT_INST_DEFINE(0);
|
||||
|
||||
#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \
|
||||
((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \
|
||||
(capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \
|
||||
(capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \
|
||||
DCMI_CR_ALL_FRAME)
|
||||
|
||||
#define STM32_DCMI_GET_BUS_WIDTH(bus_width) \
|
||||
((bus_width) == 8 ? DCMI_EXTEND_DATA_8B : \
|
||||
(bus_width) == 10 ? DCMI_EXTEND_DATA_10B : \
|
||||
|
@ -424,9 +545,6 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = {
|
|||
.VSPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0),
|
||||
vsync_active, 0) ?
|
||||
DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW,
|
||||
.CaptureRate = STM32_DCMI_GET_CAPTURE_RATE(
|
||||
DT_PROP_OR(DT_DRV_INST(inst), capture_rate,
|
||||
1)),
|
||||
.ExtendedDataMode = STM32_DCMI_GET_BUS_WIDTH(
|
||||
DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0),
|
||||
bus_width, 8)),
|
||||
|
@ -482,6 +600,7 @@ static int video_stm32_dcmi_init(const struct device *dev)
|
|||
data->dev = dev;
|
||||
k_fifo_init(&data->fifo_in);
|
||||
k_fifo_init(&data->fifo_out);
|
||||
data->capture_rate = 1;
|
||||
|
||||
/* Run IRQ init */
|
||||
config->irq_config(dev);
|
||||
|
|
|
@ -35,20 +35,6 @@ properties:
|
|||
interrupts:
|
||||
required: true
|
||||
|
||||
capture-rate:
|
||||
type: int
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
default: 1
|
||||
description: |
|
||||
The DCMI can capture all frames or alternate frames. If it is not specified,
|
||||
the default is all frames.
|
||||
1 Capture all frames.
|
||||
2 Capture alternate frames.
|
||||
4 Capture one frame every 4 frames.
|
||||
|
||||
dmas:
|
||||
required: true
|
||||
description: |
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue