System designTroubleshooting

Green screen then USB camera disconnect on Linux: fix it

Why a USB camera shows a green screen then disconnects on Linux, the tests that split a format problem from a power or cable problem, and the fix for each.

LumaSpec Vision12 min read Share on LinkedIn

On this page 10 sections
  1. 01Why the flash is green
  2. 02The three causes, ranked
  3. 03Diagnose it in five tests
  4. 04The arithmetic: why full-size uncompressed cannot fit
  5. 05Fix cause 1: negotiate a mode that fits
  6. 06Fix cause 2: give the port the current it needs
  7. 07Fix cause 3: the cable
  8. 08When the better fix is a different camera link
  9. 09Checklist: keep the disconnect from coming back
  10. 10Questions

The signature is hard to miss: you start a capture, the first frames render as flat green for half a second, and then the camera vanishes from /dev/video until you replug it. lsusb lists the device, the same module streams fine on a standard desktop PC, and nothing you change in the capture app helps. This is the empty-buffer-then-disconnect failure, and on a Linux host it has exactly three causes: a format the link cannot carry, a port that cannot deliver the current, or a cable that lost its SuperSpeed pairs. Work through the tests below and you will name the cause in about ten minutes — and pin the fix that keeps the camera streaming.

Why the flash is green

A camera that renders green is not showing you sensor data. The capture application queues a ring of frame buffers, the driver starts requesting payloads, and the screen shows whatever sits in that memory. When no valid frame arrives, the buffers stay zero-filled — and a zero-filled YUV frame converts to one specific color. Using the standard BT.601 conversion with Y, U and V all set to 0:

R = Y + 1.402 (V - 128) = 0 + 1.402 × (-128) ≈ -179, clipped to 0 G = Y - 0.344 (U - 128) - 0.714 (V - 128) = 44.0 + 91.4 ≈ 135 B = Y + 1.772 (U - 128) = 0 + 1.772 × (-128) ≈ -227, clipped to 0

Y = U = V = 0 maps to RGB (0, 135, 0): the flat green you are watching. The flash is diagnostic, not mysterious — zero bytes of image data arrived from the first frame on, and the drop that follows is the second half of the evidence. Either the module reset itself, which points at power, or the host gave up on stalled transfers, which points at bandwidth or cable.

A steady grey picture is a different failure, where the stream runs but the pixels are misread; the camera grey image at runtime article covers that case. The green-then-timeout pattern also appears away from USB: this GMSL camera green-screen and capture-timeout fix treats the same class of empty-stream failure on a different link.

The three causes, ranked

Rank them in this order when green comes first and the drop follows within a second:

  1. A format the link cannot carry. The descriptors advertise uncompressed YUV at full size and rate, the application requests it, and the host cannot allocate USB bandwidth for it — or payloads stall because the module's firmware assumed a healthier link than it got. Empty buffers render green, then the host closes the device.
  2. A port that cannot deliver the streaming current. Small Linux boards commonly boot with a conservative per-port current limit. Enumeration succeeds on idle draw; the first streamed frames push the module toward peak draw, the 5 V rail sags, the camera controller resets, and the bus reports a disconnect.
  3. A cable that lost its SuperSpeed pairs. A marginal cable enumerates happily at 480 Mbit/s, but at that speed not even a compressed 4K stream fits, and the link stalls into the same green-then-drop pattern.

The dmesg log at the moment of failure separates them. A bandwidth allocation error such as "no space left on device" when streaming starts is cause 1; a clean disconnect line with no transfer errors before it is cause 2; a device holding 480 Mbit/s instead of 5000M is cause 3. Each fix below starts with its own test, and the systems topic page gathers the sibling Linux capture failures — permissions, buffering, duplicate device paths — for when the symptom lives there instead.

Diagnose it in five tests

  1. Watch the log while you reproduce. Run sudo dmesg -w in a spare terminal, then start the capture that fails. Note the last lines before the device disappears. If the application ends on a VIDIOC_DQBUF error instead of a disconnect line, the error 19 diagnosis picks up from exactly there.
  2. Check the negotiated speed. Run lsusb -t and find the camera's entry. It should read 5000M. A 480M line means the SuperSpeed pairs are not making it — go straight to the cable test.
  3. Feed the camera from a powered USB3 hub. A hub with its own supply removes the host port from the power equation. If the disconnects stop, the port was browning out — cause 2 confirmed.
  4. List what the module offers. Run v4l2-ctl -d /dev/video0 --list-formats-ext. You get every pixel format and frame size the firmware exposes. A module that lists a 4K YUV mode is advertising it, not guaranteeing it.
  5. Pin a compressed format before capture. Run v4l2-ctl -d /dev/video0 --set-fmt-video=width=3840,height=2160,pixelformat=MJPG, then capture again. If the green flash and the disconnect both stop, cause 1 is confirmed.

