System designExplainer

USB3 Vision payload transfer size: what the device must report

SiPayloadTransferSize and SiPayloadTransferCount decide whether a USB3 Vision device streams. The payload arithmetic, a Mono8 example, and the stall they fix.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01Who writes which register, and when
  2. 02The four device registers and the identity that binds them
  3. 03How the host assembles one frame
  4. 04Worked example: 1920 × 1080 in Mono8
  5. 05The failure each wrong value produces
  6. 06Verify the registers before the first real frame
  7. 07What the payload split does not fix
  8. 08Set up the test rig, then decide
  9. 09Questions

Your USB3 Vision device enumerates, serves its GenICam XML and opens the stream — then every frame stalls: the host reports frames produced but none consumed, and the image data sits in the device's buffers. Before you touch the endpoint descriptors, read four registers in the stream interface register map (SIRM): SiPayloadTransferSize, SiPayloadTransferCount, SiPayloadFinalTransfer1Size and SiPayloadFinalTransfer2Size. The host cuts the incoming bulk stream into leader, payload and trailer using exactly these numbers, so a wrong value stalls the stream no matter how correct the rest of the firmware is. Here is the arithmetic each register must hold for any width, height and pixel format, a worked Mono8 example with the division shown, and the failure signature each wrong value produces — written for engineers bringing up a U3V device in firmware.

Who writes which register, and when

USB3 Vision keeps control and stream apart. The control interface serves the GenICam feature map over the control endpoint; the stream interface carries the image bytes over a bulk-in endpoint. The SIRM lives on the control side but governs the stream: its registers are read and written through control transfers while the data itself flows on the bulk pipe.

Six registers decide the split, and ownership is strict. The host writes two: SiMaxPayloadSize, the largest payload it can accept, and SiMaxTransferSize, the largest transfer it can assemble. Your firmware answers with four: how you actually cut the payload apart. Write those four after the host writes its two maximums, and rewrite them whenever the payload size changes — a new pixel format, a new ROI — or the host changes its maximums. While the stream runs they must hold still: the host builds its receive logic from them, so update them only between frames or with acquisition stopped.

The four device registers and the identity that binds them

The host's two maximums are questions; these registers are your answers.

Register Writer What it must contain
SiPayloadTransferSize Device Bytes in each full transfer of the payload, at most SiMaxTransferSize
SiPayloadTransferCount Device Number of full-size transfers per payload, at least 1
SiPayloadFinalTransfer1Size Device Payload bytes left after the full transfers, 0 if it divides exactly
SiPayloadFinalTransfer2Size Device Final transfer size for the fixed 16-byte image trailer

Two further registers report history and are handy on the bench: SiPayloadCount counts completed payloads and SiPayloadSize holds the size of the last completed one.

payload bytes = width × height × bytes per pixel SiPayloadTransferCount = floor(payload bytes ÷ SiPayloadTransferSize) SiPayloadFinalTransfer1Size = payload bytes mod SiPayloadTransferSize check: SiPayloadTransferCount × SiPayloadTransferSize + SiPayloadFinalTransfer1Size = payload bytes

That check line is the whole protocol in one equation: if your four registers fail it for the current resolution and pixel format, the stream cannot work. Three constraints ride along. SiPayloadTransferSize must not exceed the host's SiMaxTransferSize, the payload must fit within SiMaxPayloadSize, and SiPayloadTransferCount must never be zero. A transfer here is the SIRM's own unit — a block of bulk data your firmware commits as one item, not a USB packet: a SuperSpeed bulk packet carries at most 1,024 bytes, so a 1 MiB transfer spans over a thousand packets.

How the host assembles one frame

Each image crosses the bulk endpoint as three chunks in fixed order: leader, payload, trailer. The leader is a small header describing the image — offsets, width, height, pixel format — and the host sizes it from the stream format itself, not from the SIRM. The trailer is short and fixed; its final transfer size is the fourth register's job. The payload is what the other three registers describe: the host accepts SiPayloadTransferCount transfers of SiPayloadTransferSize bytes, then one final transfer of SiPayloadFinalTransfer1Size bytes when that value is non-zero, then the trailer.

