Motorized Focus Camera script fails with libcamera v4l2 control confusion

Hi, hoping someone can help me sort out manual focus control. I’m running the script I was given and it keeps failing — error screenshot attached. What’s throwing me off is that I was told there’s been a change in libcamera, that it’s no longer from /dev/video*, so the control of v4l2 is no longer used. But the script I have relies on v4l2 control. So which approach is actually the correct way to control the device? I feel like I’m going in circles.

Hi, welcome. To get to the bottom of this I need a bit more detail so we’re comparing the same thing:

  • Exact camera model and which driver you installed
  • OS / board you’re on
  • The exact commands you ran and the full error output
  • Which script file/version you’re using (path + where you got it from)

Also, if you can, tell me what’s in your /boot/config.txt and whether you enabled i2c there and rebooted. Let’s start from there.

Sure. Camera is an ArduCAM 64MP, board is Raspberry Pi 4, driver installed is 64mp_pi_hawk_eye_kernel_driver. libcamera is no longer from /dev/video*.

What I’ve tried so far:

  1. I followed the example at RaspberryPi/Motorized_Focus_Camera at master · ArduCAM/RaspberryPi · GitHub (the libcamera-based manual focus control one). Ran the suggested command and it fails with the address error below.
  2. I ran the switch-channel commands I was given earlier. After running the “switch channel” command I can no longer use libcamera-still to take photos at all.

Errors I’m seeing:

Error: Could not set address to 0x0c: Device or resource busy
Failed to start streaming: Input/output error
ERROR: *** failed to start camera ***

Here’s the channel switching code I was given earlier:

# Set to single channel 0
i2cset -y 10 0x0c 0x02 0x00
# Set to single channel 1
i2cset -y 10 0 0x24 0 0x24 0 0x12
# Set to single channel 2
i2cset -y 10 0 0x24 0 0x24 0 0x22
# Set to single channel 3
i2cset -y 10 0 0x24 0 0x24 0 0x32
# Set to double channel (single channel 0 and single channel 1)
i2cset -y 10 0 0x24 0 0x24 0 0x01
# Set to double channel (single channel 2 and single channel 3)
i2cset -y 10 0 0x24 0 0x24 0 0x11
# Set to four in one mode (Default)
i2cset -y 10 0 0x24 0 0x24 0 0x00

Thanks, that helps. First thing: the directories and scripts you’re running don’t look consistent with the ones in the link I sent you. Before we test anything else, please make sure you’re running exactly the script from the linked page — same directory, same file — because mismatched versions will behave differently.

Also two things to try:

  1. Set the camera to its LOWEST resolution and test. That tells us whether there’s a basic streaming issue with the camera itself, separate from focus.
  2. Confirm the i2c-enabling step was done in /boot/config.txt, then reboot. That step is what actually enables i2c and it won’t take effect until you reboot.

If it still misbehaves after that, we can set up a remote session next week to look at it together.

I double-checked the script against the linked page and it looks the same to me, but let me put everything on the table in one place.

I attached a screenshot of the manual showing how to control the focus of the ArduCAM. The script referenced in the manual is Arducam-Pivariety-V4L2-Driver/focus at master · ArduCAM/Arducam-Pivariety-V4L2-Driver · GitHub — can you verify we’re on the same page here?

I then tried manual focus control two ways:

  1. With v4l2-ctl: v4l2-ctl -l does not list the required focus_absolute control, and it shows no error at all, even in verbose mode.
  2. Following Arducam’s focuser example: the program throws OSError: [Errno 25] Inappropriate ioctl for device while executing fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl).

One positive note: the camera CAN auto-focus itself via libcamera-still --autofocus, so the camera itself works.

So my errors are now:

Error: Could not set address to 0x0c: Device or resource busy
Failed to start streaming: Input/output error
ERROR: *** failed to start camera ***
OSError: [Errno 25] Inappropriate ioctl for device

Still stuck on which control path is correct.

One more thing I forgot to mention: during the driver install, PrintCamera has no value stored. Could that be related?

Also confirming the bus I keep using is 10 — same as in the driver installer (install_privariety_pkgs.sh). And the Error: Could not set address to 0x0c: Device or resource busy also happens when I run i2cset -y 10 0x0c 0x02 0x00, even after running the script so the required config is written into /boot/config.txt. So the config is in there but I still get the busy error.

OK, there’s clearly something off in the config too. Let’s gather diagnostics — I need to see the state of the system, because “Device or resource busy” on i2c address 0x0c usually means the bus/resource is occupied or not correctly enabled/configured.

Please do the following and paste the output:

  1. Identify which program is running / holding the bus (so we know what’s occupying it).
  2. Run cat /boot/config.txt and paste the full contents.
  3. Check dmesg for any messages that confirm i2c was installed/initialized correctly.
  4. Then do the i2c-enabling step in config.txt, reboot, and retry.

