CamArray OV9281 stereo camera no frames on Jetson while B0579 works fine

Hey everyone, hoping someone here has run into this before. I’m trying to get a B0579 and a CamArray OV9281 stereo hat streaming simultaneously on a Jetson Orin Nano dev kit, and I’m hitting a wall.

Setup:

  • Jetson Linux L4T R36.4.7 (JetPack 6.x), kernel variant: oot
  • CSI CAM1: Arducam B0579
  • CSI CAM0: Arducam CamArray stereo hat (dual OV9281, single CSI cable, expected output: side-by-side 2560x800)
  • Arducam 4-lane CSI driver package installed (dual-CSI)

The B0579 works perfectly on its own, no issues at all. The CamArray enumerates fine - /dev/video* nodes show up, formats are listed - but it produces zero video frames. Running v4l2-ctl --stream on the CamArray just gives a select timeout. GStreamer complains: “No input source detected – video frames invalid.”

The CamArray’s red LED stays on (so power seems OK), and the green LED flickers briefly during init but never stays active during streaming. It’s like the OV9281 sensors get partially initialized but never actually enter continuous streaming mode.

Anyone managed to get these two running side by side? Feels like a driver conflict but I’m not sure where to start.

This is a known pain point, unfortunately. The B0579 and the CamArray OV9281 rely on different driver backend configurations. With the standard Arducam package, you can’t have both drivers installed at the same time - they overwrite each other’s kernel dependencies during installation.

On top of that, there’s no pre-built device tree overlay that combines a B0579 and a CamArray OV9281. Making them coexist on the same CSI subsystem would require compiling a custom kernel with a merged device tree, which is not trivial.

The practical workaround here is to offload one of the cameras to USB. Something like a UVC global shutter module (e.g., the 2.3MP USB2.0 UVC global shutter camera from UCTRONICS with onboard ISP) can stream alongside the MIPI camera without conflict since they’re on completely separate hardware buses. USB + MIPI works fine simultaneously.

Fair warning though: hardware frame-level sync between USB and MIPI is not supported. If you need tight synchronization, that could be a problem.

Thanks for the quick reply. A couple of questions before I go the USB route:

  1. What if I swap the B0579 for a CSI color camera that uses the same driver backend as the CamArray? Would that avoid the driver conflict?

  2. Alternatively, what if I move the B0579 to USB and keep the CamArray on CSI?

  3. What does the paid customization service for the merged device tree actually cost, ballpark? This is for a startup prototype and we’d consider it if it’s reasonable.

Good questions. Let me address each:

On swapping to a different CSI color camera: Unfortunately, this won’t solve the problem. Any decent CSI color camera will need its own dedicated MIPI driver. The Jetson system can’t load that driver AND the CamArray/OV9281 driver simultaneously. You’d just be swapping one conflict for another - the underlying issue is that the platform can’t host two different MIPI sensor drivers at once with the standard package.

Moving B0579 to USB: That’s the direction I’d recommend. Keep the CamArray on CSI and put your color/other camera on USB. This is the cleanest separation.

On the customization cost: Honestly, the engineering fees for custom driver/device tree work usually exceed the hardware cost itself by a significant margin. For single-unit or small-batch projects it rarely makes financial sense. It’s really intended for volume production scenarios.

We’re a startup and we do plan to scale beyond a single prototype. Even if the upfront cost is high, I’d like to get a proper estimate for custom driver development to make the B0579 and CamArray work together on the same board. Can your engineering team take a look and give me a number?

So I took this back to the engineering team for a proper review, and I need to issue a pretty important correction here - this goes deeper than just a driver conflict.

There is a fundamental hardware limitation on the Jetson Orin platform that prevents this configuration entirely:

Both the B0579 camera and the CamArray OV9281 stereo kit require the primary CSI port - the one located next to the power jack - to function. They physically cannot be connected and operate at the same time because they’re competing for the same hardware interface.

