Skip to content

Commit 0cb0ea4

Browse files
committed
Video: GC2145/stm32_dcmi support for CROP/Snapshot
Added support to video_stm32_dcmi for the new set and get selection. These implementations simply forward the message to the underlying camera object if they support these messages. Also added support for a snapshot mode instead of always using continuous capture mode. Tried to make it semi-transparent when you desire it to be The stm32_dcmi code now also allows you to work with only one buffer. This will force it into snapshot mode. There is also new calls added to the api for: video_get_snapshot_mode and video_set_snapshot_mode. That allows you to set it with more than one buffer and query what mode you are in. GC2145 was updated first to try out these changes. The camera now allows me to follow the call order that @josuah mentioned in another pr/issue. With this driver I also updated it to allow any resolution from the displays min to max limits. static const struct video_format_cap fmts[] = { GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_RGB565), GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_YUYV), It also still retains the other resolutions as some software does not check if it is within a range but only against the min value. When the resolution is set, it computes the scale factor. If you then later call set_crop, the same code is used except it uses the ratios computed from the set_resolution. Currently it clamps the ratio to a max of 3 as some other drivers limit it saying it helps with frame rates. With these changes: I was able to setup a test app, for the Arduino Nicla vision and send out a 480x320 image over USB. Video: GC2145 update set Format/Crop as mentioned As such if you passed in 640x480 on set_format, that is what you are limited to. So VIDEO_SEL_TGT_NATIVE_SIZE will return 640x480, so I need to save that away and/or grab it from registers. As the setting the crop updates the fmt structure: Also limited ratio in set resolution to 3 as it was mentioned in other implementations to help with frame rate. Signed-off-by: Kurt Eckhardt [email protected]
1 parent 1edc97c commit 0cb0ea4

File tree

3 files changed

+352
-39
lines changed

3 files changed

+352
-39
lines changed

drivers/video/gc2145.c

Lines changed: 184 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -706,10 +706,16 @@ static const struct video_reg8 default_regs[] = {
706706
{0x46, 0xcf},
707707

708708
{GC2145_REG_RESET, GC2145_REG_RESET_P0_REGS},
709+
/* Hb and Vb from Teensy_camera */
709710
{0x05, 0x01},
710-
{0x06, 0x1C},
711-
{0x07, 0x00},
712-
{0x08, 0x32},
711+
{0x06, 0x3b},
712+
{0x07, 0x01},
713+
{0x08, 0x0b},
714+
/* Hb and Vb from current */
715+
/*{0x05, 0x01}, */
716+
/*{0x06, 0x1C}, */
717+
/*{0x07, 0x00}, */
718+
/*{0x08, 0x32}, */
713719
{0x11, 0x00},
714720
{0x12, 0x1D},
715721
{0x13, 0x00},
@@ -768,12 +774,23 @@ struct gc2145_ctrls {
768774
struct gc2145_data {
769775
struct gc2145_ctrls ctrls;
770776
struct video_format fmt;
777+
struct video_rect crop;
778+
uint16_t format_width;
779+
uint16_t format_height;
780+
uint8_t c_ratio;
781+
uint8_t r_ratio;
771782
};
772783

773-
#define GC2145_VIDEO_FORMAT_CAP(width, height, format) \
774-
{ \
775-
.pixelformat = format, .width_min = width, .width_max = width, \
776-
.height_min = height, .height_max = height, .width_step = 0, .height_step = 0, \
784+
#define GC2145_VIDEO_FORMAT_CAP(width, height, format) \
785+
{ \
786+
.pixelformat = format, .width_min = width, .width_max = width, \
787+
.height_min = height, .height_max = height, .width_step = 0, .height_step = 0, \
788+
}
789+
790+
#define GC2145_VIDEO_FORMAT_CAP_HL(width_l, width_h, height_l, height_h, format) \
791+
{ \
792+
.pixelformat = format, .width_min = width_l, .width_max = width_h, \
793+
.height_min = height_l, .height_max = height_h, .width_step = 0, .height_step = 0,\
777794
}
778795

779796
#define RESOLUTION_QVGA_W 320
@@ -792,6 +809,9 @@ static const struct video_format_cap fmts[] = {
792809
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_QVGA_W, RESOLUTION_QVGA_H, VIDEO_PIX_FMT_YUYV),
793810
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_VGA_W, RESOLUTION_VGA_H, VIDEO_PIX_FMT_YUYV),
794811
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_UXGA_W, RESOLUTION_UXGA_H, VIDEO_PIX_FMT_YUYV),
812+
/* Add catchall resolution */
813+
GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_RGB565),
814+
GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_YUYV),
795815
{0},
796816
};
797817

@@ -843,47 +863,66 @@ static int gc2145_set_output_format(const struct device *dev, int output_format)
843863
return 0;
844864
}
845865