Screenshot of any error message is fine too.

Here’s what I’ve got.

cat /boot/config.txt — I’ve attached the file, but the relevant part is that the i2c line is there. I did the enabling step and rebooted.

After reboot, I still get the same Device or resource busy when running i2cset -y 10 0x0c 0x02 0x00.

On dmesg: I looked through it and I can’t see anything that clearly confirms i2c is up the way it should be — nothing obvious about the 64MP driver initializing the bus.

I also tried to figure out which program is holding the bus but I’m not sure what I’m looking for there.

Got it. Here’s where I think things stand.

The root cause isn’t confirmed yet, but the Device or resource busy on i2c 0x0c strongly points to the i2c bus/resource being occupied or not enabled/configured correctly — it’s a separate symptom from the focus question. So I’d stop chasing the focus methods until the bus behaves.

There’s also a real inconsistency between the two things you’ve been told: on one hand, libcamera changed so v4l2 (/dev/video*) control is no longer used and you should use libcamera; on the other hand, the supplied script you were given relies on v4l2 control. That’s worth clearing up, because they can’t both be the way forward.

Let’s narrow it down: confirm the scripts match the linked doc exactly, run at the lowest resolution to rule out the camera/streaming, do the config.txt i2c step + reboot, then retry. If it’s still bad after that, let’s book the remote session next week.

Before we do the remote session, can you settle the libcamera vs v4l2 question? You said there’s been a change in libcamera — it’s no longer from /dev/video*, so v4l2 control is no longer used, and you need to use libcamera to control focus, and that Arducam wrote a program using libcamera for manual focus. But the script I was given relies on v4l2 control.

So which is it? Do I use libcamera or v4l2 for focus? Because right now the instructions contradict the script and I don’t know which one to follow.

Fair point, let me lay it out clearly:

  • The current libcamera stack moved away from /dev/video*, so v4l2-based control is no longer the path for focus. For manual focus you should be using the libcamera-based approach — Arducam provides a program for exactly that.
  • The v4l2 route (v4l2-ctl / the V4L2 ioctl focuser example) is likely to keep failing in your current setup, which matches what you’re seeing: no focus_absolute control, and OSError: [Errno 25] Inappropriate ioctl for device.
  • The v4l2-based script you were given appears inconsistent with that newer guidance, which is part of the confusion here.

The fact that libcamera-still --autofocus works tells us the camera hardware and libcamera path are fine — it’s the control method and the i2c/bus state that are the problem.

OK that makes more sense. So to summarize what I’ll do:

  • Stop using the v4l2 focuser path (no focus_absolute, Errno 25 ioctl error).
  • Use the libcamera-based manual focus approach, since autofocus already works via libcamera-still --autofocus.
  • Make sure the script/directory matches the linked doc exactly.
  • Test at lowest resolution to rule out a streaming problem.
  • Sort out the i2c bus so I stop getting Could not set address to 0x0c: Device or resource busy.

Is that right? And I still can’t take photos after the channel-switch command — Failed to start streaming: Input/output error and ERROR: *** failed to start camera *** — so I’ll avoid running the channel-switch code until we figure out the bus.

That summary is correct. Quick recap so it’s all in one place for anyone following this thread:

For the i2c issue: do the config.txt i2c-enabling step, reboot, then retry i2cset -y 10 0x0c 0x02 0x00. If you still get Device or resource busy, the bus/resource is occupied or not configured right — that’s not something we can fix from here without a closer look.

Test the lowest resolution first to rule out camera/streaming problems. If it still doesn’t work after all this, we’ll set up a remote session so we can look at it together. I’ve sent the remote session details to you privately — check your messages.

Note for channel switching, make sure you’re using the correct form:

# Set to single channel 0
i2cset -y 10 0x24 0x24 0x02
# Set to single channel 1
i2cset -y 10 0x24 0x24 0x12
# Set to single channel 2
i2cset -y 10 0x24 0x24 0x22
# Set to single channel 3
i2cset -y 10 0x24 0x24 0x32
# Set to double channel (single channel 0 and single channel 1)
i2cset -y 10 0x24 0x24 0x01
# Set to double channel (single channel 2 and single channel 3)
i2cset -y 10 0x24 0x24 0x11
# Set to four in one mode (Default)
i2cset -y 10 0x24 0x24 0x00

Bottom line: the root cause of the i2c Device or resource busy is still unconfirmed — everything points to the bus being occupied or not enabled/configured correctly. The camera itself is fine (autofocus works), so our action plan is: match the documented script, test at lowest resolution, fix the i2c/config state, and pick up the remote session if it’s still failing.