This is not something a custom driver or device tree can work around. Software cannot overcome the physical CSI port mapping on the carrier board. Running both simultaneously on the Jetson Orin NX/Nano is simply not possible at the hardware level.

That’s… sobering, but really helpful to know before we went further down that path. A few follow-ups:

Is this limitation specific to the Orin NX/Nano developer kit carrier board (CSI lane routing, connector mapping, fixed resource assignment), or is it a fundamental limitation of the SoC itself?

Hypothetically, if we designed a custom carrier board that routes multiple CSI ports differently, could the system handle three identical monochrome cameras - all OV9281 sensors?

Any chance you can point me to NVIDIA reference docs - block diagrams, CSI/VI allocation notes, carrier board design constraints - so I can understand the hardware limits better?

Good questions. There are actually two separate layers of complexity here, so let me break them down:

1. ‘Single Instance’ Hardware Limit
The core issue is the specific CSI routing on the Orin Nano Developer Kit combined with the Jetvariety driver architecture. The system architecture supports only ONE active Jetvariety camera per board. If you try to instantiate a second Jetvariety pipeline, the CSI routing resources collide. This is tied to how the dev kit carrier board maps its CSI lanes, but it’s also baked into how the Jetvariety stack expects resources.

2. Driver & Device Tree Conflict
Even setting aside the hardware routing, the B0579 and CamArray OV9281 use distinct driver parameters. Standard kernels don’t support mixing these two different sensor definitions. You’d need a fully custom device tree regardless.

As for reference docs, NVIDIA’s TRM (Technical Reference Manual) for the Orin series covers the CSI/VI subsystem in detail. The Jetson Orin Nano Design Guide also covers carrier board CSI routing constraints. I can send you some relevant links via PM.

Bottom line though: given these routing constraints and driver mismatches, USB remains the only viable off-the-shelf option for adding a third or different camera stream.

One more idea before I give up on all-CSI. What about using a third camera that’s identical to the ones on the CamArray - a single OV9281 (mono, same sensor type) alongside the existing CamArray stereo hat? Since they’d all be the same driver stack, would that sidestep the conflict?

I checked this specifically with the team, and unfortunately the answer is still no. Both the single OV9281 and the stereo CamArray OV9281 use the Jetvariety driver stack, so they hit the exact same hardware restriction:

On the Jetson Orin Nano, Jetvariety-based cameras only function when connected to the specific CSI port closest to the power supply. The second CSI port simply cannot host a Jetvariety device, period. It doesn’t matter whether it’s a single or stereo variant - the port restriction applies to the entire Jetvariety family on this board.

USB really is the path of least resistance here. Happy to help spec out a suitable UVC module if you want to go that route.

OK, I’m convinced. I’ll pick up a B&W USB global shutter camera to pair with the CamArray. Thanks for saving me from going down the custom driver rabbit hole.

Switching topics slightly - I have a separate issue with the B0579 that I need to sort out. I’m using it for Visual Inertial Odometry and I need to control the shutter speed to avoid motion blur, but I can’t find any documentation on how to set it. The usual v4l2-ctl exposure controls don’t seem to behave the way I’d expect. Any pointers?

For the B0579, exposure control should be accessible through the standard v4l2-ctl interface. Try this:

First, list all available controls to identify the exposure parameter:

v4l2-ctl -d 0 -l

Look for ‘exposure’ in the output. Then set it:

v4l2-ctl -d 0 -c exposure=500

For shorter exposure (less motion blur), try lower values:

v4l2-ctl -d 0 -c exposure=100

Let me know what you see in the controls list - that’ll help narrow things down.

I already tried that, and that’s why I’m confused. The exposure control shows up as a boolean (min=0 max=1), which looks like it’s just an auto/manual toggle, not an actual shutter speed value. Here’s the full control list from v4l2-ctl -d /dev/video0 --list-ctrls:

