System designTroubleshooting

Sensor captures raw with v4l2-ctl but nvarguscamerasrc finds no camera

v4l2-ctl streams clean Bayer frames but nvarguscamerasrc finds no camera. Split the kernel and ISP paths, fix the device-tree bus match, size the CSI-2 link.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01Two capture paths, and only one was tested
  2. 02Likely causes, in order of probability
  3. 03Confirm the kernel layer, then leave it alone
  4. 04Fix the bus match in the device tree
  5. 05Worked example: CSI-2 payload for an 820 × 846 BGGR 10-bit sensor at 30 fps
  6. 06Run the ISP-path test with caps that can succeed
  7. 07When the sensor should skip the ISP entirely
  8. 08Bring-up order that keeps the layers provable
  9. 09Questions

Your sensor probes cleanly, dmesg settles, and v4l2-ctl hands you perfect raw Bayer frames. Then nvarguscamerasrc — or nvgstcapture-1.0 on top of it — insists there is no camera. Nothing about the hardware changed between those two commands; what changed is which layer you asked. Raw capture exercises the kernel driver. The ISP path walks the device-tree camera graph and binds the sensor itself, and it never looks at /dev/video0. Here you get the split between the two paths, the bus-match fix in the device tree that resolves this exact symptom, a worked CSI-2 bandwidth check that rules the link out, and a bring-up order that keeps the two layers provable.

Two capture paths, and only one was tested

On an embedded ARM board with an on-chip ISP, one sensor reaches you through two different stacks.

The kernel path: the sensor driver probes over I2C, registers a V4L2 device, and /dev/video0 appears. v4l2-ctl and a v4l2src element read that node directly — capturing raw Bayer frames with v4l2-ctl is precisely this path. It works as soon as the driver probes and its format list is right.

The ISP path: nvarguscamerasrc and nvgstcapture-1.0 sit on libargus, and libargus does not scan V4L2 device nodes. It enumerates the sensors declared in the device-tree camera graph, and it accepts raw Bayer sensors only, because the ISP debayers, white-balances and denoises in hardware — operations that only mean something on raw input. A YUV or RGB sensor has no place on this path; what raw sensor output means on a CSI camera with no ISP covers that distinction.

So one command can succeed while the other finds nothing, and both are telling the truth about their own layer. The fault to hunt is not in the driver — it is in the graph the ISP consumer reads.

Likely causes, in order of probability

When raw capture works and the plugin does not, work the table top down. Row 1 is the cause this symptom most often resolves to: the camera node in the device tree naming a different I2C node than the one the sensor physically hangs from.

Order What is wrong Test Fix
1 Camera node's bus designation names the wrong I2C node Compare the bus number in the dmesg probe line with the bus the camera node names Point both at the same I2C controller, rebuild the DTB, reboot
2 Sensor outputs YUV or RGB, not raw Bayer Read the pixel order in the v4l2-ctl --list-formats-ext output Skip the ISP path; capture with v4l2src
3 Requested mode is not declared Match the caps' width, height and framerate against the declared sensor modes Request a listed mode and select it with sensor-mode
4 Wrong camera index Re-run with sensor-id=0 and every other camera detached Set sensor-id to the index that holds your sensor
5 Sensor's ISP tuning file never installed Check the driver package's install output for its tuning step Install the package's ISP tuning file as its instructions give

All five faults live above the driver. That is why fixing the driver cannot help.

Confirm the kernel layer, then leave it alone

Run the format probe first:

v4l2-ctl -d /dev/video0 --list-formats-ext

You want the raw Bayer entry with your pixel order — BGGR at 10 bits in the case this guide works from — and the active sizes the driver exposes. Save the kernel log beside it (dmesg > klogs.txt is enough) so every later failure reads against a known-good baseline.

Fix the bus match in the device tree

Row 1 deserves its own section because it fails quietly: no error, a happy driver, and still no camera.

