Cameras & sensorsTroubleshooting

MIPI CRC errors after the first stream: pixel clock and mode timing

Fix a MIPI CRC error that appears only after the first stream: derive px_clk_hz for C-PHY 887 Msps, check the failing mode's settle timing, reset the receiver.

LumaSpec Vision11 min read Share on LinkedIn

On this page 12 sections
  1. 01The symptom pattern and what it rules out
  2. 02What status:0x00000004 tells you
  3. 03Cause 1: the restart path leaves the receiver mis-settled
  4. 04Cause 2: one mode's timing is marginal
  5. 05Worked example: px_clk_hz for the 3840×2160 mode at 887 Msps
  6. 06Fix sequence: recover, correct, soak
  7. 07Checks that clear the remaining suspects
  8. 08When the usual advice is wrong
  9. 09The decision for each case
  10. 10If the mode cannot be saved
  11. 11Checklist before you close the ticket
  12. 12Questions

You integrated a raw MIPI sensor on an embedded host, and the first stream after boot is clean. Launch the same camera again and the trace fills with CRC interrupts. Power-cycling the sensor changes nothing, yet one long raw capture puts it right — until the next failure. First stream good, every restart bad, and only one sensor mode affected: that pattern is a mode-timing problem, not a broken flex cable. This guide works the evidence, derives the pixel clock for a C-PHY mode at 887 Msps, gives the recovery commands and the timing fix in order of probability, and ends with the decision for each case. If you maintain a board-level camera bring-up, you will leave with the number to set and the test that proves the fix.

The symptom pattern and what it rules out

The cycle, observed on a 3840×2160 C-PHY mode: after boot, the first nvarguscamerasrc stream is clean. A later launch raises CRC errors, and from that point every launch fails. Switching the sensor's power off and on does not clear it. One raw v4l2-ctl capture with --stream-count=300 clears it, and the next daemon launch works again — until it does not. The modes that run at 800 Msps on the same three lanes stream indefinitely, whichever order you launch them in.

That pattern rules out most of the usual suspects. Swapped lanes or inverted trio polarity fail every mode from frame one — the 800 Msps modes share the same wires, so the physical link is proven good, the failure mode described in MIPI C-PHY frames time out: lane polarity and trio checks. A connector fault does not know which mode is running. A sensor register fault is not cleared by a host-side capture. What remains is the host receiver's restart path and the one mode's timing entries, and both are fixable.

What status:0x00000004 tells you

The trace lines to look for are rtcpu_nvcsi_intr with class:CORRECTABLE_ERR, type:STREAM_VC and status:0x00000004. In this trace format that status is the packet payload CRC check failing: every long packet in CSI-2 carries a CRC computed over its payload, and the receiver computed a different value. Either the decoded bits were wrong, or the receiver sampled them at the wrong instant.

CORRECTABLE_ERR is the receiver's error class, not a statement about your data. The frame still closes out in the trace — CHANSEL_PXL_EOF, ATOMP_FRAME_DONE and ATOMP_FE all follow the interrupt — so capture continues with corrupt lines instead of stopping. That is why this fault can hide for a whole session: nothing fails loudly, the pixels just go bad.

Cause 1: the restart path leaves the receiver mis-settled

A sensor power cycle does nothing because the stale state is in the host's CSI receiver, not in the sensor. The nvarguscamerasrc path reaches the sensor through nvargus-daemon, which starts and stops a stream for every pipeline. A stop that leaves the receiver half-configured means the next start settles against leftover state, and the first packet that crosses a marginal window fails its CRC.

Two documented recoveries exist. Restart the daemon:

sudo pkill nvargus-daemon
sudo systemctl start nvargus-daemon

Or run one complete raw capture on the failing mode, which forces a full stream-on and stream-off cycle that re-runs the receiver bring-up:

v4l2-ctl -d /dev/video0 --set-fmt-video=width=3840,height=2160,pixelformat=RG10 --set-ctrl bypass_mode=0,sensor_mode=0 --stream-mmap --stream-count=300 --verbose

At 30 fps, 300 frames is 10 s of streaming — long enough to carry the link through its transition. Locking the host clock tree at the same time takes clock ramping out of the comparison:

echo 1 > /sys/kernel/debug/bpmp/debug/clk/vi/mrq_rate_locked
echo 1 > /sys/kernel/debug/bpmp/debug/clk/isp/mrq_rate_locked
echo 1 > /sys/kernel/debug/bpmp/debug/clk/nvcsi/mrq_rate_locked

All of these are recovery tools. None stops the fault returning on the next launch of the same mode, which is why the fix lives in the next section.

Cause 2: one mode's timing is marginal

The two mode groups differ in one number: 887 Msps versus 800 Msps, in symbols per second on each C-PHY lane. The symbol period shrinks from 1.250 ns to 1.127 ns — 1 ÷ 887,000,000 = 1.127 ns. The faster mode moves 10.9% more symbols per second (887 ÷ 800 = 1.109), so any fixed timing error — a settle window that opens late, a constant sized for the slower mode — consumes a 10.9% larger share of every symbol.

