Skip to content

Commit f1d99dd

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), When 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. With these changes: I was able to setup a test app, for the Arduino Nicla vision and send out a 480x320 image over USB. Signed-off-by: kurte <[email protected]>
1 parent 1edc97c commit f1d99dd

File tree

3 files changed

+310
-38
lines changed

3 files changed

+310
-38
lines changed

drivers/video/gc2145.c

Lines changed: 145 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,22 @@ struct gc2145_ctrls {
768774
struct gc2145_data {
769775
struct gc2145_ctrls ctrls;
770776
struct video_format fmt;
777+
struct video_rect crop;
778+
uint8_t c_ratio;
779+
uint8_t r_ratio;
771780
};
772781

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, \
782+
#define USE_ONE_FORMAT_WIDTH_HEIGHT
783+
#define GC2145_VIDEO_FORMAT_CAP(width, height, format) \
784+
{ \
785+
.pixelformat = format, .width_min = width, .width_max = width, \
786+
.height_min = height, .height_max = height, .width_step = 0, .height_step = 0, \
787+
}
788+
789+
#define GC2145_VIDEO_FORMAT_CAP_HL(width_l, width_h, height_l, height_h, format) \
790+
{ \
791+
.pixelformat = format, .width_min = width_l, .width_max = width_h, \
792+
.height_min = height_l, .height_max = height_h, .width_step = 0, .height_step = 0,\
777793
}
778794

779795
#define RESOLUTION_QVGA_W 320
@@ -786,12 +802,22 @@ struct gc2145_data {
786802
#define RESOLUTION_UXGA_H 1200
787803

788804
static const struct video_format_cap fmts[] = {
805+
#ifdef USE_ONE_FORMAT_WIDTH_HEIGHT
806+
GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_RGB565),
807+
GC2145_VIDEO_FORMAT_CAP_HL(128, 1600, 128, 1200, VIDEO_PIX_FMT_YUYV),
808+
#else
789809
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_QVGA_W, RESOLUTION_QVGA_H, VIDEO_PIX_FMT_RGB565),
790810
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_VGA_W, RESOLUTION_VGA_H, VIDEO_PIX_FMT_RGB565),
791811
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_UXGA_W, RESOLUTION_UXGA_H, VIDEO_PIX_FMT_RGB565),
812+
/* Add some full size possible resolutions */
813+
GC2145_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_RGB565), /* div 2 */
814+
GC2145_VIDEO_FORMAT_CAP(533, 400, VIDEO_PIX_FMT_RGB565), /* div 3 */
815+
GC2145_VIDEO_FORMAT_CAP(400, 300, VIDEO_PIX_FMT_RGB565), /* div 4 */
816+
GC2145_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* div 5 */
792817
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_QVGA_W, RESOLUTION_QVGA_H, VIDEO_PIX_FMT_YUYV),
793818
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_VGA_W, RESOLUTION_VGA_H, VIDEO_PIX_FMT_YUYV),
794819
GC2145_VIDEO_FORMAT_CAP(RESOLUTION_UXGA_W, RESOLUTION_UXGA_H, VIDEO_PIX_FMT_YUYV),
820+
#endif
795821
{0},
796822
};
797823

@@ -843,47 +869,52 @@ static int gc2145_set_output_format(const struct device *dev, int output_format)
843869
return 0;
844870
}
845871

846-
static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t h)
872+
873+
static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t h,
874+
bool compute_ratio)
847875
{
848876
const struct gc2145_config *cfg = dev->config;
877+
struct gc2145_data *drv_data = dev->data;
849878
int ret;
850879

851880
uint16_t win_w;
852881
uint16_t win_h;
853-
uint16_t c_ratio;
854-
uint16_t r_ratio;
855882
uint16_t x;
856883
uint16_t y;
857884
uint16_t win_x;
858885
uint16_t win_y;
859886

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);
887+
if ((w == 0) || (h == 0)) {
876888
return -EIO;
877-
};
889+
}
890+
drv_data->c_ratio = RESOLUTION_UXGA_W / w;
891+
drv_data->r_ratio = RESOLUTION_UXGA_H / h;
892+
if (drv_data->c_ratio < drv_data->r_ratio) {
893+
drv_data->r_ratio = drv_data->c_ratio;
894+
} else {
895+
drv_data->c_ratio = drv_data->r_ratio;
896+
}
897+
898+
/* make sure we don't end up with ratio of 0 */
899+
if (drv_data->c_ratio == 0) {
900+
return -EIO;
901+
}
878902

879903
/* 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);
904+
905+
win_w = w * drv_data->c_ratio;
906+
win_h = h * drv_data->r_ratio;
884907
win_x = ((UXGA_HSIZE - win_w) / 2);
885908
win_y = ((UXGA_VSIZE - win_h) / 2);
886909

910+
drv_data->crop.left = 0;
911+
drv_data->crop.top = 0;
912+
drv_data->crop.width = w;
913+
drv_data->crop.height = h;
914+
915+
x = (((win_w / drv_data->c_ratio) - w) / 2);
916+
y = (((win_h / drv_data->r_ratio) - h) / 2);
917+
887918
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG8(GC2145_REG_RESET),
888919
GC2145_REG_RESET_P0_REGS);
889920
if (ret < 0) {
@@ -933,7 +964,8 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
933964
}
934965

935966
/* Set Sub-sampling ratio and mode */
936-
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE, ((r_ratio << 4) | c_ratio));
967+
ret = video_write_cci_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE,
968+
((drv_data->r_ratio << 4) | drv_data->c_ratio));
937969
if (ret < 0) {
938970
return ret;
939971
}
@@ -954,6 +986,32 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
954986
return 0;
955987
}
956988

