3D visionTroubleshooting

Depth stream waiting on ARM Linux: bandwidth and driver checks

Color and IMU stream, but depth sits waiting on your ARM Linux board? Size the USB budget, prove SuperSpeed negotiation and free the depth endpoints.

LumaSpec Vision10 min read Share on LinkedIn

On this page 8 sections
  1. 01What this fault looks like
  2. 02Likely causes, in the order to suspect them
  3. 03The bandwidth rule that decides it
  4. 04Worked example: a 1280 x 720 depth and IR pair at 30 fps
  5. 05Prove the link speed, then fix the transport
  6. 06Keep the kernel UVC driver off the depth endpoints
  7. 07Shrink the stream when the link really is USB 2.0
  8. 08Questions

The color window updates, the IMU values roll in, and the depth tool prints the same line every second: waiting for frames. The camera streamed fine on a desktop Windows machine, so the hardware itself works. On the ARM board running Linux, the depth and IR endpoints are almost never getting the transport they need, and the two usual reasons are a link that fell back to USB 2.0 speed and a driver holding the endpoint the SDK wants. You will size the bandwidth the streams need, see the arithmetic that rules USB 2.0 out at 720p30, prove which speed the port actually negotiated, and then free the depth endpoints and shrink the stream if the link really is high-speed only.

What this fault looks like

The SDK opens the device, reads back IR gain and exposure without complaint, starts the color stream and draws it, then sits on the depth request. Nothing errors; there is simply no first frame. That silence is the signature, and it separates this fault from three neighbors you may actually have:

If your symptom is the first shape — color fine, depth waiting, properties syncing — stay here. The cause is transport, in the order below.

Likely causes, in the order to suspect them

  1. High-speed negotiation. A USB 2.0-rated cable, an extension lead or the wrong socket on the board caps the whole camera at 480 Mbps. Test: read the Speed line in lsusb -t (step 1 below).
  2. A hub in the path. A high-speed hub, or a board where two ports share one controller, leaves the camera a fraction of the link. Test: plug straight into a root port and retest.
  3. Demand over budget. Raw depth and IR dwarf the compressed color stream, so the total can exceed what the bus carries even while color proves the cable works. Test: the arithmetic two sections down; the same budget decides the depth and color stream timeout case.
  4. The kernel UVC driver holds the depth interface. Linux grants one claimant per interface; if uvcvideo or a stray viewer owns it, the SDK waits forever. Test: read the driver binding in dmesg.
  5. An arm64 SDK build that does not match the board. A stack compiled against the wrong toolchain or headers fails silently at exactly this point. Test: run the vendor's arm64 package built for your distribution.

The bandwidth rule that decides it

Every stream on the wire pays the same toll, and one line of arithmetic settles whether a link can carry it:

bytes per second = width × height × bytes per pixel × fps megabits per second = bytes per second × 8 / 1,000,000

A raw 16-bit depth frame carries 2 bytes per pixel; an 8-bit IR frame carries 1. The color endpoint almost always negotiates a compressed MJPG profile, which lands in the low single-digit MB/s at 720p30 and rounds to nothing next to raw depth.

Link Signaling rate Practical throughput Verdict for a raw 720p30 depth + IR pair
USB 2.0 (high-speed) 480 Mbps about 40 MB/s Cannot carry it; the pair is roughly 2.8 times over
USB 3.x (SuperSpeed) 5 Gbps about 400 MB/s Carries it at about 28% of budget

The decision rule: if the planned total passes about 40 MB/s, no driver change rescues a high-speed link — the fix is SuperSpeed transport or a smaller stream. If the total fits under it, stop chasing bandwidth and look at drivers and open endpoints instead.

Worked example: a 1280 x 720 depth and IR pair at 30 fps

Take the profile these cameras open by default: depth and IR at 1280 x 720 px and 30 fps, both 16-bit (2 bytes per pixel), with color running compressed MJPG at a few MB/s.

Rule in words: bytes per second = pixels × bytes per pixel × frames per second.

  • Depth: 1280 × 720 × 2 B × 30 fps = 55,296,000 B/s = 55.3 MB/s. × 8 = 442.4 Mbps.
  • IR at the same size and rate: another 55.3 MB/s (442.4 Mbps). An 8-bit IR stream halves this to 27.6 MB/s.
  • Pair total: 55.3 + 55.3 = 110.6 MB/s, about 885 Mbps; with compressed color added, call the rig roughly 0.9 Gbps.

Result and decision: against USB 2.0's practical budget of about 40 MB/s, the pair sits at 110.6 / 40 = 2.8 times over, and even depth alone at 55.3 MB/s is 1.4 times over. Against USB 3.x's practical 400 MB/s, it uses 110.6 / 400 = 28%. This profile streams only on SuperSpeed. On a high-speed link, no combination of SDK settings produces a first depth frame — and the color stream surviving on MJPG while depth waits is the fingerprint that tells you this is exactly what happened. Threshold to carry forward: keep the planned total under half the practical bus budget.

  1. Run lsusb -t and find the camera on its bus. Speed: 5000M means SuperSpeed; Speed: 480M means the link fell back to high-speed. A 480M reading explains the stall on its own; see why lsusb -t reports 480M in the USB3 camera speed walkthrough.
  2. Unplug, run dmesg -w in a terminal, and replug. As the camera enumerates, the kernel prints a line reading new SuperSpeed USB device or new high-speed USB device. That line names the negotiated speed before any SDK gets involved.
  3. Replace the cable. Retail cables marked USB 3 sometimes omit the extra SuperSpeed pairs entirely. Fit one rated for USB 3.0 along its whole run, such as the 3 m USB3.0 camera cable, high-flex below, and repeat step 1.
