Jetson TX2 + PTP capture synchronization

I’m new to the Jetson platform. I was looking through the tegra multimedia api sample code, I see the libargus syncSensor solution to synchronize the capture of 2 streams. This is interesting and am wondering if there is a way to synchronize just a single camera capture to a PTP clock (e.g. /dev/ptp0)? e.g. to schedule the capture of a frame at a specific microsecond in the near future based on this clock?

Hi randy,
Your case is a new case and looks different from syncSensor. Please give more detail about the usecase so that we can check if it can be supported.

Thank you kindly for the response DaneLLL,

Yeah, its not quite the same, but I am still hoping you could shed some light on it perhaps. The goal is take an image at a very precise time (ideally with < 5 usec of variance), for a very short duration image capture (200 usec exposure). Currently we use a physical trigger cable tied to POE cameras which requires physically tethering devices with a trigger cable. We want to avoid this tethering. Additionally most POE camera don’t offer many post-processing features on board. We’d rather use a Jetson TX2 with a camera over the MIPI/CSI-2 bus for advanced processing for better scalability.

We know ahead of time at exactly what time the event we wish to capture will need to occur (via a PTP timestamp). The idea is to synchronize the Jetson TX2 NIC clock using ptp4l. Hopefully the Jetson NIC supports the required Tx/Rx hardware time-stamping (still waiting for the dev kits to arrive).

The unknown part is getting the camera to trigger at a precise time. Normally this is done in the FPGA for a standard POE camera, which allows for accurate triggering. I was hoping there is a way to do this with the Jetson TX2 device? Ideally scheduling a frame trigger time would be available through the libArgus API given a clock file descriptor (e.g. /dev/ptpX), but I haven’t seen such a call. I’d welcome any guidance on how to achieve this?

Hi,
It looks like your case probably cannot be achieved with public BSP release and requires further cooperation with us. Don’t see similar topics on forum search, but other users may have experiences to share.

Also please consider to contact NVIDIA salespersons to have further cooperation with us. Thanks.

Hi,

There are actually some brands of cameras that do support ptp directly in the camera. We Dalsa Genie Nano to make synchronized capture of cameras that are attached to the same switch. Works really well today. I am not sure about your tolerances but this works for us.

Best / Björn

“Jetson TX2 NIC clock using ptp4l. Hopefully the Jetson NIC supports the required Tx/Rx hardware time-stamping” So does it do this?

Hi,

We don’t support it by default. Is your usecase also synchronizing a Bayer sensor to PTP clock?

Is it hardware supported? What does by default mean? I just want to know if it is capable. Is there some secret thing you have to do to turn it on?

Hi paul,

Please share more detail about your usecase. Are you tryinh to bring up dual cameras with hardware synchronization?

We have camera modules from partners ( https://developer.nvidia.com/embedded/community/ecosystem ). To bring up sensors, we have [Sensor Driver Programming Guide] in https://docs.nvidia.com/jetson/l4t/index.html
What @TheBird64 proposes is not supported and more like a new feature. Need more information to check and evaluate.

I have a system where all units in the system on network that is capable of being sunk to a master PTP signal will be. I can’t go in to any more than that. I am asking about the NIC that is all.

Hi paul,

We don’t support it in TX2 module. Other users may share their experience and suggest you certain NIC cards.

paul.w.davis,

I don’t quite understand your purpose here. Could you elaborate your project?

TegraX2 NIC is actually a combination of our own MAC controller (eqos) + 3rdparty PHY (Broadcom).

Could you use command “ethtool -T eth0” to check the capability of our on-board ethernet?

In hopes this helps others, we spent some time to verify multiple (3) TX2 boards with PTP synchronization with the ultimate goal of taking images at a specific PTP timestamp.

We are still working on a viable camera option with a GPIO pin for triggering, but are able to show three TX2 boards toggling a GPIO pin on/off within a 1 microsecond tolerance. Note that the kernel pin toggling actually has up to 2 usec delay, but polling the system clock is quick (0.137 usec avg).

This is by no means a usable kernel (just a spin-loop), but demonstrates synchronization is possible, which can be confirmed on a scope. The kernel is trivial, it just watches the clock for a 1 second rollover and flips a pin.

// 'sudo apt install -y linuxptp'
//
// Run the daemon that sync's the NIC and system clock:
// sudo phc2sys -s /dev/ptp0 -m -w
//
// use:
// sudo insmod ptp4l_sync_test.ko && sudo rmmod ptp4l_sync_test.ko
// to install and remove

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/time.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("RS64");
MODULE_DESCRIPTION("Jetson TX2 PTP4L synchronization test.");
MODULE_VERSION("1.0");

// from: https://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout/
static unsigned int gpio5 = 398;

static bool	led5On = false;

static void runTest(void);

static int __init kern_init(void) {
	int result = 0;

	printk(KERN_INFO "PTP4L_TEST: Initializing the synchronization test\n");
	if (!gpio_is_valid(gpio5)) {
		printk(KERN_INFO "PTP4L_TEST: invalid GPIO\n");
		return -ENODEV;
	}

	// we want to use the GPIO in kernel space, not user space, do not export it to user space
	result = gpio_export(gpio5, false);
	if (!result) {
		printk(KERN_INFO "Could not export GPIO5: %d\n", result);
	}

	// sometimes this fails on the first try, not sure why?
	result = gpio_request(gpio5, "sysfs");
	if (!result) {
		printk( KERN_INFO "Could not allocate GPIO5 result: %d, trying again\n", result );
		result = gpio_request(gpio5, "sysfs");
		if (!result) {
			printk( KERN_INFO "Could not allocate GPIO5 result: %d\n", result );
			return -ENODEV;
		}
	}

	// led starts off
	result = gpio_direction_output(gpio5, led5On);
	if (result) {
		printk(KERN_INFO "Could not set GPIO5 direction to output: %d\n", result);
		return -ENODEV;
	}

	gpio_set_value(gpio5, false);
	runTest();

	return result;
}

static void __exit kern_exit(void) {
	gpio_set_value(gpio5, 0);
	gpio_free(gpio5);
	printk(KERN_INFO "PTP4L_TEST: Exiting\n");
}

static void runTest(void)
{
	int i = 0;

	static int LOOPS = 30;
	struct timespec ts_current;
	struct timespec ts_last;
	struct timespec captured[LOOPS];
	int pollCnt = 0;

	printk(KERN_INFO "PTP4L_TEST: Starting Test\n");

	// read the system clock, every time we pass an even 1 second mark, toggle the GPIO pin
	getnstimeofday(&ts_last);
	do {
		getnstimeofday(&ts_current);
		++pollCnt;

		// has the second value changed since the last time we checked?
		if (ts_current.tv_sec != ts_last.tv_sec) {
			// flash the GPIO
			gpio_set_value(gpio5, true);
			udelay(10);
			gpio_set_value(gpio5, false);
			captured[i] = ts_current;
			++i;
		}

		ts_last = ts_current;
	} while(i < LOOPS);

	for(i = 0; i < LOOPS; ++i) {
		printk("%d: %lld.%.9ld\n", i, (long long)captured[i].tv_sec, captured[i].tv_nsec);
	}

	printk("Average clock polls per second = %d\n\n", pollCnt / LOOPS);
	printk(KERN_INFO "PTP4L_TEST: Ending Test\n");
}

module_init(kern_init);
module_exit(kern_exit);

Thanks this is exactly what I was looking to find!