Setting fixed focus on the CAM500B from the NanoPI NEO AIR
Posted: Fri Jul 07, 2017 2:45 pm
I'm completely new to all of this, so I apologies if I have missed something obvious.
I'm working on a project where I capture image data from a CAM500B attached to a NanoPi NEO Air. I need to be able to capture the images as quickly as possible so since I know how far away the objects I'm capturing are going to be I would like to set the focus to a fixed length relatively close to the camera. I have been able to disable the autofocus with the following code.
So far so good. This works and the camera stays in a hyperfocal position. (note that xioctl() is just a wrapper around ioctl() that retries). The problems come in when I try to set the focus to a particular value with the following code
The output from these two pieces of code, run in order, is as follows
The interesting thing here is that the call to ioctl with VIDIOC_QUERYCTRL for V4L2_CID_FOCUS_ABSOLUTE seems to indicate that this functionality is available, but when I try to set the focus I get errno set to 22, EINVAL.
I've dumped the name of the driver that my code says this device is using, and it is called "sunxi-vfe". I don't see this name in the friendlyarm git repo anywhere, but I have found it here https://github.com/allwinner-zh/linux-3.4-sunxi/blob/master/drivers/media/video/sunxi-vfe/vfe.c. Looking through the function vidioc_s_ctrl (which I assume is called when I call ioctl(vd->fd, VIDIOC_S_CTRL, &focus_control) in both instances) it looks like if this function forks for V4L2_CID_FOCUS_AUTO it shoudl also work for V4L2_CID_FOCUS_ABSOLUTE.
My distro and kernel are as follows.
I'm working on a project where I capture image data from a CAM500B attached to a NanoPi NEO Air. I need to be able to capture the images as quickly as possible so since I know how far away the objects I'm capturing are going to be I would like to set the focus to a fixed length relatively close to the camera. I have been able to disable the autofocus with the following code.
Code: Select all
struct v4l2_queryctrl focus_vals;
memset(&focus_vals, 0, sizeof(focus_vals));
focus_vals.id = V4L2_CID_FOCUS_AUTO;
if(0 == xioctl(vd->fd, VIDIOC_QUERYCTRL, &focus_vals)){
DBG("V4L2 Got V4L2_CID_FOCUS_AUTO vals %s\n", (focus_vals.flags & V4L2_CTRL_FLAG_DISABLED) ? "DISABLED" : "ENABLED");
}
else{
DBG("V4L2 No V4L2_CID_FOCUS_AUTO valsi errno %d\n", errno);
}
struct v4l2_control focus_control;
memset(&focus_control, 0, sizeof(focus_control));
focus_control.id = V4L2_CID_FOCUS_AUTO;
focus_control.value = 1;
if(0 == xioctl(vd->fd, VIDIOC_S_CTRL, &focus_control)){
DBG("V4L2 Autofocus disabled\n");
}
else{
DBG("V4L2 Autofocus not set\n");
}
So far so good. This works and the camera stays in a hyperfocal position. (note that xioctl() is just a wrapper around ioctl() that retries). The problems come in when I try to set the focus to a particular value with the following code
Code: Select all
memset(&focus_vals, 0, sizeof(focus_vals));
focus_vals.id = V4L2_CID_FOCUS_ABSOLUTE;
if(0 == xioctl(vd->fd, VIDIOC_QUERYCTRL, &focus_vals)){
DBG("V4L2 Got V4L2_CID_FOCUS_ABSOLUTE min %d, max %d\n", focus_vals.minimum, focus_vals.maximum);
}
else{
DBG("V4L2 No V4L2_CID_FOCUS_ABSOLUTE vals errno %d\n", errno);
}
memset(&focus_control, 0, sizeof(focus_control));
focus_control.id = V4L2_CID_FOCUS_ABSOLUTE;
focus_control.value = 50;
int ret =0;
if(0 == (ret =xioctl(vd->fd, VIDIOC_S_CTRL, &focus_control))){
DBG("V4L2 focus level set!!!!!!!!!!\n");
}
else{
DBG("V4L2 focus level not set. Ret: %d errno: %d\n", ret, errno);
}
The output from these two pieces of code, run in order, is as follows
Code: Select all
DBG(v4l2uvc.c, enumerateControls(), 834): V4L2 Got V4L2_CID_FOCUS_AUTO vals ENABLED
DBG(v4l2uvc.c, enumerateControls(), 845): V4L2 Autofocus disabled
DBG(v4l2uvc.c, enumerateControls(), 854): V4L2 Got V4L2_CID_FOCUS_ABSOLUTE min 0, max 127
DBG(v4l2uvc.c, enumerateControls(), 880): V4L2 focus level not set. Ret: -1 errno: 22
The interesting thing here is that the call to ioctl with VIDIOC_QUERYCTRL for V4L2_CID_FOCUS_ABSOLUTE seems to indicate that this functionality is available, but when I try to set the focus I get errno set to 22, EINVAL.
I've dumped the name of the driver that my code says this device is using, and it is called "sunxi-vfe". I don't see this name in the friendlyarm git repo anywhere, but I have found it here https://github.com/allwinner-zh/linux-3.4-sunxi/blob/master/drivers/media/video/sunxi-vfe/vfe.c. Looking through the function vidioc_s_ctrl (which I assume is called when I call ioctl(vd->fd, VIDIOC_S_CTRL, &focus_control) in both instances) it looks like if this function forks for V4L2_CID_FOCUS_AUTO it shoudl also work for V4L2_CID_FOCUS_ABSOLUTE.
My distro and kernel are as follows.
Code: Select all
root@FriendlyARM:~# cat /etc/issue
Ubuntu 16.04.1 LTS \n \l
root@FriendlyARM:~# uname -a
Linux FriendlyARM 3.4.39-h3 #3 SMP PREEMPT Tue Feb 14 15:07:44 CST 2017 armv7l armv7l armv7l GNU/Linux
root@FriendlyARM:~#