The first stream after boot works because the receiver leaves power-on reset and the full bring-up sequence runs once, with the mode's parameters applied from scratch. The restart path is the one that skips or reuses part of that sequence. A mode whose margin is comfortable at 800 Msps and marginal at 887 Msps shows exactly this signature: clean once, then corrupt on every restart, over wires that carry the slower modes forever.

Sensor-side and host-side timing for a mode are a pair, and both halves must come from that mode's own numbers. Settle values, blanking and embedded-line counts for the 3840×2160 mode belong to that mode; values copied from the neighboring 800 Msps entry are a bug, not a shortcut. MIPI CSI camera bring-up: sensor and host tuning must match as a pair covers how those pairs drift apart during development.

Worked example: px_clk_hz for the 3840×2160 mode at 887 Msps

Inputs, each from the mode's own definition: 887 Msps per lane; 16/7 bits per symbol, because C-PHY packs 16 bits into 7 symbols; 3 lanes; raw10 — the RG10 format — so 10 bits per pixel.

The rule in words: the pixel clock is the link's total payload rate divided by the bits per pixel.

px_clk_hz = lane_rate × bits_per_symbol × lanes / bits_per_pixel

The arithmetic, written out:

  • 887 Msps × 16/7 = 2,027.4 Mbit/s per lane, because 887 × 16 = 14,192 and 14,192 ÷ 7 = 2,027.4
  • 2,027.4 Mbit/s × 3 lanes = 6,082.3 Mbit/s of payload across the link
  • 6,082.3 Mbit/s ÷ 10 bits per pixel = 608.23 Mpixel/s, so px_clk_hz = 608,228,571 Hz rounded down, or 608,228,572 Hz rounded up

Sanity-check the result against the frame geometry: active pixels alone need 3840 × 2160 × 30 fps = 248,832,000 pixels/s, or 248.83 Mpixel/s. The link carries 608.23, leaving 359.4 Mpixel/s — 59% of the budget — for blanking and the embedded data lines the trace shows as CHANSEL_EMBED_SOF and CHANSEL_EMBED_EOF. The derivation is consistent.

The decision: in the case this guide works from, values from 608,228,571 to 608,228,590 Hz, then 610 MHz, 620 MHz and 630 MHz, all failed identically. A 1 Hz rounding is 1.6 parts per billion of 608 MHz, and 630 MHz sits 3.6% high without changing anything. If your value lands within 1% of 608.23 MHz, the pixel clock is not your fault: stop tuning it and fix the settle entries. The same lane-and-rate arithmetic behind a mode's throughput is worked through in MIPI CSI-2 frame rate estimation: lanes and data rate.

Fix sequence: recover, correct, soak

  1. Recover the receiver now — restart nvargus-daemon, or run the raw capture with --stream-count=300 on the failing mode. Confirm the next nvarguscamerasrc launch is clean.
  2. Reproduce the mode dependency on purpose: after a reboot, stream a working 800 Msps mode, then the 3840×2160 mode, twice each. A CRC that appears only on the second run of the high-rate mode confirms a restart-path fault.
  3. Apply the three clock locks above before any further comparison, so VI, ISP and CSI clock ramping cannot pollute the result.
  4. Set px_clk_hz to the derived value and stop worrying about the last digit.
  5. Re-derive the mode's settle values from its own symbol period. Where the driver expresses settle in symbol counts, scale a value tuned at 800 Msps by 800 ÷ 887 = 0.90; where it is in nanoseconds, leave it and move to the mode's other timing constants.
  6. Make the failing mode carry its own timing constants. Blanking and embedded-line counts are per-mode values, and the 3840×2160 entry must not inherit the 800 Msps neighbor's.
  7. Soak it: 20 start/stop cycles of the 3840×2160 mode with no CRC, interleaved with launches of the other modes. The original fault surfaced on the second launch, so a short run proves nothing.

Checks that clear the remaining suspects

Lane order and polarity are proven good by the 800 Msps modes on the same wires; a swapped or inverted trio fails everywhere and immediately, not on the second launch of one mode.

Mode mismatch is ruled out by the trace: the receiver logs CHANSEL_PXL_SOF and completes frames with the expected geometry. A host expecting a different mode produces short-frame errors instead — see CSI camera short frame errors: match the mode to the sensor output and MIPI camera 2-lane vs 4-lane mode: why the sensor probe fails.

Host capability is worth one check at this resolution; MIPI CSI camera resolution limits: verify the host and USB camera stuck at 4K: how sensor resolution modes work cover the bounds.

Signal integrity comes last, but it is not zero: an eye that closes over an 11% rate step was already marginal. Shorten the flex, reseat the connector, then re-run the soak. Power the carrier down before reseating anything — the flex pins are ESD-sensitive, and a hot reseat turns a timing fault into a dead sensor.

When the usual advice is wrong