846-
static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t h)
866+
867+
static int gc2145_gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t h)
847868
{
848869
const struct gc2145_config *cfg = dev->config;
870+
struct gc2145_data *drv_data = dev->data;
849871
int ret;
850872

851873
uint16_t win_w;
852874
uint16_t win_h;
853-
uint16_t c_ratio;
854-
uint16_t r_ratio;
855875
uint16_t x;
856876
uint16_t y;
857877
uint16_t win_x;
858878
uint16_t win_y;
859879

860-
/* Add the subsampling factor depending on resolution */
861-
switch (w) {
862-
case RESOLUTION_QVGA_W:
863-
c_ratio = 3;
864-
r_ratio = 3;
865-
break;
866-
case RESOLUTION_VGA_W:
867-
c_ratio = 2;
868-
r_ratio = 2;
869-
break;
870-
case RESOLUTION_UXGA_W:
871-
c_ratio = 1;
872-
r_ratio = 1;
873-
break;
874-
default:
875-
LOG_ERR("Unsupported resolution %d %d", w, h);
880+
if ((w == 0) || (h == 0)) {
876881
return -EIO;
877-
};
882+
}
883+
884+
/* If we are called from set_format, then we compute ratio and initialize crop */
885+
drv_data->c_ratio = RESOLUTION_UXGA_W / w;
886+
drv_data->r_ratio = RESOLUTION_UXGA_H / h;
887+
if (drv_data->c_ratio < drv_data->r_ratio) {
888+
drv_data->r_ratio = drv_data->c_ratio;
889+
} else {
890+
drv_data->c_ratio = drv_data->r_ratio;
891+
}
892+
893+
/* Restrict ratio to 3 for faster refresh ? */
894+
if (drv_data->c_ratio > 3) {
895+
drv_data->c_ratio = 3;
896+
drv_data->r_ratio = 3;
897+
}
898+
899+
/* make sure we don't end up with ratio of 0 */
900+
if (drv_data->c_ratio == 0) {
901+
return -EIO;
902+
}
903+
904+
/* remember the width and height passed in */
905+
drv_data->format_width = w;
906+
drv_data->format_height = h;
907+
908+
/* Default to crop rectangle being same size as passed in resolution */
909+
drv_data->crop.left = 0;
910+
drv_data->crop.top = 0;
911+
drv_data->crop.width = w;
912+
drv_data->crop.height = h;
913+
878914

879915
/* Calculates the window boundaries to obtain the desired resolution */
880-
win_w = w * c_ratio;
881-
win_h = h * r_ratio;
882-
x = (((win_w / c_ratio) - w) / 2);
883-
y = (((win_h / r_ratio) - h) / 2);
916+
917+
win_w = w * drv_data->c_ratio;
918+
win_h = h * drv_data->r_ratio;
884919
win_x = ((UXGA_HSIZE - win_w) / 2);
885920
win_y = ((UXGA_VSIZE - win_h) / 2);
886921

922+
923+
x = (((win_w / drv_data->c_ratio) - w) / 2);
924+
y = (((win_h / drv_data->r_ratio) - h) / 2);
925+
887926
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG8(GC2145_REG_RESET),
888927
GC2145_REG_RESET_P0_REGS);
889928
if (ret < 0) {
@@ -933,7 +972,8 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
933972
}
934973

935974
/* Set Sub-sampling ratio and mode */
936-
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE, ((r_ratio << 4) | c_ratio));
975+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE,
976+
((drv_data->r_ratio << 4) | drv_data->c_ratio));
937977
if (ret < 0) {
938978
return ret;
939979
}
@@ -954,6 +994,66 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
954994
return 0;
955995
}
956996

