diff options
author | Seongyong Park <euphoriccatface@gmail.com> | 2021-06-08 17:24:50 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2021-09-30 10:07:57 +0200 |
commit | 439b87fceb23e7d9c963171ffb2e73144f794cc2 (patch) | |
tree | 60167c36086597b52473271561fded67b02961be /drivers/media/i2c/video-i2c.c | |
parent | media: staging: media: atomisp: code formatting changes atomisp_csi2.c (diff) | |
download | linux-439b87fceb23e7d9c963171ffb2e73144f794cc2.tar.xz linux-439b87fceb23e7d9c963171ffb2e73144f794cc2.zip |
media: video-i2c: more precise intervals between frames
MLX90640 should ideally be working without a frame skip.
In short, if a frame is skipped, then half of a frame loses correction
information, having no way to retrieve its original compensation.
This patch improves the timing in three ways:
1) Replaced schedule_timeout_interruptible() to usleep_range()
The former "only ensures that it will sleep for at least
schedule_delay (if not interrupted)", as pointed out by mchehab.
As a result, the frame rate could lag behind than the actual capability
of the hardware
(Raspberry Pi would show a few Hz slower than set value)
2) Calculation based on us, not jiffies
Jiffies usually has resolution of 100Hz, and possibly even cruder.
MLX90640 can go up to 64Hz frame rate, which does not make sense to
calculate the interval with aforementioned resolution.
3) Interval calculation based on the last frame's end time
Using the start time of the current frame will probably make tiny bit
of drift every time. This made more sense when I didn't realize 1),
but it still makes sense without adding virtually any complexity,
so this stays in.
Signed-off-by: Seongyong Park <euphoriccatface@gmail.com>
Acked-by: Matt Ranostay <matt.ranostay@konsulko.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/i2c/video-i2c.c')
-rw-r--r-- | drivers/media/i2c/video-i2c.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index de12f38f347c..cb660b4bfd4b 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -441,14 +441,15 @@ static void buffer_queue(struct vb2_buffer *vb) static int video_i2c_thread_vid_cap(void *priv) { struct video_i2c_data *data = priv; - unsigned int delay = mult_frac(HZ, data->frame_interval.numerator, - data->frame_interval.denominator); + u32 delay = mult_frac(1000000UL, data->frame_interval.numerator, + data->frame_interval.denominator); + s64 end_us = ktime_to_us(ktime_get()); set_freezable(); do { - unsigned long start_jiffies = jiffies; struct video_i2c_buffer *vid_cap_buf = NULL; + s64 current_us; int schedule_delay; try_to_freeze(); @@ -475,12 +476,14 @@ static int video_i2c_thread_vid_cap(void *priv) VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); } - schedule_delay = delay - (jiffies - start_jiffies); - - if (time_after(jiffies, start_jiffies + delay)) - schedule_delay = delay; - - schedule_timeout_interruptible(schedule_delay); + end_us += delay; + current_us = ktime_to_us(ktime_get()); + if (current_us < end_us) { + schedule_delay = end_us - current_us; + usleep_range(schedule_delay * 3 / 4, schedule_delay); + } else { + end_us = current_us; + } } while (!kthread_should_stop()); return 0; |