Restarting the daemon recovers the link and fixes nothing — the fault returns with the next launch of that mode. Power-cycling the sensor does nothing here, because the stale state is host-side and survives a full sensor power cycle. Raising px_clk_hz is a dead end once the correct derivation is in place: a pixel clock wrong enough to cause CRC corrupts every mode, not one, and the 610–630 MHz sweep changed nothing. Boosting the host clocks removes ramping and is worth one try, but it never touches link settle.

The decision for each case

Your symptom Root cause Decision
First stream good, later launches CRC, one mode only Restart-path settle on a marginal mode Fix that mode's settle and px_clk_hz, then pass the 20-restart soak
CRC from the very first stream, in every mode Lane order, polarity or signal integrity Check trio polarity and lane mapping before touching timing
CRC only through nvarguscamerasrc, never through raw v4l2-ctl The daemon start/stop path Restart the daemon to recover; fix the mode timing for the root cause
CRC appears whenever a mode's rate rises about 10% Eye margin at the connector or flex Shorten and reseat first, then treat it as a marginal mode
No access to the mode's timing entries You do not own the driver Run production on the 800 Msps mode, or buy the link inside a camera

If the mode cannot be saved

You fix mode entries when you own the driver. When you do not, the decision becomes where the MIPI link lives: on your carrier board, or inside a module the maker has already soaked.

A board-level camera keeps the embedded form factor and moves the C-PHY link onto the module:

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
$690.00View part
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
$239.00View part

The LS-BCM-0003 is a 3.1 MP USB3 board-level camera on a 1/1.8" global-shutter sensor with a C-mount. The MV-CB060-10UM-B is a 6 MP USB3 board camera sold as a bare board on the same 1/1.8" format. Before you commit to a module, run the board camera evaluation checklist for inspection systems and the guide to matching a board-level camera and USB3 bridge board. The board-level cameras category lists the current modules.

A finished camera ends the bring-up entirely:

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
$560.00View part
Area scan camerasHikrobot MV-CS200-10UM 20 MP Area Scan Camera, USB3.0, IMX183, 2nd Gen., MonoMV-CS200-10UM
Sensor format
1"
Lens mount
C-mount
$759.00View part

The LS-CMR-0166 delivers 4000 × 3000 at 30 fps over USB3, with the link inside the housing. The MV-CS200-10UM is a 20 MP camera on a 1" sensor. Use that one when you want resolution margin over the 3840 × 2160 mode you are leaving behind. Start from the area scan cameras finder or the camera step of the configurator to match interface and resolution.

Checklist before you close the ticket

  • px_clk_hz = 608,228,571 Hz for the 887 Msps C-PHY mode, derived with the formula above; within 1% is close enough.
  • Settle values scaled to the mode's 1.127 ns symbol period where the driver counts symbols — factor 0.90 from an 800 Msps reference.
  • One raw --stream-count=300 capture and the daemon restart in the runbook as the two recovery paths.
  • The three clock locks applied before any timing comparison.
  • A 20-restart soak on the failing mode, interleaved with the other modes, clean throughout.
  • Power removed before any flex reseat.
  • The mode-order repro test recorded with its trace, so the next engineer sees the dependency.

Questions

What does status:0x00000004 mean in the nvcsi interrupt trace?

It is the packet payload CRC check failing on that virtual channel: the receiver recomputed a long packet's payload CRC and got a different value than the sender. The host classes it as CORRECTABLE_ERR because the receiver logs it and keeps capturing — frames still complete, so your pipeline runs on with corrupted lines rather than stopping. Damage to a packet header instead reports as an ECC fault, a different line in the trace. Treat the pixels as corrupt.

Why does one long v4l2-ctl run clear the CRC error?

The command forces a complete stream-on and stream-off cycle at the driver level, which re-runs the CSI receiver's bring-up, settle included, from a clean state. The nvargus-daemon stop path is what leaves the receiver badly configured, so rebuilding it through the raw driver side-steps that leftover state. Keep the command in the runbook as the first recovery step when a station locks up.

Is px_clk_hz 608228571 or 608228572 for this mode?

Either. The pair differs by 1 Hz in 608 MHz, about 1.6 parts per billion, and no receiver behavior can hinge on that. The case behind this guide swept 608,228,571 through 608,228,590 Hz, then 610, 620 and 630 MHz, with identical failures every time. Set 608,228,571 Hz and spend the time on the mode's settle values instead.

Why does the first stream after boot always work?

Because the receiver leaves power-on reset and the full bring-up sequence runs once, applying the mode's timing from scratch. The fault lives in the restart path, which reuses or skips part of that sequence against leftover state. That is also why power-cycling the sensor never helps: the stale state is in the host, and only a full stream stop or a daemon restart rebuilds it.

Should we just run the 800 Msps mode in production?

If that mode's resolution and frame rate meet the inspection need, yes — it is the lowest-risk fix and the link is proven stable on your wires. The 887 Msps mode buys 10.9% more pixel rate; pay for it only when a timing need forces you. Otherwise fix the mode's settle entries, or move to a finished camera where the maker owns the link.