* [PATCH V2 0/2] media: video-i2c: additional support for Melexis MLX90640 @ 2021-06-05 11:54 Seongyong Park 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 2021-06-05 11:54 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 0 siblings, 2 replies; 16+ messages in thread From: Seongyong Park @ 2021-06-05 11:54 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park Previous attempt at re-submitting the patch(set) seems to have failed, due to a mishap at threading. Here is another attempt. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time @ 2021-05-16 11:09 ` Seongyong Park 2021-05-16 11:09 ` [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park ` (3 more replies) 0 siblings, 4 replies; 16+ messages in thread From: Seongyong Park @ 2021-05-16 11:09 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park Current implementation calculates frame delay based on the time of start of the loop. This inevitably causes the loop delay to be slightly longer than the actual measurement period, thus skipping a frame every now and then. However, MLX90640 should ideally be working without a frame skip. Each measurement step updates half of the pixels in the frame (every other pixel in default "chess mode", and every other row in "interleave mode"), while additional coefficient data (25th & 26th row) updates every step. The compensational coefficient data only corresponds with the pixels updated in the same step. In short, if a frame is skipped, then half of a frame loses correction information and becomes garbage data. Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> --- drivers/media/i2c/video-i2c.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 0465832a4..2ccb08335 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -445,14 +445,16 @@ 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); + unsigned long end_jiffies = jiffies; set_freezable(); do { - unsigned long start_jiffies = jiffies; struct video_i2c_buffer *vid_cap_buf = NULL; int schedule_delay; + end_jiffies += delay; + try_to_freeze(); spin_lock(&data->slock); @@ -477,10 +479,9 @@ 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_delay = end_jiffies - jiffies; + while (schedule_delay <= 0) + schedule_delay += delay; schedule_timeout_interruptible(schedule_delay); } while (!kthread_should_stop()); -- 2.31.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park @ 2021-05-16 11:09 ` Seongyong Park 2021-05-16 20:48 ` Matt Ranostay 2021-05-16 20:13 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Matt Ranostay ` (2 subsequent siblings) 3 siblings, 1 reply; 16+ messages in thread From: Seongyong Park @ 2021-05-16 11:09 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park On MLX90640, Each measurement step updates half of the pixels in the frame (every other pixel in default "chess mode", and every other row in "interleave mode"), while additional coefficient data (25th & 26th row) updates every step. The compensational coefficient data only corresponds with the pixels updated in the same step. Only way to know which "subpage" was updated on the last step is to read "status register" on address 0x8000. Without this data, compensation calculation may be able to detect which sets of pixels have been updated, but it will have to make assumptions when frame skip happens, and there is no way to do it correctly when the host simply cannot keep up with refresh rate. Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> --- drivers/media/i2c/video-i2c.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 2ccb08335..ca3a1c504 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -74,7 +74,7 @@ static const struct v4l2_fmtdesc mlx90640_format = { static const struct v4l2_frmsize_discrete mlx90640_size = { .width = 32, - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ + .height = 27, /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ }; static const struct regmap_config amg88xx_regmap_config = { @@ -168,8 +168,11 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) static int mlx90640_xfer(struct video_i2c_data *data, char *buf) { - return regmap_bulk_read(data->regmap, 0x400, buf, - data->chip->buffer_size); + int ret = regmap_bulk_read(data->regmap, 0x400, buf, + data->chip->buffer_size - 64); + if (ret) return ret; + return regmap_bulk_read(data->regmap, 0x8000, buf + 1664, + 64); } static int amg88xx_setup(struct video_i2c_data *data) @@ -375,7 +378,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { .format = &mlx90640_format, .frame_intervals = mlx90640_frame_intervals, .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), - .buffer_size = 1664, + .buffer_size = 1728, .bpp = 16, .regmap_config = &mlx90640_regmap_config, .nvmem_config = &mlx90640_nvram_config, -- 2.31.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-16 11:09 ` [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park @ 2021-05-16 20:48 ` Matt Ranostay 2021-05-17 1:39 ` Seongyong Park 0 siblings, 1 reply; 16+ messages in thread From: Matt Ranostay @ 2021-05-16 20:48 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Mauro Carvalho Chehab On Sun, May 16, 2021 at 4:09 AM Seongyong Park <euphoriccatface@gmail.com> wrote: > > On MLX90640, Each measurement step updates half of the pixels in the frame > (every other pixel in default "chess mode", and every other row > in "interleave mode"), while additional coefficient data (25th & 26th row) > updates every step. The compensational coefficient data only corresponds > with the pixels updated in the same step. > > Only way to know which "subpage" was updated on the last step is to read > "status register" on address 0x8000. Without this data, > compensation calculation may be able to detect which sets of pixels have > been updated, but it will have to make assumptions when frame skip happens, > and there is no way to do it correctly when the host simply cannot > keep up with refresh rate. > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > --- > drivers/media/i2c/video-i2c.c | 11 +++++++---- > 1 file changed, 7 insertions(+), 4 deletions(-) > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > index 2ccb08335..ca3a1c504 100644 > --- a/drivers/media/i2c/video-i2c.c > +++ b/drivers/media/i2c/video-i2c.c > @@ -74,7 +74,7 @@ static const struct v4l2_fmtdesc mlx90640_format = { > > static const struct v4l2_frmsize_discrete mlx90640_size = { > .width = 32, > - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ > + .height = 27, /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ > }; > > static const struct regmap_config amg88xx_regmap_config = { > @@ -168,8 +168,11 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) > > static int mlx90640_xfer(struct video_i2c_data *data, char *buf) > { > - return regmap_bulk_read(data->regmap, 0x400, buf, > - data->chip->buffer_size); > + int ret = regmap_bulk_read(data->regmap, 0x400, buf, > + data->chip->buffer_size - 64); > + if (ret) return ret; > + return regmap_bulk_read(data->regmap, 0x8000, buf + 1664, > + 64); Rather than "buf + 1664" it would be more portable and clear if you use "buf + (data->chip->buffer_size - 64)" Also isn't the 1 line of registers only 32-bytes not 64-bytes? - Matt > } > > static int amg88xx_setup(struct video_i2c_data *data) > @@ -375,7 +378,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { > .format = &mlx90640_format, > .frame_intervals = mlx90640_frame_intervals, > .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), > - .buffer_size = 1664, > + .buffer_size = 1728, > .bpp = 16, > .regmap_config = &mlx90640_regmap_config, > .nvmem_config = &mlx90640_nvram_config, > -- > 2.31.1 > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-16 20:48 ` Matt Ranostay @ 2021-05-17 1:39 ` Seongyong Park 2021-05-17 23:40 ` Matt Ranostay 0 siblings, 1 reply; 16+ messages in thread From: Seongyong Park @ 2021-05-17 1:39 UTC (permalink / raw) To: Matt Ranostay; +Cc: linux-media, Mauro Carvalho Chehab 2021년 5월 17일 (월) 오전 5:49, Matt Ranostay <matt.ranostay@konsulko.com>님이 작성: > > On Sun, May 16, 2021 at 4:09 AM Seongyong Park > <euphoriccatface@gmail.com> wrote: > > > > On MLX90640, Each measurement step updates half of the pixels in the frame > > (every other pixel in default "chess mode", and every other row > > in "interleave mode"), while additional coefficient data (25th & 26th row) > > updates every step. The compensational coefficient data only corresponds > > with the pixels updated in the same step. > > > > Only way to know which "subpage" was updated on the last step is to read > > "status register" on address 0x8000. Without this data, > > compensation calculation may be able to detect which sets of pixels have > > been updated, but it will have to make assumptions when frame skip happens, > > and there is no way to do it correctly when the host simply cannot > > keep up with refresh rate. > > > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > > --- > > drivers/media/i2c/video-i2c.c | 11 +++++++---- > > 1 file changed, 7 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > > index 2ccb08335..ca3a1c504 100644 > > --- a/drivers/media/i2c/video-i2c.c > > +++ b/drivers/media/i2c/video-i2c.c > > @@ -74,7 +74,7 @@ static const struct v4l2_fmtdesc mlx90640_format = { > > > > static const struct v4l2_frmsize_discrete mlx90640_size = { > > .width = 32, > > - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ > > + .height = 27, /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ > > }; > > > > static const struct regmap_config amg88xx_regmap_config = { > > @@ -168,8 +168,11 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) > > > > static int mlx90640_xfer(struct video_i2c_data *data, char *buf) > > { > > - return regmap_bulk_read(data->regmap, 0x400, buf, > > - data->chip->buffer_size); > > + int ret = regmap_bulk_read(data->regmap, 0x400, buf, > > + data->chip->buffer_size - 64); > > + if (ret) return ret; > > + return regmap_bulk_read(data->regmap, 0x8000, buf + 1664, > > + 64); > > Rather than "buf + 1664" it would be more portable and clear if you > use "buf + (data->chip->buffer_size - 64)" Okay, I'll send another patch later to change it. > Also isn't the 1 line of registers only 32-bytes not 64-bytes? In terms of the V4L2 frame, a row is 64-bytes because width is 32 and each pixel is 16-bit. This was the main reason to decide the appendage to be 64-bytes. For MLX90640, the address 0x8010 is mentioned in the datasheet, and actual output appears that up to 0x8013 is valid For reference, an output from my sensor shows: 0x8000: 0900 a200 9f69 0000 6120 0500 2003 e003 2817 4f8e 8701 8d04 0000 8119 0000 0000 0x8010: 33be 8000 4d02 0000 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff - Seongyong > > - Matt > > > } > > > > static int amg88xx_setup(struct video_i2c_data *data) > > @@ -375,7 +378,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { > > .format = &mlx90640_format, > > .frame_intervals = mlx90640_frame_intervals, > > .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), > > - .buffer_size = 1664, > > + .buffer_size = 1728, > > .bpp = 16, > > .regmap_config = &mlx90640_regmap_config, > > .nvmem_config = &mlx90640_nvram_config, > > -- > > 2.31.1 > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-17 1:39 ` Seongyong Park @ 2021-05-17 23:40 ` Matt Ranostay 0 siblings, 0 replies; 16+ messages in thread From: Matt Ranostay @ 2021-05-17 23:40 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Mauro Carvalho Chehab On Sun, May 16, 2021 at 6:40 PM Seongyong Park <euphoriccatface@gmail.com> wrote: > > 2021년 5월 17일 (월) 오전 5:49, Matt Ranostay <matt.ranostay@konsulko.com>님이 작성: > > > > On Sun, May 16, 2021 at 4:09 AM Seongyong Park > > <euphoriccatface@gmail.com> wrote: > > > > > > On MLX90640, Each measurement step updates half of the pixels in the frame > > > (every other pixel in default "chess mode", and every other row > > > in "interleave mode"), while additional coefficient data (25th & 26th row) > > > updates every step. The compensational coefficient data only corresponds > > > with the pixels updated in the same step. > > > > > > Only way to know which "subpage" was updated on the last step is to read > > > "status register" on address 0x8000. Without this data, > > > compensation calculation may be able to detect which sets of pixels have > > > been updated, but it will have to make assumptions when frame skip happens, > > > and there is no way to do it correctly when the host simply cannot > > > keep up with refresh rate. > > > > > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > > > --- > > > drivers/media/i2c/video-i2c.c | 11 +++++++---- > > > 1 file changed, 7 insertions(+), 4 deletions(-) > > > > > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > > > index 2ccb08335..ca3a1c504 100644 > > > --- a/drivers/media/i2c/video-i2c.c > > > +++ b/drivers/media/i2c/video-i2c.c > > > @@ -74,7 +74,7 @@ static const struct v4l2_fmtdesc mlx90640_format = { > > > > > > static const struct v4l2_frmsize_discrete mlx90640_size = { > > > .width = 32, > > > - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ > > > + .height = 27, /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ > > > }; > > > > > > static const struct regmap_config amg88xx_regmap_config = { > > > @@ -168,8 +168,11 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) > > > > > > static int mlx90640_xfer(struct video_i2c_data *data, char *buf) > > > { > > > - return regmap_bulk_read(data->regmap, 0x400, buf, > > > - data->chip->buffer_size); > > > + int ret = regmap_bulk_read(data->regmap, 0x400, buf, > > > + data->chip->buffer_size - 64); > > > + if (ret) return ret; > > > + return regmap_bulk_read(data->regmap, 0x8000, buf + 1664, > > > + 64); > > > > Rather than "buf + 1664" it would be more portable and clear if you > > use "buf + (data->chip->buffer_size - 64)" > > Okay, I'll send another patch later to change it. > > > Also isn't the 1 line of registers only 32-bytes not 64-bytes? > > In terms of the V4L2 frame, a row is 64-bytes because width is 32 and > each pixel is 16-bit. > This was the main reason to decide the appendage to be 64-bytes. > Ok, forgot this sensor has 12-bit data padded to 16-bits. - Matt > For MLX90640, the address 0x8010 is mentioned in the datasheet, and > actual output appears that up to 0x8013 is valid > For reference, an output from my sensor shows: > 0x8000: 0900 a200 9f69 0000 6120 0500 2003 e003 2817 4f8e 8701 8d04 > 0000 8119 0000 0000 > 0x8010: 33be 8000 4d02 0000 ffff ffff ffff ffff ffff ffff ffff ffff > ffff ffff ffff ffff > > - Seongyong > > > > > - Matt > > > > > } > > > > > > static int amg88xx_setup(struct video_i2c_data *data) > > > @@ -375,7 +378,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { > > > .format = &mlx90640_format, > > > .frame_intervals = mlx90640_frame_intervals, > > > .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), > > > - .buffer_size = 1664, > > > + .buffer_size = 1728, > > > .bpp = 16, > > > .regmap_config = &mlx90640_regmap_config, > > > .nvmem_config = &mlx90640_nvram_config, > > > -- > > > 2.31.1 > > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 2021-05-16 11:09 ` [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park @ 2021-05-16 20:13 ` Matt Ranostay 2021-05-19 3:45 ` [PATCH V2 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park 2021-06-05 11:54 ` Seongyong Park 3 siblings, 0 replies; 16+ messages in thread From: Matt Ranostay @ 2021-05-16 20:13 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Mauro Carvalho Chehab On Sun, May 16, 2021 at 4:09 AM Seongyong Park <euphoriccatface@gmail.com> wrote: > > Current implementation calculates frame delay based on the time of > start of the loop. This inevitably causes the loop delay to be > slightly longer than the actual measurement period, thus skipping a frame > every now and then. > > However, MLX90640 should ideally be working without a frame skip. > Each measurement step updates half of the pixels in the frame > (every other pixel in default "chess mode", and every other row > in "interleave mode"), while additional coefficient data (25th & 26th row) > updates every step. The compensational coefficient data only corresponds > with the pixels updated in the same step. > > In short, if a frame is skipped, then half of a frame loses correction > information and becomes garbage data. This changeset makes sense to me. Guess I got lucky with the timing on my board. Reviewed-by: Matt Ranostay <matt.ranostay@konsulko.com> > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > --- > drivers/media/i2c/video-i2c.c | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > index 0465832a4..2ccb08335 100644 > --- a/drivers/media/i2c/video-i2c.c > +++ b/drivers/media/i2c/video-i2c.c > @@ -445,14 +445,16 @@ 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); > + unsigned long end_jiffies = jiffies; > > set_freezable(); > > do { > - unsigned long start_jiffies = jiffies; > struct video_i2c_buffer *vid_cap_buf = NULL; > int schedule_delay; > > + end_jiffies += delay; > + > try_to_freeze(); > > spin_lock(&data->slock); > @@ -477,10 +479,9 @@ 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_delay = end_jiffies - jiffies; > + while (schedule_delay <= 0) > + schedule_delay += delay; > > schedule_timeout_interruptible(schedule_delay); > } while (!kthread_should_stop()); > -- > 2.31.1 > ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH V2 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 2021-05-16 11:09 ` [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park 2021-05-16 20:13 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Matt Ranostay @ 2021-05-19 3:45 ` Seongyong Park 2021-06-05 11:54 ` Seongyong Park 3 siblings, 0 replies; 16+ messages in thread From: Seongyong Park @ 2021-05-19 3:45 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park On MLX90640, Each measurement step updates half of the pixels in the frame (every other pixel in default "chess mode", and every other row in "interleave mode"), while additional coefficient data (25th & 26th row) updates every step. The compensational coefficient data only corresponds with the pixels updated in the same step. Only way to know which "subpage" was updated on the last step is to read "status register" on address 0x8000. Without this data, compensation calculation may be able to detect which sets of pixels have been updated, but it will have to make assumptions when frame skip happens, and there is no way to do it correctly when the host simply cannot keep up with refresh rate. Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> --- drivers/media/i2c/video-i2c.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 2ccb08335..f2313b446 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -74,7 +74,8 @@ static const struct v4l2_fmtdesc mlx90640_format = { static const struct v4l2_frmsize_discrete mlx90640_size = { .width = 32, - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ + .height = 27, + /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ }; static const struct regmap_config amg88xx_regmap_config = { @@ -168,8 +169,12 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) static int mlx90640_xfer(struct video_i2c_data *data, char *buf) { - return regmap_bulk_read(data->regmap, 0x400, buf, - data->chip->buffer_size); + int ret = regmap_bulk_read(data->regmap, 0x400, buf, + data->chip->buffer_size - 64); + if (ret) + return ret; + return regmap_bulk_read(data->regmap, 0x8000, buf + (data->chip->buffer_size - 64), + 64); } static int amg88xx_setup(struct video_i2c_data *data) @@ -375,7 +380,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { .format = &mlx90640_format, .frame_intervals = mlx90640_frame_intervals, .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), - .buffer_size = 1664, + .buffer_size = 1728, .bpp = 16, .regmap_config = &mlx90640_regmap_config, .nvmem_config = &mlx90640_nvram_config, -- 2.31.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH V2 2/2] media: video-i2c: append register data on MLX90640's frame 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park ` (2 preceding siblings ...) 2021-05-19 3:45 ` [PATCH V2 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park @ 2021-06-05 11:54 ` Seongyong Park 3 siblings, 0 replies; 16+ messages in thread From: Seongyong Park @ 2021-06-05 11:54 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park On MLX90640, Each measurement step updates half of the pixels in the frame (every other pixel in default "chess mode", and every other row in "interleave mode"), while additional coefficient data (25th & 26th row) updates every step. The compensational coefficient data only corresponds with the pixels updated in the same step. Only way to know which "subpage" was updated on the last step is to read "status register" on address 0x8000. Without this data, compensation calculation may be able to detect which sets of pixels have been updated, but it will have to make assumptions when frame skip happens, and there is no way to do it correctly when the host simply cannot keep up with refresh rate. Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> --- drivers/media/i2c/video-i2c.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 2ccb08335..f2313b446 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -74,7 +74,8 @@ static const struct v4l2_fmtdesc mlx90640_format = { static const struct v4l2_frmsize_discrete mlx90640_size = { .width = 32, - .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ + .height = 27, + /* 24 lines of pixel data + 2 lines of processing data + 1 line of registers */ }; static const struct regmap_config amg88xx_regmap_config = { @@ -168,8 +169,12 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) static int mlx90640_xfer(struct video_i2c_data *data, char *buf) { - return regmap_bulk_read(data->regmap, 0x400, buf, - data->chip->buffer_size); + int ret = regmap_bulk_read(data->regmap, 0x400, buf, + data->chip->buffer_size - 64); + if (ret) + return ret; + return regmap_bulk_read(data->regmap, 0x8000, buf + (data->chip->buffer_size - 64), + 64); } static int amg88xx_setup(struct video_i2c_data *data) @@ -375,7 +380,7 @@ static const struct video_i2c_chip video_i2c_chip[] = { .format = &mlx90640_format, .frame_intervals = mlx90640_frame_intervals, .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), - .buffer_size = 1664, + .buffer_size = 1728, .bpp = 16, .regmap_config = &mlx90640_regmap_config, .nvmem_config = &mlx90640_nvram_config, -- 2.31.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-05 11:54 [PATCH V2 0/2] media: video-i2c: additional support for Melexis MLX90640 Seongyong Park 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park @ 2021-06-05 11:54 ` Seongyong Park 2021-06-05 14:00 ` Mauro Carvalho Chehab 1 sibling, 1 reply; 16+ messages in thread From: Seongyong Park @ 2021-06-05 11:54 UTC (permalink / raw) To: linux-media; +Cc: Matt Ranostay, Mauro Carvalho Chehab, Seongyong Park Current implementation calculates frame delay based on the time of start of the loop. This inevitably causes the loop delay to be slightly longer than the actual measurement period, thus skipping a frame every now and then. However, MLX90640 should ideally be working without a frame skip. Each measurement step updates half of the pixels in the frame (every other pixel in default "chess mode", and every other row in "interleave mode"), while additional coefficient data (25th & 26th row) updates every step. The compensational coefficient data only corresponds with the pixels updated in the same step. In short, if a frame is skipped, then half of a frame loses correction information and becomes garbage data. Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> --- drivers/media/i2c/video-i2c.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 0465832a4..2ccb08335 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -445,14 +445,16 @@ 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); + unsigned long end_jiffies = jiffies; set_freezable(); do { - unsigned long start_jiffies = jiffies; struct video_i2c_buffer *vid_cap_buf = NULL; int schedule_delay; + end_jiffies += delay; + try_to_freeze(); spin_lock(&data->slock); @@ -477,10 +479,9 @@ 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_delay = end_jiffies - jiffies; + while (schedule_delay <= 0) + schedule_delay += delay; schedule_timeout_interruptible(schedule_delay); } while (!kthread_should_stop()); -- 2.31.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-05 11:54 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park @ 2021-06-05 14:00 ` Mauro Carvalho Chehab 2021-06-05 14:53 ` Mauro Carvalho Chehab 0 siblings, 1 reply; 16+ messages in thread From: Mauro Carvalho Chehab @ 2021-06-05 14:00 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Matt Ranostay Em Sat, 5 Jun 2021 20:54:56 +0900 Seongyong Park <euphoriccatface@gmail.com> escreveu: > Current implementation calculates frame delay based on the time of > start of the loop. This inevitably causes the loop delay to be > slightly longer than the actual measurement period, thus skipping a frame > every now and then. > > However, MLX90640 should ideally be working without a frame skip. > Each measurement step updates half of the pixels in the frame > (every other pixel in default "chess mode", and every other row > in "interleave mode"), while additional coefficient data (25th & 26th row) > updates every step. The compensational coefficient data only corresponds > with the pixels updated in the same step. > > In short, if a frame is skipped, then half of a frame loses correction > information and becomes garbage data. > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > --- > drivers/media/i2c/video-i2c.c | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > index 0465832a4..2ccb08335 100644 > --- a/drivers/media/i2c/video-i2c.c > +++ b/drivers/media/i2c/video-i2c.c > @@ -445,14 +445,16 @@ 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); > + unsigned long end_jiffies = jiffies; > > set_freezable(); > > do { > - unsigned long start_jiffies = jiffies; > struct video_i2c_buffer *vid_cap_buf = NULL; > int schedule_delay; > > + end_jiffies += delay; > + > try_to_freeze(); > > spin_lock(&data->slock); > @@ -477,10 +479,9 @@ 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_delay = end_jiffies - jiffies; > + while (schedule_delay <= 0) > + schedule_delay += delay; Huh? Why do you need a loop for that? If you want to make it positive, you could just do: if (schedule_delay < 0) schedule_delay = delay; /* or something else */ but this won't solve the issue, as this is basically equivalent to the logic you removed. > > schedule_timeout_interruptible(schedule_delay); This is probably what's causing troubles, as this only ensures that it will sleep for at least schedule_delay (if not interrupted). If you want to give a dead line to schedule, you should likely be doing, instead: usleep_range(delay, delay + delta); this would tell the realtime clock that there's a dead line of (schedule_delay + delta) microseconds. You'll need to change the delay to be in microseconds too, e. g., I guess that something similar to this: static int video_i2c_thread_vid_cap(void *priv) { struct video_i2c_data *data = priv; u64 delay; delay = div64_u64(1000000ULL * data->frame_interval.numerator, data->frame_interval.denominator); set_freezable(); do { ... usleep_range(delay * 3 / 4, delay); } while (!kthread_should_stop()); return 0; } would give you what you want. Regards, Mauro ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-05 14:00 ` Mauro Carvalho Chehab @ 2021-06-05 14:53 ` Mauro Carvalho Chehab 2021-06-06 7:20 ` Seongyong Park 0 siblings, 1 reply; 16+ messages in thread From: Mauro Carvalho Chehab @ 2021-06-05 14:53 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Matt Ranostay Em Sat, 5 Jun 2021 16:00:28 +0200 Mauro Carvalho Chehab <mchehab@kernel.org> escreveu: > Em Sat, 5 Jun 2021 20:54:56 +0900 > Seongyong Park <euphoriccatface@gmail.com> escreveu: > > > Current implementation calculates frame delay based on the time of > > start of the loop. This inevitably causes the loop delay to be > > slightly longer than the actual measurement period, thus skipping a frame > > every now and then. > > > > However, MLX90640 should ideally be working without a frame skip. > > Each measurement step updates half of the pixels in the frame > > (every other pixel in default "chess mode", and every other row > > in "interleave mode"), while additional coefficient data (25th & 26th row) > > updates every step. The compensational coefficient data only corresponds > > with the pixels updated in the same step. > > > > In short, if a frame is skipped, then half of a frame loses correction > > information and becomes garbage data. > > > > Signed-off-by: Seongyong Park <euphoriccatface@gmail.com> > > --- > > drivers/media/i2c/video-i2c.c | 11 ++++++----- > > 1 file changed, 6 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c > > index 0465832a4..2ccb08335 100644 > > --- a/drivers/media/i2c/video-i2c.c > > +++ b/drivers/media/i2c/video-i2c.c > > @@ -445,14 +445,16 @@ 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); > > + unsigned long end_jiffies = jiffies; > > > > set_freezable(); > > > > do { > > - unsigned long start_jiffies = jiffies; > > struct video_i2c_buffer *vid_cap_buf = NULL; > > int schedule_delay; > > > > + end_jiffies += delay; > > + > > try_to_freeze(); > > > > spin_lock(&data->slock); > > @@ -477,10 +479,9 @@ 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_delay = end_jiffies - jiffies; > > + while (schedule_delay <= 0) > > + schedule_delay += delay; > > Huh? Why do you need a loop for that? If you want to make it positive, > you could just do: > > if (schedule_delay < 0) > schedule_delay = delay; /* or something else */ > > but this won't solve the issue, as this is basically equivalent > to the logic you removed. > > > > > schedule_timeout_interruptible(schedule_delay); > > This is probably what's causing troubles, as this only ensures > that it will sleep for at least schedule_delay (if not > interrupted). > > If you want to give a dead line to schedule, you should > likely be doing, instead: > > usleep_range(delay, delay + delta); > > this would tell the realtime clock that there's a dead line of > (schedule_delay + delta) microseconds. > > You'll need to change the delay to be in microseconds too, > e. g., I guess that something similar to this: > > > static int video_i2c_thread_vid_cap(void *priv) > { > struct video_i2c_data *data = priv; > u64 delay; > > delay = div64_u64(1000000ULL * data->frame_interval.numerator, > data->frame_interval.denominator); > > set_freezable(); > > do { > ... > usleep_range(delay * 3 / 4, delay); > } while (!kthread_should_stop()); > > return 0; > } > > would give you what you want. The actual the logic should be more complex, as it needs to dynamically adjust the delay based on how much frames were streamed and how much time it was elapsed, but the basically idea is that you would need to use: usleep_range(min_delay_us, max_delay_us); instead of: schedule_timeout_interruptible(schedule_delay); in order to tell the realtime clock about a dead line for sleeping. Thanks, Mauro ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-05 14:53 ` Mauro Carvalho Chehab @ 2021-06-06 7:20 ` Seongyong Park 2021-06-06 11:00 ` Mauro Carvalho Chehab 0 siblings, 1 reply; 16+ messages in thread From: Seongyong Park @ 2021-06-06 7:20 UTC (permalink / raw) To: Mauro Carvalho Chehab; +Cc: linux-media, Matt Ranostay, Seongyong Park 2021년 6월 5일 (토) 오후 11:53, Mauro Carvalho Chehab <mchehab@kernel.org>님이 작성: > you would need to use: > > usleep_range(min_delay_us, max_delay_us); > > instead of: > > schedule_timeout_interruptible(schedule_delay); > > in order to tell the realtime clock about a dead line for > sleeping. > > Thanks, > Mauro Okay, I have tried `usleep_range()` instead, and it indeed shows improvement in the frame rate. Now it's basically the same as before my patch, except for `jiffies_to_usecs()` and then `usleep_range()`. ... int schedule_delay; + uint64_t schedule_delay_us; try_to_freeze(); ... if (time_after(jiffies, start_jiffies + delay)) schedule_delay = delay; - schedule_timeout_interruptible(schedule_delay); + schedule_delay_us = jiffies_to_usecs(schedule_delay); + usleep_range(schedule_delay_us * 3/4, schedule_delay_us); } while (!kthread_should_stop()); return 0; ... I decided to keep the `if (...) schedule_delay = delay;` part. The concern was that my RPi Zero was having quite a bit of constant drift, like showing 3FPS when set to 4FPS, 6FPS when 8FPS, 10FPS when 16FPS, and so on. Now that I've confirmed the timing's good enough (usually ~0.5 FPS faster than the frame rate given), there's no need for me to bother anymore. I'll send another patchset if it doesn't look too bad. Thank you very much. Seongyong Park ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-06 7:20 ` Seongyong Park @ 2021-06-06 11:00 ` Mauro Carvalho Chehab 2021-06-06 15:06 ` Seongyong Park 0 siblings, 1 reply; 16+ messages in thread From: Mauro Carvalho Chehab @ 2021-06-06 11:00 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Matt Ranostay Em Sun, 6 Jun 2021 16:20:53 +0900 Seongyong Park <euphoriccatface@gmail.com> escreveu: > 2021년 6월 5일 (토) 오후 11:53, Mauro Carvalho Chehab <mchehab@kernel.org>님이 작성: > > you would need to use: > > > > usleep_range(min_delay_us, max_delay_us); > > > > instead of: > > > > schedule_timeout_interruptible(schedule_delay); > > > > in order to tell the realtime clock about a dead line for > > sleeping. > > > > Thanks, > > Mauro > > Okay, I have tried `usleep_range()` instead, and it indeed shows > improvement in the frame rate. > Now it's basically the same as before my patch, except for > `jiffies_to_usecs()` and then `usleep_range()`. > > ... > int schedule_delay; > + uint64_t schedule_delay_us; > > try_to_freeze(); > ... > if (time_after(jiffies, start_jiffies + delay)) > schedule_delay = delay; > > - schedule_timeout_interruptible(schedule_delay); > + schedule_delay_us = jiffies_to_usecs(schedule_delay); > + usleep_range(schedule_delay_us * 3/4, schedule_delay_us); > } while (!kthread_should_stop()); > > return 0; > ... > > I decided to keep the `if (...) schedule_delay = delay;` part. Yeah, you would need something like that. > The concern was that my RPi Zero was having quite a bit of constant > drift, like showing 3FPS when set to 4FPS, 6FPS when 8FPS, 10FPS when > 16FPS, and so on. > Now that I've confirmed the timing's good enough (usually ~0.5 FPS > faster than the frame rate given), there's no need for me to bother > anymore. In other to avoid the drift, the logic needs to calculate the delay based on something like this (pseudo-C) code: start_jiffies = jiffies; frame_count = 0; i = 0; do { i++; delay = jiffies - (start_jiffies * i * <interval>); ... } The actual logic should probably avoid multiplying stuff there, as this could go sideways easily due to overflows. Perhaps something like this would work better, keeping a more precise average fps rate: next_jiffies = jiffies + delay; do { ... schedule_delay_us = jiffies_to_usecs(next_jiffies - jiffies); usleep_range(schedule_delay_us * 3/4, schedule_delay_us); ... next_jiffies += delay; } > > I'll send another patchset if it doesn't look too bad. > > Thank you very much. > Seongyong Park Thanks, Mauro ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-06 11:00 ` Mauro Carvalho Chehab @ 2021-06-06 15:06 ` Seongyong Park 2021-06-06 19:18 ` Mauro Carvalho Chehab 0 siblings, 1 reply; 16+ messages in thread From: Seongyong Park @ 2021-06-06 15:06 UTC (permalink / raw) To: Mauro Carvalho Chehab; +Cc: linux-media, Matt Ranostay `2021년 6월 6일 (일) 오후 8:00, Mauro Carvalho Chehab <mchehab@kernel.org>님이 작성: > > > Perhaps something like this would work better, keeping a more precise > average fps rate: > > next_jiffies = jiffies + delay; > do { > ... > schedule_delay_us = jiffies_to_usecs(next_jiffies - jiffies); > usleep_range(schedule_delay_us * 3/4, schedule_delay_us); ... > next_jiffies += delay; > } > > > > > I'll send another patchset if it doesn't look too bad. > > > > Thank you very much. > > Seongyong Park > > > > Thanks, > Mauro For a few hours, I couldn't get the module to make precise timing. It would always be a few tenths of FPS higher than I set, regardless of how I construct the calculation. And then it hit me, maybe jiffies is not granular enough - and of course, resolution of jiffies turns out to be 100Hz :P e.g. If you set it 16FPS, the count of jiffies to sleep results 100 / 16 = 6 The sleep interval ends up being 60ms, resulting in 16.666... FPS. This discrepancy gets quite big if you set it to 64 FPS, resulting in a single jiffies count, i.e. 100Hz. (Though you will need to either skip some data, or set I2C baud rate beyond the sensor's spec in order to realistically even achieve 64 FPS, at least on an RPi Zero it seems.) So, I basically changed the time source from `jiffies` to `ktime_to_us(ktime_get())`. The timing is definitely better now :) One last question please, before creating another patchset. > usleep_range(schedule_delay_us * 3/4, schedule_delay_us); Is it okay to make it essentially 0 microseconds sleep here, by setting `schedule_delay_us` to 0? It's going to be like, ``` if (current_us > end_us) { end_us = current_us; } schedule_delay_us = end_us - current_us; ``` Regards, Seongyong Park ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time 2021-06-06 15:06 ` Seongyong Park @ 2021-06-06 19:18 ` Mauro Carvalho Chehab 0 siblings, 0 replies; 16+ messages in thread From: Mauro Carvalho Chehab @ 2021-06-06 19:18 UTC (permalink / raw) To: Seongyong Park; +Cc: linux-media, Matt Ranostay Em Mon, 7 Jun 2021 00:06:36 +0900 Seongyong Park <euphoriccatface@gmail.com> escreveu: > `2021년 6월 6일 (일) 오후 8:00, Mauro Carvalho Chehab <mchehab@kernel.org>님이 작성: > > > > > > Perhaps something like this would work better, keeping a more precise > > average fps rate: > > > > next_jiffies = jiffies + delay; > > do { > > ... > > schedule_delay_us = jiffies_to_usecs(next_jiffies - jiffies); > > usleep_range(schedule_delay_us * 3/4, schedule_delay_us); ... > > next_jiffies += delay; > > } > > > > > > > > I'll send another patchset if it doesn't look too bad. > > > > > > Thank you very much. > > > Seongyong Park > > > > > > > > Thanks, > > Mauro > > For a few hours, I couldn't get the module to make precise timing. > It would always be a few tenths of FPS higher than I set, regardless > of how I construct the calculation. > And then it hit me, maybe jiffies is not granular enough - and of > course, resolution of jiffies turns out to be 100Hz :P It is actually worse than that, as it depends on CONFIG_HZ, which is set by the one who built the Kernel. So, on other machines, it could be higher (like 1200) or lower (24 is one of the options on mips) ;-) > e.g. If you set it 16FPS, the count of jiffies to sleep results 100 / 16 = 6 > The sleep interval ends up being 60ms, resulting in 16.666... FPS. That's basically why I suggested you to count the time from the start of streaming, instead of just waiting for a fixed delay every time. > This discrepancy gets quite big if you set it to 64 FPS, resulting in > a single jiffies count, i.e. 100Hz. > (Though you will need to either skip some data, or set I2C baud rate > beyond the sensor's spec > in order to realistically even achieve 64 FPS, at least on an RPi Zero > it seems.) The issue is probably not RPi zero, but the low speeds of I2C bus, and the speed of the sensor. > So, I basically changed the time source from `jiffies` to > `ktime_to_us(ktime_get())`. > The timing is definitely better now :) This helps but it probably use a lot more CPU cycles than reading jiffies. > One last question please, before creating another patchset. > > usleep_range(schedule_delay_us * 3/4, schedule_delay_us); > Is it okay to make it essentially 0 microseconds sleep here, by > setting `schedule_delay_us` to 0? > It's going to be like, > ``` > if (current_us > end_us) { > end_us = current_us; > } > schedule_delay_us = end_us - current_us; > ``` Not sure, but you could instead revert the logic, like: if (current_us <= end_us) usleep_range(); Thanks, Mauro ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2021-06-06 19:18 UTC | newest] Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-06-05 11:54 [PATCH V2 0/2] media: video-i2c: additional support for Melexis MLX90640 Seongyong Park 2021-05-16 11:09 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 2021-05-16 11:09 ` [PATCH 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park 2021-05-16 20:48 ` Matt Ranostay 2021-05-17 1:39 ` Seongyong Park 2021-05-17 23:40 ` Matt Ranostay 2021-05-16 20:13 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Matt Ranostay 2021-05-19 3:45 ` [PATCH V2 2/2] media: video-i2c: append register data on MLX90640's frame Seongyong Park 2021-06-05 11:54 ` Seongyong Park 2021-06-05 11:54 ` [PATCH 1/2] media: video-i2c: frame delay based on last frame's end time Seongyong Park 2021-06-05 14:00 ` Mauro Carvalho Chehab 2021-06-05 14:53 ` Mauro Carvalho Chehab 2021-06-06 7:20 ` Seongyong Park 2021-06-06 11:00 ` Mauro Carvalho Chehab 2021-06-06 15:06 ` Seongyong Park 2021-06-06 19:18 ` Mauro Carvalho Chehab
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.