989+
static int gc2145_set_crop(const struct device *dev)
990+
{
991+
/* set the crop, start off with most of a duplicate of set resolution */
992+
int ret;
993+
struct gc2145_data *drv_data = dev->data;
994+
995+
/* Calculates the window boundaries to obtain the desired resolution */
996+
if ((drv_data->fmt.width == drv_data->crop.width) &&
997+
(drv_data->fmt.height == drv_data->crop.height)) {
998+
return 0;
999+
}
1000+
1001+
LOG_DBG("set_res: %u %u ratios: %u %u", drv_data->crop.width, drv_data->crop.height,
1002+
drv_data->c_ratio, drv_data->r_ratio);
1003+
ret = gc2145_set_resolution(dev, drv_data->crop.width, drv_data->crop.height, false);
1004+
if (ret == 0) {
1005+
/* enqueue/dequeue depend on this being set as well as the crop */
1006+
drv_data->fmt.width = drv_data->crop.width;
1007+
drv_data->fmt.height = drv_data->crop.height;
1008+
drv_data->fmt.pitch = drv_data->fmt.width
1009+
* video_bits_per_pixel(drv_data->fmt.pixelformat) / BITS_PER_BYTE;
1010+
}
1011+
return ret;
1012+
}
1013+
1014+
9571015
static int gc2145_check_connection(const struct device *dev)
9581016
{
9591017
const struct gc2145_config *cfg = dev->config;
@@ -1057,7 +1115,10 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10571115

10581116
/* Check if camera is capable of handling given format */
10591117
for (int i = 0; i < ARRAY_SIZE(fmts) - 1; i++) {
1060-
if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height &&
1118+
if ((fmts[i].width_min <= fmt->width) &&
1119+
(fmts[i].width_max >= fmt->width) &&
1120+
(fmts[i].height_min <= fmt->height) &&
1121+
(fmts[i].height_max >= fmt->height) &&
10611122
fmts[i].pixelformat == fmt->pixelformat) {
10621123
res = i;
10631124
break;
@@ -1076,7 +1137,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10761137
}
10771138

10781139
/* Set window size */
1079-
ret = gc2145_set_resolution(dev, fmt->width, fmt->height);
1140+
ret = gc2145_set_resolution(dev, fmt->width, fmt->height, true);
10801141

10811142
if (ret < 0) {
10821143
LOG_ERR("Failed to set the resolution");
@@ -1171,12 +1232,60 @@ static int gc2145_set_ctrl(const struct device *dev, uint32_t id)
11711232
}
11721233
}
11731234

1235+
static int gc2145_set_selection(const struct device *dev, struct video_selection *sel)
1236+
{
1237+
LOG_DBG("called: (%p, %p: %u %u)", dev, sel, sel->type, sel->target);
1238+
if (sel->type != VIDEO_BUF_TYPE_OUTPUT) {
1239+
return -EINVAL;
1240+
}
1241+
1242+
struct gc2145_data *drv_data = dev->data;
1243+
1244+
if (sel->target == VIDEO_SEL_TGT_CROP) {
1245+
drv_data->crop = sel->rect;
1246+
return gc2145_set_crop(dev);
1247+
}
1248+
1249+
return -EINVAL;
1250+
}
1251+
1252+
static int gc2145_get_selection(const struct device *dev, struct video_selection *sel)
1253+
{
1254+
LOG_DBG("called: (%p, %p: %u %u)", dev, sel, sel->type, sel->target);
1255+
if (sel->type != VIDEO_BUF_TYPE_OUTPUT) {
1256+
return -EINVAL;
1257+
}
1258+
1259+
struct gc2145_data *drv_data = dev->data;
1260+
1261+
switch (sel->target) {
1262+
case VIDEO_SEL_TGT_COMPOSE:
1263+
case VIDEO_SEL_TGT_CROP:
1264+
sel->rect = drv_data->crop;
1265+
break;
1266+
1267+
case VIDEO_SEL_TGT_NATIVE_SIZE:
1268+
sel->rect.top = 0;
1269+
sel->rect.left = 0;
1270+
sel->rect.width = UXGA_HSIZE / drv_data->c_ratio;
1271+
sel->rect.height = UXGA_VSIZE / drv_data->r_ratio;
1272+
break;
1273+
default:
1274+
return -EINVAL;
1275+
}
1276+
1277+
return 0;
1278+
}
1279+
1280+
11741281
static DEVICE_API(video, gc2145_driver_api) = {
11751282
.set_format = gc2145_set_fmt,
11761283
.get_format = gc2145_get_fmt,
11771284
.get_caps = gc2145_get_caps,
11781285
.set_stream = gc2145_set_stream,
11791286
.set_ctrl = gc2145_set_ctrl,
1287+
.set_selection = gc2145_set_selection,
1288+
.get_selection = gc2145_get_selection,
11801289
};
11811290

11821291
static int gc2145_init_controls(const struct device *dev)
@@ -1214,8 +1323,8 @@ static int gc2145_init(const struct device *dev)
12141323
/* set default/init format VGA RGB565 */
12151324
struct video_format fmt = {
12161325
.pixelformat = VIDEO_PIX_FMT_RGB565,
1217-
.width = RESOLUTION_VGA_W,
1218-
.height = RESOLUTION_VGA_H,
1326+
.width = RESOLUTION_QVGA_W,
1327+
.height = RESOLUTION_QVGA_H,
12191328
};
12201329
int ret;
12211330
const struct gc2145_config *cfg = dev->config;

0 commit comments

Comments
 (0)