System designTroubleshooting

CSI short frames in binning mode: fix the embedded data size

Why a binned CSI mode discards frames and fails raw capture, how the embedded data size breaks the row-width rule, and the device tree values that fix it.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01Read the two errors first
  2. 02Test the capture clocks before touching geometry
  3. 03The row-width rule behind the BadParameter error
  4. 04Worked example: a 2088 × 1096 RAW10 binning mode
  5. 05Fix the mode node in five steps
  6. 06Prove the fix in every mode you ship
  7. 07When the capture stack is not your product
  8. 08Prevention checklist before sign-off
  9. 09Questions

A binned mode that streams nothing is rarely a broken link. dmesg fills with discarded frames, a frame-rate query prints no number, the preview window renders a clean picture — and a raw capture aborts with a message about embedded data size. That combination localizes the fault precisely: the geometry your mode node declares does not match the lines your sensor actually sends in binning mode. If you are bringing up a MIPI CSI sensor on an embedded board, here you will read the two errors, run the row-width arithmetic on your own device tree, and decide between the three fixes — capture clocks, declared geometry, and the embedded-metadata switch. The worked example uses a real failing mode, 2088 × 1096 active pixels at RAW10 over four lanes, and ends with the values that let raw capture complete.

Read the two errors first

The failures arrive in pairs. In dmesg, the capture engine repeats corr_err: discarding frame 0, flags: 0, err_data 131072 once per frame period, and the driver trace shows the tag CHANSEL_SHORT_FRAME. The preview keeps rendering. A raw grabber such as nvargus_nvraw aborts with Embedded data size (7,552) is not a perfect multiple of row width (4,176).

Read together, they localize the fault. A live preview proves the sensor, the lanes, the PHY and the link clocks all work. A short frame means each frame ended before the capture engine had filled the buffer your mode node declared, so the engine discarded it and your application never received one — which is also why a frame-rate query prints nothing. The BadParameter error is a second, independent check: the raw writer cannot lay out the embedded data block that precedes the pixels. Two checks, one root cause — declared geometry versus actual binned output.

The non-binned version of this fault, where the whole mode is misdeclared, is covered in CSI camera short frame errors: match the mode to the sensor output. The cousin where the width is right but the line padding is not shows up as green frames from a CSI camera: pixel clock and padded line width.

Test the capture clocks before touching geometry

Boost the software-controlled capture clocks to their maximum and re-run the identical capture before editing anything. The test takes minutes, and it matters because an under-supplied capture path produces the same CHANSEL_SHORT_FRAME tag as a geometry mismatch. You do not want to rewrite a correct mode node to chase a timing fault.

The decision is binary. If the tag disappears at maximum clocks, the mode node was right and the platform simply could not move the declared data rate — check the lane budget with the MIPI CSI-2 frame rate estimation: lanes and data rate arithmetic before locking the clocks down for production. If the tag survives, the declared output exceeds what the sensor actually sends, and the geometry work below applies.

Two neighboring faults behave differently. A sensor that never streams at all fails earlier, and the MIPI sensor detected but streaming fails: power, clocks, device tree article splits those causes. Size faults also bite from both directions: a declared buffer smaller than the arriving frames is the mirror image of this one, and V4L2 raw capture fails when frame height is undersized walks that diagnosis.

The row-width rule behind the BadParameter error

A raw capture writes more than pixels. Before the active rows, the sensor transmits embedded data lines — its own state, such as exposure and gain, frozen at capture time. The mode node declares how many exist with embedded_metadata_height. The raw writer stores that block as whole rows of the same width as the image rows, so it applies one arithmetic rule: the embedded block's size in bytes must be an exact integer multiple of the row width in bytes.

Binning is where integrations fail this rule. The image rows are narrow — that is the point of binning — but the sensor still transmits its embedded line in the wide, unbinned line format. The block arrives sized for a line the binned rows cannot divide evenly into, so the raw path rejects every frame while the preview path, which never touches the metadata block, keeps working. The worked example below runs the numbers on a real failure.

Worked example: a 2088 × 1096 RAW10 binning mode

Inputs, all from the failing system: the mode node declares active_w = "2088" pixels, active_h = "1096" pixels, csi_pixel_bit_depth = "10" and embedded_metadata_height = "1", four lanes at 30 fps. The raw capture reports an embedded data size of 7552 bytes against a row width of 4176 bytes.

Rule, in words: this capture stack stores RAW10 unpacked, at two bytes per pixel, so the row width equals the declared active width times two bytes. The pass condition is that the embedded size divided by the row width is a whole number.

Arithmetic:

  • Row width: 2088 px × 2 B/px = 4176 B, which matches the reported row width exactly — both sides are using the declared width.
  • Multiple check: 7552 B ÷ 4176 B = 1.808, not a whole number, so the check fails and every raw capture aborts.
  • What the block contains: 7552 B ÷ 2 B/px = 3776 px of stored metadata, 1688 px wider than the declared rows (3776 − 2088). The embedded line arrived in the unbinned width, which the binned rows can never slice evenly.
row_width_bytes = active_w_px × bytes_stored_per_pixel pass: embedded_size_bytes ÷ row_width_bytes = whole number

Decision: whenever embedded size ÷ row width leaves a remainder, no clock setting and no retry helps — the memory layout is impossible, not the timing. Set embedded_metadata_height = "0" for that mode; the sensor-driver programming guide defines the property as the number of embedded rows per frame, with 0 disabling embedded metadata support. Leave it at 1 in full-resolution modes where the division comes out even.

