I2C bus address confusion controlling autofocus on two IMX219 cameras with CM4

Hi, I’m trying to control the autofocus on two IMX219 motorized cameras attached to a CM4, and I’m confused about which I2C bus actually reaches which camera. I’m using the picamera Python library and create two instances: cam1 = piCamera.PiCamera(camera_num=0) and cam2 = piCamera.PiCamera(camera_num=1), then I start preview for both. From what I found, i2cset -y 0 0x0c dat1 dat2 moves cam1, and i2cset -y 10 0x0c dat1 dat2 moves cam2. But after repeated use the bus seems to switch: the command I thought was for cam1 (bus 0) starts moving cam2. Does the I2C address (0x0c) change while the preview is running? The GitHub example I found uses arducam_vcm.choose_channel and only creates one picamera object without specifying a camera number, so that doesn’t match what I’m doing.

The 0x0c address is hardcoded in the sensor firmware, so it doesn’t change during preview. What changes is the I2C bus number assigned to each PiCamera instance. When you create multiple PiCamera() objects, the first instance gets bus 0, the second gets bus 10, and so on. So bus 0 talks to the first instance (cam1) regardless of the camera_num you passed, and bus 10 talks to the second instance (cam2), again regardless of camera_num. Keep track of which bus belongs to which camera instance and always use that bus: i2cset -y 0 0x0c for cam1 and i2cset -y 10 0x0c for cam2. The switching you saw happens because the i2cset call changes the bus number associated with that camera instance, so repeated calls against different buses make the mapping appear to drift.

Thanks, but I’m still seeing the switch. Right after I start, bus 0 moves cam1 and bus 10 moves cam2. Then on subsequent calls bus 0 moves cam2 and bus 10 moves cam1. What could make the bus address switch dynamically like that? Also, I’m running these cameras through an HDMI to CSI Arducam extender — does that extender still pass I2C control through?

That is strange. Could you record a short clip showing the exact sequence (bus 0, then bus 10, then bus 0 again) so I can see which camera moves each time? Also let me know which OS image you’re on (Buster or Bullseye) and how your preview program is structured — for example, whether you create both PiCamera objects once and keep them open while running those i2cset commands.

Here’s a clip: IMG_7776.MOV at https://drive.google.com/file/d/1h0cFFEESHlCthrJHDXSKs_Zz8R-h4aDL/view?usp=drive_web . I’m on a CM4 running Buster, and I have a tkinter program that opens two preview windows, one for each attached camera. In the video, i2cset -y 0 changes camera 1 focus, then i2cset -y 10 does nothing, then i2cset -y 0 again changes the 2nd camera. The HDMI cable works for the i2c commands otherwise. Is this a Buster vs Bullseye issue?

Thanks for the video, that’s very helpful. I can see exactly what you mean: bus 0 moves cam1, bus 10 does nothing, then bus 0 moves cam2. I want to reproduce this on our side, so let me test it next week and get back to you.

Just checking in — any findings on why the same bus number ends up hitting different cameras? I’d really like to control both focus motors independently if that’s possible.

Sorry for the delay. I dug into how the CM4 CSI interfaces work. It turns out both CSI interfaces share the same I2C controller, and the driver implements dynamic remapping to switch between CSI0 and CSI1. That’s why the same bus number can address different cameras on successive calls: calling i2cset -y 0 can move the first camera’s motor, and then calling i2cset -y 0 again can move the second camera’s motor. So it’s not really a Buster vs Bullseye thing — it’s the shared controller remapping between the two interfaces. Getting fully independent control would need an evaluation and customization of the motor driver, which isn’t a trivial change.

Got it, so manual i2c focus on both cameras is basically unreliable with this setup. Is there any workaround, or do I need to drop focus control from my script entirely?

One thing to try is moving to Bullseye OS. Arducam has added continuous autofocus for the IMX219 motorized focus module, so you don’t need to drive the focus over i2c manually at all. There’s a quick-start guide here: Quick start - Arducam Wiki . That’s probably the cleaner path if manual i2c control keeps fighting the driver remapping.