The camera's node in the device tree carries a designation that says which I2C bus the sensor hangs from. The driver's probe line in dmesg names the bus number and the 7-bit address it actually bound to. The two must agree, because libargus finds sensors through the device-tree graph, not through the V4L2 device list. A camera node that names the wrong I2C controller leaves the ISP consumer with an empty camera list while /dev/video0 keeps streaming.

  1. Read the probe line: note the I2C bus number and the 7-bit address where the driver bound.
  2. Open the camera node in your device-tree source and read the bus it names.
  3. Set the node to name the same I2C controller the sensor is wired to.
  4. Rebuild the DTB, install it, reboot.
  5. Re-run the plugin test from the ISP-path section below.

When node and driver agree, libargus attaches the sensor and nvgstcapture-1.0 captures a normal stream. If your edit never reaches the running system, that is a build-and-install problem, not a binding problem — the device-tree and DTB mismatch checks walk that path.

Worked example: CSI-2 payload for an 820 × 846 BGGR 10-bit sensor at 30 fps

Inputs, each with its source:

  • Active pixels 820 × 846 — the size the driver's format list reports and the size of the raw capture in this case.
  • Raw Bayer, BGGR order, 10 bits per pixel, packed — the sensor's output format, so four pixels travel in five bytes.
  • 30 frames per second — the framerate the test pipeline requests.

The rule in words: packed 10-bit raw spends five bytes on every four pixels, so bytes per frame is width × height × 5/4, and the payload rate is frame size × framerate.

bytes per frame = width × height × 5 / 4 payload rate = bytes per frame × framerate

Arithmetic, step by step:

  • 820 × 846 = 693,720 pixels per frame.
  • 693,720 × 5 / 4 = 866,150 bytes per frame, about 846 KiB.
  • 866,150 × 30 = 25,984,500 bytes per second, about 24.8 MiB/s, or roughly 208 Mbit/s of payload.

Now the link. CSI-2 lanes on these SoCs run on D-PHY, whose high-speed rate per lane commonly sits between 80 Mbit/s and 1.5 Gbit/s; plan on about 80 percent of the lane-rate total surviving as payload after packet headers and line overhead — a standard planning figure. Two lanes at a modest 800 Mbit/s each therefore carry 2 × 800 × 0.8 = 1,280 Mbit/s of usable payload.

Decision: 1,280 Mbit/s against a 208 Mbit/s need is about six times headroom, so bandwidth cannot be why the plugin finds no camera. A link that genuinely cannot keep up produces short or torn frames — the short-frame failure mode — and that symptom shows up on the raw path too. If your only complaint is no camera from the plugin, stay on the binding and the declared mode list.

Run the ISP-path test with caps that can succeed

With the binding fixed, test the plugin in the form that isolates framerate without a display:

gst-launch-1.0 nvarguscamerasrc sensor-id=0 sensor-mode=0 ! 'video/x-raw(memory:NVMM),width=1920, height=1080, framerate=30/1, format=NV12' ! nvvidconv ! fpsdisplaysink text-overlay=0 name=sink_0 video-sink=fakesink sync=0 -v

The width, height and framerate in those caps are the sample pipeline's values, not a target. Set them to a mode your --list-formats-ext output listed, and pick that mode with sensor-mode. fpsdisplaysink prints the achieved framerate straight to the terminal, so one run tells you whether the ISP path delivers.

Keep a second terminal on dmesg while it runs: when the plugin fails, the kernel side usually records which node it tried to open.

sensor-id selects among cameras, so with a USB webcam also attached it can point at the wrong one and look exactly like a missing camera — that index mix-up has its own write-up.

When the sensor should skip the ISP entirely

Two situations make the whole binding exercise unnecessary.

The sensor outputs YUV or RGB. libargus takes raw Bayer only, so there is nothing to repair — capture with v4l2src or v4l2-ctl and convert in your pipeline if the application wants NV12 or RGB at the end.

You want the raw data anyway. If your algorithm does its own debayering, flat-field correction or HDR stacking — common in measurement work — the ISP's corrections are something you would have to undo. Take the Bayer stream from the kernel path and process it yourself.

And if you are picking hardware for a new build and would rather not touch a device-tree camera graph at all, a USB3 board camera keeps the kernel path as the only path: no camera graph, no ISP tuning file, no binding to get wrong. Two examples from the range.

The LS-BCM-0003 is a 3.1 MP USB3 board-level camera with a 1/1.8" global-shutter sensor, streaming at 120 fps.

