Three GMSL2 cameras synchronized in an array on Jetson Orin for multi-camera frame sync
gmsl2multi-cameraframe syncjetson orintriggersynchronization

Synchronizing multiple GMSL2 cameras on Jetson Orin: frame sync

Andres Campos ·

Synchronizing multiple GMSL2 cameras on Jetson requires hardware-level frame sync — software timestamp comparison introduces too much jitter for stereo or multi-view applications. The FSYNC signal travels through the GMSL2 control channel from Jetson to each camera, triggering simultaneous exposure across all sensors. This post covers the full synchronization setup.

Key Insights

  • Hardware frame sync via FSYNC is the only reliable way to synchronize GMSL2 cameras — software approaches drift within seconds
  • The FSYNC signal travels from Jetson GPIO → MAX9296A → GMSL2 control channel → MAX9295A → camera sensor trigger input
  • Virtual channel assignment is mandatory for multi-camera setups — two cameras on the same VC corrupt both streams
  • The MAX96724 quad-deserializer simplifies 4-camera designs by aggregating all streams into a single MIPI output
  • Frame sync failures look like intermittent frame drops or tearing, not a complete pipeline failure — harder to diagnose

Why frame sync matters for multi-camera

If you are building a stereo, surround-view, or array camera system, unsynchronized frames are not a cosmetic problem — they cause real failures. Stereo depth estimation requires both cameras to capture the same moment in time. Surround-view stitching requires frames to align spatially. Even 10 ms of offset between cameras introduces motion artifacts that make the output unusable for most applications.

Free-running cameras — even cameras with identical settings — drift relative to each other over time because their internal oscillators have tolerance. Two cameras nominally running at 30 fps may be 16.7 ms apart (half a frame period) within a minute of start-up.

Hardware frame sync solves this by driving all cameras from a common trigger. Every camera captures on the same edge. Frame-to-frame timing error is in the microsecond range, which is acceptable for virtually any multi-camera application.

The FSYNC signal path in GMSL2

GMSL2 provides a control channel that runs bidirectionally alongside the video data. This control channel carries I2C/UART traffic and GPIO signals between the deserializer and serializer sides.

The FSYNC path for a dual-camera GMSL2 setup on Jetson Orin:

Jetson GPIO (configured as PWM or GPIO output)
  → MAX9296A FSYNC pin
    → GMSL2 control channel (both links simultaneously)
      → MAX9295A FSYNC pin (link 0)
      → MAX9295A FSYNC pin (link 1)
        → Camera sensor TRIGGER/SYNC input

This means a single Jetson GPIO triggers all cameras simultaneously. No separate wire per camera. No cable routing changes for additional cameras.

The FSYNC GPIO is configured in the DTS and the deserializer driver forwards it automatically once the link is locked.

/* Configure FSYNC GPIO in DTS */
max9296@48 {
    /* ... */
    fsync-gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(BB, 1) GPIO_ACTIVE_HIGH>;
    fsync-mode = "GMSL2";
    fsync-period = <3300000>; /* 33ms = ~30fps FSYNC period in nanoseconds */
};

Virtual channel assignment for multi-camera

The MAX9296A deserializer aggregates multiple camera streams onto a single MIPI output using MIPI CSI-2 virtual channels. Each camera gets a unique VC number.

Camera 0 → MAX9295A link 0 → MAX9296A → MIPI VC0 → NVCSI → V4L2 device 0
Camera 1 → MAX9295A link 1 → MAX9296A → MIPI VC1 → NVCSI → V4L2 device 1

The VC assignment is configured in the MAX9296A deserializer registers and must also be reflected in the DTS via vc_id:

/* Camera 0 — Virtual Channel 0 */
imx390@1a {
    sensor_modes {
        mode0 {
            vc_id = "0";
            /* ... */
        };
    };
};

/* Camera 1 — Virtual Channel 1 */
imx390@1b {
    sensor_modes {
        mode0 {
            vc_id = "1";
            /* ... */
        };
    };
};

If both cameras are on VC0, the NVCSI interleaves their data and both streams are corrupt. The failure looks like two unusable but active video streams — not a complete pipeline failure.

4-camera topology with MAX96724

For 4-camera designs on Jetson Orin, the MAX96724 quad-deserializer is the common solution. It supports 4 GMSL2 input ports and outputs 4 virtual channels over a single MIPI CSI-2 link.

