Sequencer Configuration

View as Markdown

The heart of the HSB Native Latency Tool lies in its precise sequencer configuration, which synchronizes LED triggers with camera frame events at the hardware level. Different camera sensor types require different timing strategies due to their distinct capture mechanisms.

The HSB Native Latency Tool provides complete example implementations for each sensor type, demonstrating the specific timing adjustments and GPIO control sequences required for accurate latency measurement.

The HSB Native Latency Tool includes two example applications in the examples/ directory:

  • e2e_imx274_latency.py - Rolling shutter camera implementation (IMX274)
  • e2e_vb1940_latency.py - Global shutter camera implementation (VB1940)

Each implementation showcases the hardware sequencer programming, event handling, and timing synchronization specific to that sensor type, providing a complete reference for implementing latency measurement with your own camera sensors.

Rolling Shutter Sequencer Setup

The HSB Native Latency Tool uses hardware sequencers to precisely control GPIO events synchronized to camera frame timing. The following code demonstrates how to configure the sequencer for rolling shutter cameras.

Event Sequencer Implementation

The code snippets below are from the rolling shutter application e2e_imx274_latency.py.

1def setup_sequencer(self):
2 # GPIO register addresses
3 GPIO_DIRECTION_REG_BASE = 0x0000002C
4 # GPIO module control registers
5 GPIO_DELAYED_IO_OUTPUT_REG = 0x70000014
6 GPIO_MODULE_CLEAR_REG = 0x7000080C
7 GPIO_MODULE_ENABLE_REG = 0x700008F0
8 GPIO_DELAY_REG = 0x70000804
9 GPIO_DELAYED_SET_REG = 0x70000814
10
11 self._hololink.write_uint32(
12 GPIO_DELAYED_IO_OUTPUT_REG, 0x00000100
13 ) # Enable DELAYED_IO output on GPIO
14
15 # GPIO Pin 0 will be set HIGH on Frame Start event
16 sequencer = self._hololink.sif0_frame_start_sequencer()
17 sequencer.write_uint32(GPIO_MODULE_CLEAR_REG, 0x1) # Clear all
18 sequencer.write_uint32(
19 GPIO_MODULE_ENABLE_REG, 0x1
20 ) # To enable the whole module
21 sequencer.write_uint32(GPIO_DELAY_REG, 0x0) # 0ms delay
22 sequencer.write_uint32(GPIO_DELAYED_SET_REG, 0x1) # Delayed set
23 sequencer.write_uint32(GPIO_DIRECTION_REG_BASE, 0x2) # Set pin 1 as Input
24 sequencer.enable()
25
26 # Setting up sequencer to retrieve timestamp on LED_TRIGGER aka GPIO0
27 sequencer = self._hololink.gpio0_sequencer()
28 sequencer.enable()
29
30 # When the PD_ACTIVE aka GPIO1 goes HIGH, timestamp is retrieved to calculate end to end measurements.
31 # Also LED_TRIGGER aka GPIO0 is set to LOW to ACK that PD_ACTIVE went HIGH.
32 sequencer = self._hololink.gpio1_sequencer()
33 sequencer.write_uint32(
34 GPIO_MODULE_ENABLE_REG, 0x1
35 ) # To enable the whole module
36 sequencer.write_uint32(GPIO_MODULE_CLEAR_REG, 0x1) # To clear all
37 sequencer.enable()

Key Configuration Parameters

  • GPIO_DELAYED_IO_OUTPUT_REG (0x70000014) - Enables DELAYED_IO output on the GPIO pin
  • GPIO_MODULE_CLEAR_REG (0x7000080C) - Clears all previous sequencer states
  • GPIO_MODULE_ENABLE_REG (0x700008F0) - Enables the sequencer module
  • GPIO_DELAY_REG (0x70000804) - Sets the LED trigger delay (0 for rolling shutter; set to sensor_readout_time for global shutter)
  • GPIO_DELAYED_SET_REG (0x70000814) - Enables delayed set functionality

Event Acknowledgment for Continuous Measurement

To enable continuous latency measurements, events must be acknowledged after each measurement cycle. The following MultiEventAcknowledgmentOperator class is implemented in both applications e2e_imx274_latency.py and e2e_vb1940_latency.py:

1class MultiEventAcknowledgmentOperator(holoscan.core.Operator):
2 """
3 Operator that acknowledges events after a specified frame count.
4 """
5
6 def __init__(self, fragment, hololink, frame_threshold=50, *args, **kwargs):
7 super().__init__(fragment, *args, **kwargs)
8 self._hololink = hololink
9 self._frame_threshold = frame_threshold
10 self._frame_count = 0
11
12 def setup(self, spec):
13 spec.input("input")
14 spec.output("output")
15
16 def compute(self, op_input, op_output, context):
17 in_message = op_input.receive("input")
18
19 self._frame_count += 1
20
21 if self._frame_count >= self._frame_threshold:
22 logging.info(f"Acknowledging events after {self._frame_count} frames")
23 self._hololink.write_uint32(0x0000020C, 0xFFFFFFFF) # Set flag
24 self._hololink.write_uint32(0x0000020C, 0x0) # Clear flag
25 # Reset frame counter for next acknowledgment cycle
26 self._frame_count = 0
27
28 op_output.emit(in_message, "output")

Sequencer Operation Flow

  1. Frame Start Detection - HSB FPGA detects camera frame start signal
  2. Immediate LED Trigger - GPIO pin 0 set high with 0ms delay (rolling shutter)
  3. Event Processing - LED_TRIGGER and PD_ACTIVE events are processed
  4. Frame Counting - MultiEventAcknowledgmentOperator tracks frame count
  5. Event Acknowledgment - After N frames, events are acknowledged for next cycle
  6. Cycle Repeat - Process repeats for continuous measurement

Global Shutter Modifications

For global shutter cameras (like VB1940), the sequencer configuration in e2e_vb1940_latency.py modifies the delay parameter to account for sensor readout time:

1# Global shutter configuration
2sequencer.write_uint32(GPIO_DELAY_REG, sensor_readout_time) # Add readout time delay

Where sensor_readout_time is the specific readout time for your sensor mode.

Run Latency Tool app

Once your HSB system is operational, run the app using:

$# Navigate to latency measurement examples
$# for IMX274
$python3 examples/e2e_imx274_latency.py --fullscreen
$# for VB1940
$python3 examples/e2e_vb1940_latency.py --fullscreen