Five tests, three clean verdicts. Skip the temptation to cycle through ten different viewers — the failure reproduces in all of them because it lives in the negotiation layer beneath them.

The arithmetic: why full-size uncompressed cannot fit

USB 3.0 puts 5 Gbit/s on the wire. After the 8b/10b line coding that SuperSpeed uses, 4 Gbit/s of payload remains, and a real streaming link delivers about 400 MB/s of usable data once protocol overhead is paid. Price a frame against that budget:

bytes per frame = width × height × 2 (YUV 4:2:2, 8 bit per component) link requirement = bytes per frame × frame rate

Take an illustrative module streaming 3840 × 2160 at 30 fps in uncompressed YUV 4:2:2:

  • 3840 × 2160 = 8,294,400 pixels per frame
  • 8,294,400 × 2 bytes = 16,588,800 bytes ≈ 16.6 MB per frame
  • 16,588,800 × 30 = 497,664,000 bytes per second ≈ 498 MB/s ≈ 3.98 Gbit/s

That 3.98 Gbit/s of payload goes against roughly 3.2 Gbit/s of deliverable stream (400 MB/s × 8 bits). It does not fit, so the module must fall back to MJPEG. At a typical 8:1 MJPEG compression the same stream costs about 62 MB/s (498 ÷ 8) — comfortable margin. Treat the ratio as an estimate; real MJPEG sizes vary with scene detail. Drop the link to 480 Mbit/s, as a tired cable does, and usable payload falls to roughly 40 MB/s — now even MJPEG is over budget and the failure returns.

The same sum explains the classic "no space left on device" on multi-camera hosts, because bandwidth is reserved per stream: four 1080p30 YUV streams claim about 498 MB/s, far past the budget one stream seemed to leave, which is where the USB hub frame-rate budget article starts. What a link fallback looks like on other embedded hosts is laid out in this USB3 camera fallback troubleshooting guide.

Decision: request MJPEG at full resolution, or uncompressed at a frame size the arithmetic clears — never full-size uncompressed at 30 fps.

Fix cause 1: negotiate a mode that fits

UVC hands the format choice to whoever opens the device first, so pin it yourself instead of letting the application guess:

  1. List the modes: v4l2-ctl -d /dev/video0 --list-formats-ext.
  2. Pick MJPEG at your target resolution, or uncompressed YUV at a size the budget clears. Uncompressed 1920 × 1080 at 30 fps needs 1920 × 1080 × 2 × 30 = 124,416,000 bytes per second ≈ 124 MB/s, which fits.
  3. Set it before capture: v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=YUYV for 1080p uncompressed, or the MJPG command from the test above.
  4. In your own acquisition code, set the format immediately after opening the node and before streaming starts.

One more negotiation trap: these modules enumerate as two /dev/video nodes — one carrying the regular YUV and MJPEG outputs, the other an H.264 encoder output. A tool that opens the H.264 node negotiates nothing useful and can reproduce the same green-or-empty behavior, so list formats on both nodes and capture from the one offering YUV or MJPEG. When a driver and an application disagree about modes, the rejected-modes format negotiation article follows the negotiation path line by line, and the pixel format that will not change article explains why a format refuses to switch at runtime.

Fix cause 2: give the port the current it needs

The port has to cover the module's full unit load — the 4.5 W figure above — and no more sharing. Budget the camera a port of its own. A camera that shares a port with thin headroom browns out at the exact moment streaming begins, which is why it enumerates, renders nothing and vanishes.

  • Powered hub first. Put the module on a powered USB3 hub, nothing else plugged into it. If the failure disappears, the host port was the constraint.
  • Lift the board's current limit. Where the board firmware provides a USB maximum-current option, enable it; the setting's name and location differ between boards, so take it from your board's own configuration reference.
  • Read the power state while streaming. Where the board exposes vcgencmd, query the throttle and undervoltage flags during capture. A flag that appears only while streaming convicts the supply, not the camera.
  • Feed the module separately where it supports it. Some modules accept external 5 V alongside the bus; the USB versus external 5 V power article works through when that beats bus power.

The replug pattern is the tell: a device that returns only after you pull the plug was reset by its own supply, and it will keep doing so under the same load.

Fix cause 3: the cable