User Controls:
  brightness 0x00980900 (int): min=0 max=33000 step=1 default=33000 value=33000 flags=slider
  contrast 0x00980901 (int): min=0 max=4 step=1 default=2 value=2 flags=slider
  saturation 0x00980902 (int): min=0 max=4 step=1 default=2 value=2 flags=slider
  exposure 0x00980911 (int): min=0 max=1 step=1 default=1 value=1
  gain 0x00980913 (int): min=0 max=16 step=1 default=0 value=0
  horizontal_flip 0x00980914 (bool): default=0 value=0
  vertical_flip 0x00980915 (bool): default=0 value=0
  sharpness 0x0098091b (int): min=0 max=6 step=1 default=3 value=3 flags=slider
  disable_frame_timeout 0x00981902 (bool): default=0 value=0
  frame_timeout 0x00981903 (int): min=100 max=12000 step=1 default=2000 value=2000
  frame_rate 0x00981906 (int): min=1 max=30 step=1 default=30 value=30

Camera Controls:
  error 22 getting ext_ctrl Sensor configuration
  error 22 getting ext_ctrl Sensor mode I2C packet
  error 22 getting ext_ctrl Sensor control I2C packet
  bypass_mode 0x009a2064 (intmenu): min=0 max=1 default=0 value=0
  override_enable 0x009a2065 (intmenu): min=0 max=1 default=0 value=0
  height_align 0x009a2066 (int): min=1 max=16 step=1 default=1 value=1
  size_align 0x009a2067 (intmenu): min=0 max=2 default=0 value=0
  write_isp_format 0x009a2068 (int): min=1 max=1 step=1 default=1 value=1
  sensor_signal_properties 0x009a2069 (u32): dims=[30][18] flags=read-only, has-payload
  sensor_image_properties 0x009a206a (u32): dims=[30][16] flags=read-only, has-payload
  sensor_control_properties 0x009a206b (u32): dims=[30][36] flags=read-only, has-payload
  sensor_dv_timings 0x009a206c (u32): dims=[30][16] flags=read-only, has-payload
  low_latency_mode 0x009a206d (bool): default=0 value=0
  preferred_stride 0x009a206e (int): min=0 max=65535 step=1 default=0 value=0
  override_capture_timeout_ms 0x009a206f (int): min=-1 max=2147483647 step=1 default=2500 value=2500
  sensor_modes 0x009a2082 (int): min=0 max=30 step=1 default=30 value=1 flags=read-only

See what I mean? exposure at 0x00980911 has min=0 max=1 - that’s a switch, not a shutter speed. And I don’t see any other control that looks like it maps to shutter duration. Am I missing something obvious?

You’re right, that definitely looks like a boolean toggle and not an exposure value control. Let me have engineering take a closer look at the firmware - there may be something non-standard about how the B0579 exposes its shutter control. We might need to generate a firmware update tool to fix the control mapping.

I’ll follow up once I have something concrete. This might take until tomorrow - I’ll send any files via PM.

Alright, after digging into the source code while we were preparing the firmware tool, we actually found a much simpler workaround - no firmware update needed at all.

Here’s what’s going on in the current B0579 firmware:

  • exposure (0x00980911, min=0 max=1) is indeed a boolean. It toggles between auto exposure (1) and manual exposure (0). It is NOT a shutter speed value.

  • brightness (0x00980900, min=0 max=33000) is actually mapped internally as the manual shutter speed control. Despite the label saying “brightness”, that’s the register you want for setting exposure time.

So for your VIO use case, here’s how to lock exposure and control shutter speed:

# 1. Switch to manual exposure mode:
v4l2-ctl -d 0 -c exposure=0

# 2. Set shutter speed via the brightness control:
v4l2-ctl -d 0 -c brightness=5000    # moderate exposure
v4l2-ctl -d 0 -c brightness=500     # very short exposure for fast motion

Lower brightness = shorter shutter = less motion blur (but darker image). Start around 5000 and tune down until you get acceptable blur, then compensate with gain if needed:

v4l2-ctl -d 0 -c gain=8   # gain range is 0-16

Not the most intuitive naming convention, but it should get you unblocked without waiting for a firmware update.