The host never searches for frame boundaries. It counts transfers. That is why a wrong count rarely produces a visible corrupt image — it produces no image at all, or a stream that never settles.

Worked example: 1920 × 1080 in Mono8

A host opens the stream from a 1920 × 1080 mono camera running Mono8 and writes SiMaxPayloadSize = 16,777,216 B (16 MiB) and SiMaxTransferSize = 4,194,304 B (4 MiB). The payload is:

1920 px × 1080 px × 1 byte = 2,073,600 bytes

Two device choices stream identically, and the host cannot tell the difference.

One full-size transfer: 2,073,600 B fits inside the host's 4,194,304 B maximum, so set SiPayloadTransferSize = 2,073,600 B. Then SiPayloadTransferCount = floor(2,073,600 ÷ 2,073,600) = 1 and SiPayloadFinalTransfer1Size = 0; SiPayloadFinalTransfer2Size = 16 B for the trailer.

One fixed chunk size for every resolution: with SiPayloadTransferSize = 1,048,576 B (1 MiB), SiPayloadTransferCount = floor(2,073,600 ÷ 1,048,576) = 1, and SiPayloadFinalTransfer1Size = 2,073,600 − 1,048,576 = 1,025,024 B. Check: 1 × 1,048,576 + 1,025,024 = 2,073,600 ✓.

Either way the host consumes 2,073,600 payload bytes plus 16 B of trailer per frame. What it cannot absorb is the broken pair a stalling device reports — for example SiPayloadTransferSize = 3,424,256 B with SiPayloadTransferCount = 0. The identity then collapses to zero payload bytes and reception ends before the first byte arrives.

The failure each wrong value produces

Ranked by how often each one shows up on the bench:

  1. SiPayloadTransferCount = 0. The host computes zero payload transfers, ends payload reception immediately and returns no buffers. Frames pile up in your device's memory until you stop acquisition — the produced-but-never-consumed signature, for example ten frames produced and zero consumed.
  2. SiPayloadTransferSize above SiMaxTransferSize. The host refuses the stream or mis-chunks it; expect a start-up error rather than damaged images.
  3. SiPayloadFinalTransfer1Size left at 0 when a remainder exists. Every frame arrives short by the remainder bytes; the host times out waiting for them or drifts its offsets, and images tear by the same amount on every frame.
  4. Registers never updated. The host writes its maximums, or the pixel format or ROI changes, and your four registers still hold power-up zeros or stale values. The host reads numbers that describe a payload you no longer send.
  5. Byte-order or wrong-address writes. The three payload registers read back as huge nonsense values — 3,424,256 B against an expected 2,073,600 B — while unrelated SIRM registers read correctly.

If the identity holds and frames still drop or crawl, the split is innocent; the cause is throughput or host buffering, the failure modes described in USB3 Vision transfer errors: diagnose bandwidth and buffers and in USB3 Vision bandwidth reporting zero during acquisition.

Verify the registers before the first real frame

Each check isolates one fault class and costs minutes:

  • Compute the four values by hand for the current width, height and pixel format, then read the registers back through the host tool. The identity must hold exactly.
  • Read the _L and _H halves of each 64-bit register as separate 32-bit words and confirm the byte order; a swapped 64-bit write still returns plausible-looking large numbers.
  • Change the ROI height by one row and re-read: the total payload must move by width × bytes per pixel, and the count or the final transfer must move with it.
  • Stream one frame of a known ramp pattern and have the host report consumed bytes: payload + leader + trailer exactly, nothing left over.

Compare against a camera that already streams. Put a standard area scan camera on the same host and host tool, set the same resolution and pixel format, and treat its clean consumption as the target behavior:

Area scan camerasHikrobot MV-CT0MU0060/R/NN/NN 6 MP Area Scan Camera, 3rd Gen., USB3.0, Mono, BASEMV-CT0MU0060/R/NN/NN
Sensor format
1/1.8"
Lens mount
C-mount
$969.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
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