Cables3 m USB3.0 camera cable, high-flex (drag chain) (LS-CBL-0219)LS-CBL-0219$62.00View partBuild a system with it
  1. Move the camera to a root port on the board. If you need more ports than the board has, use a SuperSpeed hub and budget its shared link as the hub bandwidth walkthrough shows.
  2. Confirm each endpoint alone: start depth at the lowest rate it offers, add IR, then color, stepping rates back up until the link breaks. Testing streams one at a time, as in the multi-camera low-fps diagnosis, finds the real ceiling — and your configuration must live under it, not under the camera's advertised maximum.

Keep the kernel UVC driver off the depth endpoints

These cameras expose several interfaces: color, the IR sensors, and a vendor control interface for depth processing and the IMU. The SDK's USB backend (many stacks are built on libuvc) must claim the depth and IR interfaces exclusively, and Linux grants one claimant per interface. If uvcvideo or a stray viewer process claimed them first, the start call succeeds anyway and the frame counter stays at zero forever — the same waiting line, on a perfect link.

Read the driver binding in dmesg from the moment of plug-in, close any generic camera tool holding the device open, and apply the vendor's Linux setup steps for device permissions before debugging your own code. If you built the SDK from source for arm64, retire that build in favor of the vendor's arm64 package for your distribution; vendor userspace stacks on ARM64 boards fail in this silent way often enough that the discipline is the same as for any vendor driver build on ARM64 Linux hosts.

If the Speed line still reads 480M after a cable and port swap, the transport is settled and the streams must shrink. Work the levers in this order:

  1. Frame rate first. Dropping 30 fps to 15 halves every stream: the pair above falls from 110.6 MB/s to 55.3 MB/s. Still over the high-speed budget, so keep going.
  2. Pixel depth second. An 8-bit depth or IR format halves bytes per pixel again: 1280 × 720 × 1 B × 15 fps = 13.8 MB/s per stream, 27.6 MB/s for the pair — under 40 MB/s, so it fits, with compressed color alongside.
  3. Resolution third when quality allows. 640 x 480 at 30 fps and 16-bit costs 18.4 MB/s per stream, 36.8 MB/s for the pair: the only single change that fits a healthy high-speed link at full rate.
  4. Compressed depth formats. If the camera's format list offers MJPG on the depth or IR endpoint, request it; that moves those streams onto the same compressed path the color stream already uses.

Before the next station ships:

  • Spec every USB run as SuperSpeed end to end: cable, any hub, and the socket the board's own manual wires for USB 3.
  • Log lsusb -t at startup and alarm when a depth camera reports Speed: 480M.
  • Give each uncompressed camera its own root port rather than a shared hub leg.
  • Ship the vendor's arm64 package inside the station image instead of a hand build.

For parts, start at the 3D sensors category and its camera finder, and match the link with a run from the camera cables page or the accessories finder. More diagnosis paths for depth rigs sit on the 3D vision topic page.

Build the whole station

The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.

Start with the cables and extras

If every check above passes and the depth endpoint still waits, take the dmesg output and the lsusb -t reading to the contact page and the support team will read the log with you.

Questions

Why do the SDK property logs print normally while no depth frame ever arrives?

Property exchange and frame streaming use different paths. Gains, exposures and mirror settings travel over control transfers, which need almost no bandwidth; frames travel over bulk endpoints sized in MB/s. A camera that syncs every property but never delivers a frame is telling you the control path is healthy and the bulk path is starved or unclaimed, which is the exact signature of a bandwidth shortfall or a driver holding the endpoint.

How much bandwidth does a 720p30 depth stream actually need?

A 1280 x 720 depth stream at 30 fps carries 16-bit pixels at 55.3 MB/s, or 442 Mbps, before protocol overhead. Dropping to 640 x 480 at the same rate costs 640 × 480 × 2 × 30 = 18.4 MB/s per stream, and even with a matching IR stream at 36.8 MB/s it stays inside USB 2.0's practical budget, so resolution is the strongest single lever when the bus cannot be upgraded.

Can two USB depth cameras share one controller?

Two cameras each streaming 55.3 MB/s put 110.6 MB/s on the wire. A USB 3 host with a practical 400 MB/s budget carries that with room for a third compressed profile. On USB 2 nothing fits: one uncompressed depth stream alone already passes the 40 MB/s budget. Put each camera on its own root port rather than a pass-through hub, and stream one at a time while you measure the ceiling.

Does a USB 3.0 cable always give USB 3.0 speed?

No. A link runs at the slowest rated element in it: a USB 2.0-rated cable in a blue port negotiates 480 Mbps and reports Speed: 480M in lsusb -t. Cables also fail partially, where the SuperSpeed pairs are damaged but 480 Mbps signaling still works, which is why a camera enumerates yet streams nothing. Trust the reported speed, not the port color or the printing on the plug.

Is the problem ever the camera itself?

Yes, but it is the last suspect. The same camera that waits on the ARM board streamed on a desktop, so the depth pipeline inside it works. A genuine camera fault shows identical behavior on every host: no depth on any port, any cable, any OS. Test once on a desktop machine with the vendor's own viewer; if depth appears there, put the ARM side under suspicion and work the bandwidth and driver checks.