GMSL YUV422 capture and FORCE_FE errors on Jetson Orin — debug guide
GMSL YUV422 capture problems on Jetson trace almost exclusively to a mismatch between what the MAX9296 deserializer outputs on the MIPI bus and what the Jetson NVCSI driver expects. The partial-frame symptom — top portion valid, bottom black — is the signature of a per-line byte count mismatch: the CSI receiver thinks each line is shorter than it actually is and closes frames early.
Key Insights
- YUV422 8-bit outputs 2 bytes per pixel — vs RAW8’s 1 byte per pixel at the same resolution; the CSI configuration must account for this
- The
FORCE_FEregister forces a Frame End on the MIPI output — when configured, the deserializer inserts an end-of-frame marker after a fixed pixel count; if this doesn’t match the sensor output, frames are truncated MEDIA_BUS_FMT_UYVY8_1X16is the correct format enum for YUV422 8-bit in the Jetson camera DT- MAX9296 data type register must be set to
0x1Efor YUV422 — the default (RAW12 =0x2C) will cause the MIPI receiver to misinterpret the data - dmesg
crc errororforce-fe triggeredconfirms the deserializer output doesn’t match NVCSI expectations
The YUV422 bandwidth math
At 1920×1080:
- RAW12: 1920 × 1080 × 12 bits = 24.9 Mbytes/frame
- YUV422 8-bit: 1920 × 1080 × 16 bits = 33.2 Mbytes/frame
For the same framerate, YUV422 requires ~33% more lane bandwidth. A 4-lane GMSL2 link at 3Gbps/lane can sustain 1080p60 in YUV422 comfortably. The issue is not bandwidth — it’s the data type mismatch in the MIPI header.
MIPI data type configuration on MAX9296
The MAX9296 transmits a MIPI CSI-2 packet header with a Data Type field on every line. The Jetson NVCSI uses this header to determine how to parse incoming data.
MIPI CSI-2 Short Packet Header:
[ Virtual Channel | Data Type | Word Count | ECC ]
─────────
0x2C = RAW12 (default MAX9296)
0x1E = YUV422 8-bit ← must set this
0x1F = YUV422 10-bit
Setting the correct data type in the MAX9296 (via I2C on the serializer/deserializer):
/* MAX9296 I2C writes to configure YUV422 8-bit output */
/* Register 0x0313 = DATA_TYPE_SEL for PIPE_X */
i2c_write(max9296_addr, 0x0313, 0x5E); /* YUV422 8-bit, VC=0 */
/* Register 0x031C = MIPI output format for pipe X */
i2c_write(max9296_addr, 0x031C, 0x1E); /* 0x1E = YUV422 */
/* Verify PIPE_X is configured for 8-bit YUV */
i2c_read(max9296_addr, 0x0313, &val);
/* val should be 0x5E */
In the MAX9296 kernel driver (max9296.c), these registers are typically set in the max9296_set_pipe_settings function. If using a vendor-provided driver that hardcodes RAW12, you need to patch the register write sequence.
Device tree configuration for YUV422
/* In your camera module node */
&i2c_camera {
your_sensor@42 {
compatible = "your-sensor";
reg = <0x42>;
/* This must match the deserializer data type output */
sensor_modes {
mode0 {
num_lanes = "4";
tegra_sinterface = "serial_a";
phy_mode = "DPHY";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "0";
active_w = "1920";
active_h = "1080";
pixel_t = "yuv_uyvy8"; /* YUV422 format */
readout_orientation = "0";
line_length = "2200";
inherent_gain = "1";
mclk_multiplier = "25";
pix_clk_hz = "297000000";
min_gain_val = "1";
max_gain_val = "16";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "30";
max_framerate = "30";
min_exp_time = "34";
max_exp_time = "550385";
};
};
};
};
/* tegra-camera-platform media bus format override */
&cam_i2cmux {
drivernode0 {
pcl_id = "v4l2_sensor";
/* Override default RAW12 with YUV422 */
physical_w = "5.095";
physical_h = "4.930";
};
};
The pixel_t = "yuv_uyvy8" entry is critical — it sets the MEDIA_BUS_FMT_UYVY8_1X16 bus format in the Tegra camera platform, which controls what NVCSI expects.
Diagnosing the partial frame issue
# 1. Check dmesg for MIPI framing errors
dmesg | grep -E "nvcsi|crc|force.fe|overflow|frame.start" | tail -30
# 2. Capture a test frame and check the frame size
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=1920,height=1080,pixelformat=UYVY \
--stream-mmap --stream-count=1 --stream-to=/tmp/frame.raw
# YUV422 8-bit frame should be exactly:
# 1920 * 1080 * 2 = 4,147,200 bytes
ls -la /tmp/frame.raw
# If size is ~2MB (half), you have a RAW8 config on a YUV422 stream
# 3. Check what pixel format the driver reports
v4l2-ctl -d /dev/video0 --get-fmt-video
# Should show UYVY or YUYV, not RG10/BA10
# 4. Read the MAX9296 data type register over I2C
i2cget -y 2 0x48 0x0313
# Expected: 0x5e (YUV422 8-bit)
# If: 0x5f (RAW12) → this is the root cause
FORCE_FE register usage
The FORCE_FE register on MAX9296 is sometimes used to work around sensors that don’t generate proper MIPI end-of-frame packets:
/* MAX9296 register 0x01CE: FORCE_FE_TIMEOUT */
/* Set to 0 to disable forced frame end (let sensor control it) */
i2c_write(max9296_addr, 0x01CE, 0x00);
/* If sensor requires FORCE_FE, set timeout to match frame period:
For 1080p30, frame period = ~33ms = 33000µs */
i2c_write(max9296_addr, 0x01CE, 0x04); /* unit-specific, check MAX9296 datasheet */
Forcing frame end at the wrong time produces the partial frame symptom even with correct data type configuration.
For the complete GMSL2 camera bring-up workflow including MAX9295/MAX9296 initialization sequence, see GMSL2 camera bring-up on Jetson Orin with MAX9295/MAX9296. For GMSL serializer comparison and use case guidance, see GMSL2 vs FPD-Link III on Jetson — SerDes comparison.
FAQ
What is a FORCE_FE error in GMSL camera capture on Jetson?
A MIPI protocol error where the deserializer inserts a forced Frame End marker that doesn’t align with the actual frame data length. Caused by a mismatch between the deserializer output format (YUV422) and the CSI receiver configuration (RAW8/RAW12).
Why does GMSL YUV422 capture show only the top portion of the frame?
The deserializer is outputting YUV422 (2 bytes/pixel) but the driver expects RAW8 (1 byte/pixel). The CSI receiver closes the frame after half the data arrives, producing a partial image.
How do I configure MAX9295/MAX9296 for YUV422 output on Jetson Orin?
Set MAX9296 register 0x031C to 0x1E (YUV422 data type), set the DT pixel format to yuv_uyvy8, and verify MEDIA_BUS_FMT_UYVY8_1X16 is in the tegra-camera-platform node.
What dmesg messages indicate a GMSL MIPI framing error?
nvcsi: vc0 crc error, nvcsi: force-fe triggered, vi: frame start timeout, and vi: overflow error.
Relevant Services
NVIDIA Jetson Expert Support
Stuck on a Jetson bring-up?
We've debugged this failure mode before. BSP, device tree, camera pipelines, OTA, most blockers clear in the first session. No long retainers. No guessing.
Frequently Asked Questions
What is a FORCE_FE error in GMSL camera capture on Jetson?
FORCE_FE is a deserializer register that forces a Frame End event on the MIPI output regardless of whether the incoming GMSL frame has completed. When the deserializer outputs more data than the VI pipeline expects — caused by a YUV422 vs RAW format mismatch — VI closes the frame early and triggers a FORCE_FE MIPI protocol error. The symptom is a partial frame where the top 2/3 of the image is valid and the bottom is black or garbage.
Why does GMSL YUV422 capture show only the top portion of the frame?
The most common cause is a mismatch between the deserializer output format and the VI/CSI configuration. MAX9296 in YUV422 8-bit mode outputs twice the byte count per line compared to RAW8, but if the DT or kernel driver configures the CSI receiver for RAW8 pixel format, VI expects half the data and closes the frame when its line counter hits the expected byte count, resulting in a truncated frame.
How do I configure MAX9295/MAX9296 for YUV422 output on Jetson Orin?
Set the MAX9296 PIPE_X register to YUV8 (0x5F bit configuration) and configure the MIPI output data type to 0x1E (YUV422 8-bit). In the device tree, set the CSI port bus-width to 8 and the tegra-camera-platform sensor format to MEDIA_BUS_FMT_UYVY8_1X16. Also set num_lanes to match — YUV422 from GMSL typically uses 4 lanes to maintain the same bandwidth as the equivalent RAW12 sensor.
What kernel dmesg messages indicate a GMSL MIPI framing error?
Look for: nvcsi: vc0 crc error, nvcsi: force-fe triggered, vi: frame start timeout, vi: overflow error. These appear when the CSI receiver detects a protocol violation from the deserializer output. The messages may appear on every frame or intermittently depending on whether the mismatch is systematic or timing-related.
Written by
Andrés CamposCo-Founder & CTO · ProventusNova
8 years deep in embedded systems, from underwater ROVs to edge AI. Andrés leads every technical delivery personally.
Connect on LinkedInRelated Articles
Jetson camera works with v4l2-ctl but fails to launch argus_camera — debug guide
Why your Jetson camera works with v4l2-ctl but argus_camera fails — tegra-camera DT node issues, sensor mode tables, and the V4L2-to-Argus fault path.
How to enable CSI0 on Jetson Orin in the device tree
Enable CSI0, CSI1, and CSI2 on Jetson Orin by configuring nvcsi and VI device tree nodes, port status, and lane count in your DT overlay.
MIPI CSI-2 from an FPGA on Jetson Orin — nvcsi deskew and custom source bring-up
Bring up a MIPI CSI-2 source from an FPGA on Jetson Orin — handling nvcsi deskew calibration, clock errors, and short frame faults.
nvargus crash and CaptureScheduler deadlock on Jetson — debug guide
Debug nvargus core dumps and CaptureScheduler deadlock on Jetson. libargus logs, JP6 libnvscf regression, and watchdog recovery patterns.