Board-level cameras3.1 MP USB3 board-level camera, IMX252, 1/1.8" global shutter, 120 fps (LS-BCM-0003)LS-BCM-0003
Sensor format
1/1.8"
Lens mount
C-mount
Interface
USB3
Resolution
5 MP
$690.00View partBuild a system with it

The MV-CB060-10UM-B is a 6 MP bare board on USB3 with a rolling shutter, for builds where you make the housing yourself.

Board-level camerasHikrobot MV-CB060-10UM-B 6 MP Board Level Camera, USB3, IMX178, Mono, Bare Board, V4MV-CB060-10UM-B
Sensor format
1/1.8"
Interface
USB3
Resolution
6-10 MP
Shutter
Rolling
$239.00View partBuild a system with it

Browse the rest in the board-level cameras category, or filter by interface, shutter and format in the camera finder.

Bring-up order that keeps the layers provable

Run every new sensor module through the same order; each step gates the next one.

  1. Rails and levels: confirm the module's supply and logic levels before anything deeper — a module on the wrong rail powers up and still misbehaves, and why some camera modules work at 5 V but not at 3.3 V is the classic form of that failure.
  2. Probe: dmesg shows the driver bound at the I2C bus number and 7-bit address you actually wired.
  3. Formats: --list-formats-ext lists the raw Bayer entry and the active sizes.
  4. Raw frames: pull a short capture with v4l2-ctl and check the frames change over time.
  5. Graph: set the camera node's bus designation to that same I2C bus, rebuild the DTB, reboot.
  6. ISP tuning: install the tuning file the sensor driver's package provides, before the first plugin run.
  7. Plugin test with caps matched to a declared mode and sensor-mode set.
  8. Only then build the application pipeline on top.

Steps 1-4 prove the sensor. Steps 5-7 prove the consumer. When a symptom appears later, one run tells you which half to blame.

If the diagnosis ends at row 2 — the part was never a raw Bayer sensor — or the binding work is not worth it for a new build, choose hardware that matches the path you want: the area scan cameras category covers the standard interfaces, and the system configurator walks camera, lens and light in order. The surrounding integration topics live on the systems topic page.

Questions

Why does v4l2-ctl work but nvarguscamerasrc report no camera?

They are different layers. v4l2-ctl talks to the sensor's kernel driver through /dev/video0, so any probing driver streams raw frames. nvarguscamerasrc and nvgstcapture-1.0 run on libargus and the ISP, which enumerate cameras from the device-tree camera graph instead of V4L2 nodes. If the camera node's bus designation names a different I2C node than the sensor sits on, libargus binds nothing and reports no camera while /dev/video0 keeps working.

Which sensors can the ISP capture path handle?

Raw Bayer output only — for example BGGR at 10 bits. The ISP consumes the raw stream and performs debayering, white balance and denoise in hardware before handing frames to the plugin. A sensor that outputs YUV or RGB gains nothing from this path: capture it with v4l2src in a plain pipeline and convert there. If you process raw Bayer yourself, the kernel path alone is already enough.

How do I check which I2C bus my sensor really sits on?

Read the kernel probe line: dmesg names the I2C bus number and the 7-bit address the driver bound to. Compare that bus number with the bus designation inside the camera's device-tree node. When the two differ, the ISP consumer never finds the sensor even though raw capture works. Make the node name the same bus, rebuild the DTB, reboot, and re-run the plugin test.

What caps should the nvarguscamerasrc pipeline request?

Only values a declared sensor mode can deliver. List the driver's modes with v4l2-ctl -d /dev/video0 --list-formats-ext, set width, height and framerate in the caps to one listed mode, and select that mode with sensor-mode. Requesting a size no mode declares fails on its own, and with more than one camera attached, sensor-id picks the index — set it deliberately.

How much CSI-2 bandwidth does an 820 × 846 10-bit sensor need at 30 fps?

693,720 pixels per frame; packed 10-bit carries four pixels in five bytes, so one frame is 866,150 bytes, about 846 KiB. At 30 fps the payload is about 24.8 MiB/s, roughly 208 Mbit/s. Two lanes at 800 Mbit/s carry about 1,280 Mbit/s usable — six times the need. If frames still come back short, suspect the mode declaration, not the link.