USB 3.0 needs all of its pairs. A cable that enumerates but never holds 5000M in lsusb -t has lost — or never had — working SuperSpeed wiring; plenty of cables sold with USB-A plugs carry only the USB 2.0 set plus power conductors. Keep passive runs at 3 m or less, swap in a lead certified for USB 3.0, and route it away from motor and switch-mode wiring. On a moving axis an office cable is a consumable: repeated flexing fatigues the copper, the SuperSpeed pairs fail first, and you get exactly this enumerate-then-stall signature. The USB link checks after a cable swap article walks the link-side checks step by step, and camera cables filtered by length and use sit in the accessories finder. For a machine that runs all day, spec the cable for the motion:

Cables3 m USB3.0 camera cable, high-flex (drag chain) (LS-CBL-0219)LS-CBL-0219$62.00View partBuild a system with it

The LS-CBL-0219 is a 3 m USB3.0 camera cable with high-flex, drag-chain construction — the cable you spec once instead of replacing monthly.

UVC is a webcam protocol: whoever opens the device first sets the format, bandwidth is not reserved, and the module firmware decides how gracefully it fails. Vision transports remove those freedoms. USB3 Vision reserves and reports its bandwidth so a stream cannot be overbooked; GigE Vision negotiates packet size and runs over standard network cable up to 100 m. If the module keeps fighting the host after the three fixes above, move the application onto a camera built for it:

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

The LS-CMR-0166 streams 4000 × 3000 at 30 fps over USB3 — a 12 MP sensor whose link budget is accounted for by the driver rather than negotiated by whichever viewer opened first. Where the camera must sit further from the host or share a machine network, GigE is the sturdier transport:

Area scan camerasHikrobot MV-CU020-90GC 2.5 MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
$309.00View partBuild a system with it

The MV-CU020-90GC is a 2.5 MP GigE camera with a global shutter: the same host that starves a UVC module runs a GigE stream all day, because the protocol carries its own bandwidth contract. Match sensor and interface to the task in the area scan cameras range or the camera finder, and count the hours spent coaxing a webcam module into streaming — most of that cost disappears the moment the transport carries a bandwidth contract.

Checklist: keep the disconnect from coming back

Run this once at bench time and once before the machine ships:

  • Format pinned in code. Your acquisition code sets pixel format and frame size right after opening the device; it never relies on whatever the driver picked last time.
  • Bandwidth budgeted. width × height × 2 × fps for uncompressed, about an eighth of that for MJPEG, summed across every camera on the controller, against roughly 400 MB/s of usable USB3 payload.
  • Power proven. The camera runs on a powered hub or a port confirmed to deliver the full 900 mA, with no throttle or undervoltage flags while streaming.
  • Cable certified and short. USB 3.0 rated, passive runs of 3 m or less, drag-chain rated anywhere the cable flexes.
  • Failure logged. dmesg captured to a file at start-up, so the next green flash arrives with its own evidence.

If your log ends somewhere this decision path does not reach, send the dmesg excerpt through the contact page and we will read it against your setup.

Questions

Why does the same camera work on a desktop PC but fail on the Linux host?

Desktop UVC stacks usually open the camera in its compressed MJPEG mode and allocate bandwidth conservatively, so the hardest uncompressed modes are never attempted. Linux capture tools often request uncompressed YUV first, and at 4K that mode cannot fit through USB 3.0 at 30 fps. The hardware is fine; the two systems start the negotiation from different defaults. Force MJPEG on Linux and the behavior should match the desktop machine.

Can low power cause the green flash too, or only the disconnect?

Both can appear in one event. A port that sags under streaming load resets the module at the moment frames should arrive, so you can see a brief green flash and then a clean disconnect with no transfer errors in the log. The discriminator is the dmesg line: a plain disconnect points at power, transfer or bandwidth errors point at format and link. The powered-hub test settles it in one swap.

Will a USB 2.0 port work as a fallback?

Enumeration succeeds on USB 2.0, but the 480 Mbit/s link carries roughly 40 MB/s of usable payload. A 4K MJPEG stream needs around 62 MB/s, so full-resolution streaming is out; the module will either drop frames, renegotiate downward or stall. USB 2.0 is fine for bringing up a 1080p camera or verifying firmware, not for a 4K inspection stream.

How long can a USB 3.0 camera cable be?

Keep a passive USB 3.0 cable at 3 m or less; that is what certified cables are built and tested for. Past that, SuperSpeed integrity degrades and the link falls back to 480 Mbit/s, which cannot carry a 4K stream in any format. For longer runs use a powered hub as a repeater, an active optical cable, or move to GigE Vision, which runs over standard cable to 100 m.

How much current must a USB 3.0 port deliver for a streaming camera?

USB 3.0 specifies 5 V at up to 900 mA per port, about 4.5 W. Budget a streaming module a full port's worth. Small Linux boards frequently start with a lower per-port limit to protect their supply, so enable the board's USB maximum-current option where it provides one, or run the camera from a powered hub whose supply covers the module with margin.