Any of these USB3 area scan cameras, from 6 MP to 20 MP, gives you the end state: a stream the host consumes cleanly at whatever resolution and pixel format you set. Reproduce that behavior in your firmware for the same numbers and the protocol is off your risk list.

What the payload split does not fix

The SIRM numbers shape frames; they do not buy throughput. Bulk transfer on SuperSpeed is best effort: the link carries 5 Gbit/s raw, which is 500 MB/s of data after 8b/10b encoding, and a working host delivers roughly 350-450 MB/s. Firmware whose payload bytes per second exceed that drops frames with flawless registers. Budget the link per camera — the per-camera arithmetic is in Reduce USB3 camera bandwidth: the per-camera budget math — and give the host enough receive buffers, as in reuse image buffers instead of per-frame allocation and two USB3 cameras at full resolution stream: raise the host USB buffer.

Host-side frame buffers are sized from the same arithmetic: bytes per pixel sets both the payload and the host allocation, a connection covered in color image buffer no size info error: match pixel format.

USB3 Vision also defines GenDC, a generic container format, as an alternative payload type for multi-part or non-image data. A GenDC container still crosses the endpoint as leader, payload and trailer bytes, so the split identity applies to its total size unchanged.

Set up the test rig, then decide

Until the identity holds, no host consumes a frame; once it does, any stable machine streams. Run the bring-up on the host that will stream in production rather than a development laptop: a vision controller with USB 3 ports such as the MV-VC2140-128G40-1T keeps the same silicon and the same driver stack on every run.

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$1,679.00View partBuild a system with it

The decision, per case. Building your own U3V device: write the four registers from the formula and verify with the checklist above. Debugging a stalled stream: read the three payload registers first — a count of zero explains produced-but-unconsumed frames more often than any endpoint problem. Deciding between building and buying: if the sensor is your part and the stream is a commodity, a finished camera removes the whole protocol from your critical path; pick one from the camera finder or start at the camera step of the configurator.

Payload-budget questions go to the contact page; stream-level diagnostics beyond these registers sit on the systems topic page.

Questions

How many bytes is one Mono8 frame?

Width × height × 1 byte. A 5 MP sensor with 2448 × 2048 pixels produces a 5,013,504-byte payload. With a 1,048,576-byte SiPayloadTransferSize the device reports SiPayloadTransferCount = 4 and SiPayloadFinalTransfer1Size = 819,200, because 4 × 1,048,576 + 819,200 = 5,013,504. Add the leader bytes and the 16-byte trailer for the total the host consumes per frame.

What should SiPayloadTransferCount be for a 4000 × 3000 Mono8 sensor?

The payload is 4000 × 3000 × 1 B = 12,000,000 bytes. With a 1,048,576-byte transfer size: count = floor(12,000,000 ÷ 1,048,576) = 11 and final transfer = 12,000,000 − 11,534,336 = 465,664 bytes. With a 4,194,304-byte transfer size: count = 2 and final transfer = 12,000,000 − 8,388,608 = 3,611,392 bytes. Both satisfy the identity, so either streams.

Why does my host produce frames but consume none?

In almost every case the device reports SiPayloadTransferCount = 0. The host then computes a zero-byte payload, ends payload reception at once and returns no buffers, so frames accumulate in the device until acquisition stops. Rewrite the count as floor(payload ÷ transfer size) — at least 1 — after every change of resolution, pixel format or host maximum.

Does the transfer size change USB3 bandwidth or frame rate?

No. The registers decide only how one frame is fragmented; the payload bytes per frame and the bulk throughput are unchanged. Frame rate is payload bytes per frame divided by sustained throughput, and sustained throughput is a link-budget question, not a transfer-sizing question. Changing SiPayloadTransferSize cannot rescue a link that is out of budget.

Are USB3 Vision SIRM registers little-endian or big-endian?

Little-endian. Each 64-bit register occupies a low half (_L) and a high half (_H) of 32 bits each, least-significant byte first. Firmware that writes them in the wrong byte order still reads back as large plausible-looking numbers while unrelated registers behave, which is why the bug hides. Check byte order whenever a host read-back disagrees with the value the firmware wrote.