Fix the mode node in five steps

  1. Boost the capture clocks, re-run, and record whether CHANSEL_SHORT_FRAME persists. Persistence means geometry, not timing.
  2. Inside the binned mode node only, set embedded_metadata_height = "0". The property sits inside each mode node; do not change a value that other modes share.
  3. Check active_w, active_h and line_length against the sensor driver's own table for that binning mode. The declared width must equal the sensor's actual binned output so the capture buffer width equals the real CSI line length, and line_length must be the driver's value because the timing math consumes it.
  4. Rebuild the device tree, deploy, and reboot so the capture engine programs the new geometry.
  5. Re-run the raw capture and a 30-second stream, then apply the pass marks in the next section.

The relevant part of the failing node, with the change marked:

active_w = "2088";              /* must equal the sensor's real binned output */
active_h = "1096";
line_length = "3000";           /* take this value from the driver's mode table */
csi_pixel_bit_depth = "10";
embedded_metadata_height = "1"; /* failing value: set to "0" for this mode */

If short frames survive both the metadata switch and a geometry pass, the value you want is still in the driver's mode table, not in the trace — go back to step 3 rather than guessing widths.

Prove the fix in every mode you ship

Pass marks, per mode, with the clocks back at their operating values:

  • 30 seconds of streaming adds zero new corr_err lines to dmesg.
  • The trace shows no new CHANSEL_SHORT_FRAME tags.
  • The raw capture prints its captured frame count and writes the file, with no BadParameter lines.
  • The frame-rate readout prints a number at or above the mode's minimum frame rate.

Run the raw grabber in every mode you expose, not only the one that failed. embedded_metadata_height is declared per mode, so a mode set can pass at full resolution and fail in binning — the exact pattern the worked example models. Expect the metadata trade too: with the block disabled, values you parsed from it are unavailable on that mode's path. Control is unaffected — set exposure and gain through the normal controls, and when you need the applied values per frame, the read actual exposure per frame when metadata says unsupported article shows the readback path.

When a mode streams complete frames but the pixels look wrong — striping, shifted lines, color noise — the fault has moved into the pixel domain, and the V4L2 CSI image-artifact troubleshooting walkthrough covers that triage.

When the capture stack is not your product

Everything above repairs a mode you have declared. If the sensor choice is still open and the deliverable is frames on a host, the whole fault class disappears when the camera enumerates over a standard link: no device-tree mode nodes, no capture-engine geometry, no embedded-block arithmetic — the module's driver carries its own format table. A board-level camera on USB3 behaves like any capture device on the bus.

The board-level cameras range is built for that integration style. The LS-BCM-0003 covers the fast end — 3.1 MP at 120 fps over USB3 with a global shutter — and the MV-CB060-10UM-B carries 6 MP mono on the same USB3 link as a bare board for compact housings. The camera finder filters both by sensor format and interface, and the board camera evaluation checklist for inspection systems walks the decision before you commit a design.

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

Prevention checklist before sign-off

When you declare a mode

  • Copy every geometry value from the sensor driver's table for that exact mode, never from a neighbouring mode — binning changes the line format, not only the pixel count.
  • Give each mode its own embedded_metadata_height and set it to 0 wherever the embedded block cannot divide into the row width.
  • Run the two-line row-width arithmetic once per mode before the first flash; it costs half a minute.

During bring-up

  • Maximum capture clocks for the first stream on every new mode, then re-test at operating clocks.
  • Capture raw alongside preview from day one; preview-only bring-up hides metadata faults until integration.

Before sign-off

  • 30 seconds per mode with a clean dmesg, a number from the frame-rate readout and a written raw file.
  • Record clocks, mode set and device-tree revision together so any future failure reproduces exactly.

Other capture-stack fault walks sit on the systems topic page. If you are choosing the camera rather than debugging one, the camera configurator pairs sensor format, interface and mount in one pass — and the area scan cameras and board-level ranges cover both integration styles.

Questions

Why does the preview work while raw capture fails?

The preview consumes the active image rows only, so a working picture proves the sensor, the lanes, the PHY and the clocks are all fine. Raw capture additionally has to place the embedded data block, and the writer rejects a block whose size is not a whole multiple of the row width it computed from active_w. Treat the combination as a layout bookkeeping fault, not a hardware fault, and start at the mode node.

Can I keep embedded metadata in a binning mode?

Only if the embedded block size divides evenly by the row width. With RAW10 stored at two bytes per pixel, row width equals active_w × 2 bytes; in the failing 2088-pixel mode the block measured 7552 bytes against a 4176-byte row width, a quotient of 1.808 that can never be whole. Set embedded_metadata_height to 0 for that one mode and leave it enabled in full-resolution modes where the division comes out even.

What does the corr_err discarding line in dmesg mean?

It is the capture engine reporting that a frame arrived incomplete and was thrown away before your application saw it, which is also why the frame-rate readout prints nothing while discards continue. The flags and err_data fields are internal diagnostic values; the trace tag that identifies this failure family is CHANSEL_SHORT_FRAME, meaning the frame ended before the declared geometry was filled.

Does setting embedded_metadata_height to 0 lose me exposure and gain readback?

On that mode's path, yes. The per-frame block no longer exists, so exposure, gain and any frame counter you parsed from it are unavailable there. Control is unaffected: set exposure and gain through the normal controls, and when you need the applied values per frame, read them back from the camera the way the per-frame metadata article describes rather than from the raw file.

How do I prove the fix before shipping the mode set?

Stream each mode for 30 seconds with the clocks back at operating values and count three things: zero new corr_err lines in dmesg, zero CHANSEL_SHORT_FRAME tags in the trace, and a raw capture that prints its captured frame count and writes the file. Run the raw grabber in every exposed mode, because embedded_metadata_height is declared per mode and a mode set can pass at full resolution while binning fails.