997+
static int gc2145_set_crop(const struct device *dev, struct video_selection *sel)
998+
{
999+
/* set the crop, start off with most of a duplicate of set resolution */
1000+
int ret;
1001+
const struct gc2145_config *cfg = dev->config;
1002+
struct gc2145_data *drv_data = dev->data;
1003+
1004+
1005+
/* Verify the passed in rectangle is valid */
1006+
if (((sel->rect.left + sel->rect.width) > drv_data->format_width) ||
1007+
((sel->rect.top + sel->rect.height) > drv_data->format_height)) {
1008+
LOG_INF("(%u %u) %ux%u > %ux%u", sel->rect.left, sel->rect.top,
1009+
sel->rect.width, sel->rect.height,
1010+
drv_data->format_width, drv_data->format_height);
1011+
return -EINVAL;
1012+
}
1013+
1014+
/* if rectangle passed in is same as current, simply return */
1015+
if (memcmp((void *)&drv_data->crop, (void *)&sel->rect, sizeof(struct video_rect)) == 0) {
1016+
return 0;
1017+
}
1018+
1019+
/* save out the updated crop window registers */
1020+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG8(GC2145_REG_RESET),
1021+
GC2145_REG_RESET_P0_REGS);
1022+
if (ret < 0) {
1023+
return ret;
1024+
}
1025+
1026+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_OUT_WIN_ROW_START, sel->rect.top);
1027+
if (ret < 0) {
1028+
return ret;
1029+
}
1030+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_OUT_WIN_COL_START, sel->rect.left);
1031+
if (ret < 0) {
1032+
return ret;
1033+
}
1034+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_OUT_WIN_HEIGHT, sel->rect.height);
1035+
if (ret < 0) {
1036+
return ret;
1037+
}
1038+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_OUT_WIN_WIDTH, sel->rect.width);
1039+
if (ret < 0) {
1040+
return ret;
1041+
}
1042+
1043+
1044+
/* Only if valid do we update our crop rectangle */
1045+
drv_data->crop = sel->rect;
1046+
1047+
/* enqueue/dequeue depend on this being set as well as the crop */
1048+
drv_data->fmt.width = drv_data->crop.width;
1049+
drv_data->fmt.height = drv_data->crop.height;
1050+
drv_data->fmt.pitch = drv_data->fmt.width *
1051+
video_bits_per_pixel(drv_data->fmt.pixelformat) / BITS_PER_BYTE;
1052+
1053+
return 0;
1054+
}
1055+
1056+
9571057
static int gc2145_check_connection(const struct device *dev)
9581058
{
9591059
const struct gc2145_config *cfg = dev->config;
@@ -1057,7 +1157,10 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10571157

10581158
/* Check if camera is capable of handling given format */
10591159
for (int i = 0; i < ARRAY_SIZE(fmts) - 1; i++) {
1060-
if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height &&
1160+
if ((fmts[i].width_min <= fmt->width) &&
1161+
(fmts[i].width_max >= fmt->width) &&
1162+
(fmts[i].height_min <= fmt->height) &&
1163+
(fmts[i].height_max >= fmt->height) &&
10611164
fmts[i].pixelformat == fmt->pixelformat) {
10621165
res = i;
10631166
break;
@@ -1076,7 +1179,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10761179
}
10771180

10781181
/* Set window size */
1079-
ret = gc2145_set_resolution(dev, fmt->width, fmt->height);
1182+
ret = gc2145_gc2145_set_resolution(dev, fmt->width, fmt->height);
10801183

10811184
if (ret < 0) {
10821185
LOG_ERR("Failed to set the resolution");
@@ -1171,12 +1274,57 @@ static int gc2145_set_ctrl(const struct device *dev, uint32_t id)
11711274
}
11721275
}
11731276

1277+
static int gc2145_set_selection(const struct device *dev, struct video_selection *sel)
1278+
{
1279+
LOG_DBG("called: (%p, %p: %u %u)", dev, sel, sel->type, sel->target);
1280+
if (sel->type != VIDEO_BUF_TYPE_OUTPUT) {
1281+
return -EINVAL;
1282+
}
1283+
1284+
if (sel->target == VIDEO_SEL_TGT_CROP) {
1285+
return gc2145_set_crop(dev, sel);
1286+
}
1287+
1288+
return -EINVAL;
1289+
}
1290+
1291+
static int gc2145_get_selection(const struct device *dev, struct video_selection *sel)
1292+
{
1293+
LOG_DBG("called: (%p, %p: %u %u)", dev, sel, sel->type, sel->target);
1294+
if (sel->type != VIDEO_BUF_TYPE_OUTPUT) {
1295+
return -EINVAL;
1296+
}
1297+
1298+
struct gc2145_data *drv_data = dev->data;
1299+
1300+
switch (sel->target) {
1301+
case VIDEO_SEL_TGT_COMPOSE:
1302+
case VIDEO_SEL_TGT_CROP:
1303+
sel->rect = drv_data->crop;
1304+
break;
1305+
1306+
case VIDEO_SEL_TGT_NATIVE_SIZE:
1307+
sel->rect.top = 0;
1308+
sel->rect.left = 0;
1309+
sel->rect.width = drv_data->format_width;
1310+
sel->rect.height = drv_data->format_height;
1311+
break;
1312+
default:
1313+
return -EINVAL;
1314+
}
1315+
1316+
return 0;
1317+
}
1318+
1319+
11741320
static DEVICE_API(video, gc2145_driver_api) = {
11751321
.set_format = gc2145_set_fmt,
11761322
.get_format = gc2145_get_fmt,
11771323
.get_caps = gc2145_get_caps,
11781324
.set_stream = gc2145_set_stream,
11791325
.set_ctrl = gc2145_set_ctrl,
1326+
.set_selection = gc2145_set_selection,
1327+
.get_selection = gc2145_get_selection,
11801328
};
11811329

11821330
static int gc2145_init_controls(const struct device *dev)
@@ -1214,8 +1362,8 @@ static int gc2145_init(const struct device *dev)
12141362
/* set default/init format VGA RGB565 */
12151363
struct video_format fmt = {
12161364
.pixelformat = VIDEO_PIX_FMT_RGB565,
1217-
.width = RESOLUTION_VGA_W,
1218-
.height = RESOLUTION_VGA_H,
1365+
.width = RESOLUTION_QVGA_W,
1366+
.height = RESOLUTION_QVGA_H,
12191367
};
12201368
int ret;
12211369
const struct gc2145_config *cfg = dev->config;

0 commit comments

Comments
 (0)