Camera 0 → MAX9295A → MAX96724 port 0 → \
Camera 1 → MAX9295A → MAX96724 port 1 →  MIPI (VC0-VC3) → Jetson NVCSI
Camera 2 → MAX9295A → MAX96724 port 2 → /
Camera 3 → MAX9295A → MAX96724 port 3 → /

The MAX96724 requires a different kernel driver and DTS structure than the MAX9296A. NVIDIA’s reference drivers in L4T R36 include MAX96724 support for specific carrier board configurations.

Diagnosing sync failures

# Check frame timestamps across cameras
v4l2-ctl --stream-mmap -d /dev/video0 --stream-count=30 --stream-to=/dev/null -v 2>&1 | grep timestamp &
v4l2-ctl --stream-mmap -d /dev/video1 --stream-count=30 --stream-to=/dev/null -v 2>&1 | grep timestamp

# Compare timestamps — hardware sync: delta < 1ms
#                    software sync / no sync: delta varies widely

# Check FSYNC signal is reaching serializer
sudo i2cget -y <bus> 0x40 <fsync_status_register>
# Check MAX9295A FSYNC status register for sync detection

# Check virtual channel assignments
sudo media-ctl -p | grep "VC"

For the broader GMSL2 camera pipeline on Jetson, see GMSL2 camera driver on Linux: V4L2, MAX9296 kernel driver, device tree. For bring-up of the underlying GMSL2 link, see GMSL2 camera bring-up on Jetson Orin: MAX9295/MAX9296 setup.

The MIPI CSI-2 virtual channel specification is in the MIPI Alliance CSI-2 standard. The MAX9296A FSYNC configuration registers are documented in the Analog Devices MAX9296A datasheet.


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 the difference between hardware frame sync and software frame sync for GMSL2 cameras?

Hardware frame sync uses a dedicated FSYNC signal from the Jetson GPIO (or an external sync source) routed to each serializer via the GMSL2 control channel. All cameras trigger on the same hardware edge, so frames are captured within microseconds of each other. Software frame sync relies on the cameras running at the same nominal frame rate and the host timestamping frames as they arrive — frame capture offsets can be 10-50ms, which is unacceptable for stereo or surround-view applications.

How does the FSYNC signal reach GMSL2 cameras over coaxial cable?

The MAX9296A deserializer has a FSYNC input pin. When the host drives this pin, the deserializer forwards the signal to each connected serializer through the GMSL2 control channel. Each MAX9295A serializer then drives the FSYNC pin to the camera sensor. This is the primary mechanism for hardware frame sync in GMSL2 multi-camera systems — no separate physical wire to each camera is needed.

What is a virtual channel in GMSL2 and why does it matter for multi-camera?

MIPI CSI-2 supports 4 virtual channels (VC0–VC3) on a single physical link. In a GMSL2 multi-camera setup, each camera's data stream is assigned to a different virtual channel by the deserializer before being output over the MIPI link to Jetson. The Jetson NVCSI demultiplexes the virtual channels into separate capture streams. If two cameras are on the same virtual channel, their data is interleaved and both streams are corrupt.

Can I run 4 GMSL2 cameras on a single Jetson Orin NX?

Yes, with the right hardware. Jetson Orin NX supports 4 NVCSI ports and up to 8 MIPI lanes total. A quad-deserializer (MAX96724 or similar) connects to one or two NVCSI ports and outputs all 4 camera streams over MIPI using 4 virtual channels. Each camera uses 2 MIPI lanes (2-lane per camera × 4 cameras = 8 lanes total). Orin NX can handle this, but Orin Nano (fewer lanes) may require a different topology.

My multi-camera GMSL2 setup shows frame tearing on alternating cameras. What causes this?

Frame tearing between cameras almost always means hardware frame sync is not working and the cameras are free-running at slightly different effective frame rates. Even cameras with nominally identical frame rate settings drift relative to each other because crystal oscillators have tolerance. The fix is enabling hardware FSYNC so all cameras trigger from the same edge. Verify the FSYNC signal is reaching each serializer and that each sensor's trigger input is configured for external sync mode.

Andrés Campos, Co-Founder & CTO at ProventusNova

Written by

Andrés Campos

Co-Founder & CTO · ProventusNova

8 years deep in embedded systems — from underwater ROVs to edge AI. Andrés leads every technical delivery personally.

Connect on LinkedIn