Device Tree Overlay for PPS Support on JP4.6.4

Hello, I’ve read as many forum threads I can find on enabling PPS input using a device tree overlay but I think there must have been some changes since the Jetpack versions that were being used at the time the posts were made. I’ve run into an error that I can’t seem to work around and wanted to gather input. Here is the workflow so far, and the error I’m facing.

  1. I have the following jetson_nano_pps.dts file following examples on many other threads. One thing to note, I am having a hell of a time trying to trace the pin/GPIO numbers and 148 is copied from others. I am trying to target Pin 7 on the J41 header (the same as posted on this blog that many others reference, however instead of recompiling the kernel I need to apply an overlay due to my application: Enabling PPS on Jetson Nano)
/dts-v1/;
/plugin/;

/ {
    overlay-name = "PPS Input";
    jetson-header-name = "Jetson 40pin Header";
    compatible = "nvidia,p3449-0000-b00+p3448-0000-b00", "nvidia,p3449-0000-a02+p3448-0000-a02";
    fragment {
        target-path = "/";
        __overlay__ {
            pps: pps_gpio {
                compatible = "pps-gpio";
                gpios = <&tegra_main_gpio 148 1>;
                assert-falling-edge;
                status = "okay";
            };
        };
    };
};
  1. I have generated a jetson_nano_pps.dtbo file using the following command. sudo sudo dtc -O dtb -o /boot/jetson_nano_pps.dtbo -@ /home/nvidia/Downloads/jetson_nano_pps.dts

  2. I can see the “PPS Input” as an option when running the following Jetson IO command.sudo /opt/nvidia/jetson-io/config-by-hardware.py -l

This produces an warning that was noted by others but apparently doesn’t matter (according to the replies to the previous threads). Warning (gpios_property): Could not get phandle node for /fragment/__overlay__/pps_gpio:gpios

  1. When attempting to apply the overlay using Jetson IO, I receive a very non-descript error as follows, which is where I am stuck.
sudo /opt/nvidia/jetson-io/config-by-hardware.py -n "PPS Input"
Traceback (most recent call last):
  File "/opt/nvidia/jetson-io/config-by-hardware.py", line 125, in <module>
    main()
  File "/opt/nvidia/jetson-io/config-by-hardware.py", line 121, in main
    generate_dtb(jetson, dtbos)
  File "/opt/nvidia/jetson-io/config-by-hardware.py", line 44, in generate_dtb
    fn = jetson.create_dtb_for_headers(dtbos)
  File "/opt/nvidia/jetson-io/Jetson/board.py", line 376, in create_dtb_for_headers
    dtc.overlay(self.dtb, dtb, dtbos)
  File "/opt/nvidia/jetson-io/Utils/dtc.py", line 53, in overlay
    raise RuntimeError("Failed to overlay %s with %s!" % (dtb, files))
RuntimeError: Failed to overlay /boot/dtb/kernel_tegra210-p3448-0000-p3449-0000-b00.dtb with /boot/jetson_nano_pps.dtbo!

Unfortunately there are no comments in the /opt/nvidia/jetson-io/Utils/dtc.py file, but the function that is erroring is as follows.

def overlay(dtb, out, overlays):
    for overlay in overlays:
        __files_exist(dtb, overlay)
    files = ' '.join(overlays)
    if syscall.call('fdtoverlay -i "%s" -o "%s" %s' % (dtb, out, files)):
        raise RuntimeError("Failed to overlay %s with %s!" % (dtb, files))

Adding some debug print statements into this file I arrived at the following command that is being compiled by the function: fdtoverlay -i "/boot/dtb/kernel_tegra210-p3448-0000-p3449-0000-b00.dtb" -o "/boot/kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb" /boot/jetson_nano_pps.dtbo

Unfortunately the only output from running this command manually is Failed to apply /boot/jetson_nano_pps.dtbo (-1).

Any help would be greatly appreciated. Is there an error in how I am structuring the dts file? From everything I’ve read from the nvidia docs and from inspecting other dts files that shouldn’t be the case.

Thanks.

Hi roo,

Are you using the devkit or custom board for Jetson Nano?

PIN7 of J41 Expansion Header is PBB.00.

phandle is generated during flash, every node has its phandle.
Please try to modify the source of device to apply your change for pps.

            pps: pps_gpio {
                compatible = "pps-gpio";
                gpios = <&tegra_aon_gpio TEGRA_AON_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
                assert-falling-edge;
                status = "okay";
            };

Thanks KevinFFF for your assistance.

I am using the Jetson Nano on the nVidia DevKit carrier board.

Thanks for the pin reference!

I made the changes to the dts file as you suggested, however I now get an error when compiling the dtbo file. Here is my command and output.

nvidia@jetson:~$ sudo dtc -O dtb -o /boot/jetson_nano_pps.dtbo -@ /home/nvidia/Downloads/jetson_nano_pps.dts
Error: /home/nvidia/Downloads/jetson_nano_pps.dts:13.42-43 syntax error
FATAL ERROR: Unable to parse input tree

Line 13 is the gpios=... line in the dts file. Position 42-43 is the first letter of “TEGRA_AON_GPIO”. I’m guessing this is an invalid phandle? Is there a reference or file somewhere listing the available phandles?

For completeness, here is the full dts file after modification:

/dts-v1/;
/plugin/;

/ {
    overlay-name = "PPS Input";
    jetson-header-name = "Jetson 40pin Header";
    compatible = "nvidia,p3449-0000-b00+p3448-0000-b00", "nvidia,p3449-0000-a02+p3448-0000-a02";
    fragment {
        target-path = "/";
        __overlay__ {
            pps: pps_gpio {
                compatible = "pps-gpio";
                gpios = <&tegra_aon_gpio TEGRA_AON_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
                assert-falling-edge;
                status = "okay";
            };
        };
    };
};

Thank you.

What I shared is to be added in device tree source rather than overlay dtbo since your overlay dts could not find the definition of TEGRA_AON_GPIO.

Please add pps: pps_gpio { in the device tree source and re-compile kerenl image/dtb to apply the change.

Hi Kevin,

I am not able to recompile the kernel and flash. I’m specifically asking about achieving my goes with a device tree overlay as others have done in the past on this forum. I am running into issues that they didn’t face.

Do you have anything that you can suggest to make the overlay method work and overcome the errors I’m facing?

James

Then you have to get this line as the hex style.
please try the following:

gpios = <&tegra_main_gpio 0xA8 0>;

Please decompile /boot/dtb/kernel_XXX.dtb from your board to dts and share it as file here for further check.

Thanks for the assistance Kevin,

Unfortunately I am receiving the same error when compiling the DTBO regarding a missing phandle, and receive the same error as before when attempting to apply the DTBO.

Please see the attached text file containing an fdtdump of /boot/opt/kernel_tegra210-p3448-0000-p3449-0000-b00.dtb. This should be what is included in the Nano image from nVidia, I do have a camera driver installed from FRAMOS so there could be some changes.

kernel_tegra210-p3448-0000-p3449-0000-b00.txt (495.5 KB)

Please share your device tree before any modification for the devkit.

and refer to the following steps to apply the overlay dtbo for pps:

Step 1. create overlay dts (my-overlay.dts)
$ vim my-overlay.dts

/dts-v1/;
/plugin/;
 
/ {
    overlay-name = "My PPS Overlay";
    jetson-header-name = "Jetson 40pin Header";
    compatible = "nvidia,p3449-0000-b00+p3448-0000-b00";
 
    fragment@0 {
		target-path = "/";
		__overlay__ {
			pps_gpio {
				compatible = "pps-gpio";
				gpios = <0x5b 0xd8 0x0>;
				assert-falling-edge;
				status = "okay";
			};
		};
	};
};

Step 2. create overlay dtbo (my-overlay.dtbo)

$ dtc -O dtb -o my-overlay.dtbo -@ my-overlay.dts

Step 3. apply overlay dtbo through jetson-io tool

$ sudo cp my-overlay.dtbo /boot
$ sudo /opt/nvidia/jetson-io/config-by-hardware.py -l
$ sudo /opt/nvidia/jetson-io/config-by-hardware.py -n "My PPS Overlay"
$ sudo reboot
1 Like

Thank you KevinFFF! The changes to the gpios element of the overlay has allowed it to apply correctly. I’m now in the process of determining whether this has worked as desired and whether my GPS’ PPS signal is being received.

Is it possible for you to provide some reference or instructions on how you were able to come up with those hex values so that I might repeat it myself in the future if I need to make any changes?

Just to clarify, you are asking for the device tree prior to the FRAMOS camera devkit changes?

A quick update here, I appear to be receiving PPS signals from the GPS via the GPIO pin specified. Here are my results from some testing.

$ sudo ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1708021678.101498595, sequence: 59047 - clear  0.000000000, sequence: 0
source 0 - assert 1708021679.101498203, sequence: 59048 - clear  0.000000000, sequence: 0
source 0 - assert 1708021680.101286452, sequence: 59049 - clear  0.000000000, sequence: 0
...

Unfortunately I am struggling with getting this working in chrony via gpsd. As shown in the following output chrony is receiving the PPS signal but is marking it with an “x” meaning the sources is thought to be in error. I believe this means it’s not being used for timekeeping so I’m still working on debugging that.

$ chronyc sources
210 Number of sources = 10
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#? GPS                           0   4     0     -     +0ns[   +0ns] +/-    0ns
#x PPS                           0   4   377    19   +102ms[ +102ms] +/- 1286ns
...

I have a further update in case anyone else reads this thread attempting the same thing.

As you can see in my previous post the PPS signal has a ~100ms offset and therefore is not used by chrony as a source. This is due to the device tree overlay specifying the assert-falling-edge option. This may be valid for some GPS devices, however most should be referenced on the rising edge. The signal is usually held high for 100ms (again, not a rule, but most GPS seem to do this) before falling.

This was the source of the 100ms offset in my results. By modifying the dts file as follows and removing assert-falling-edge no offset is measured and chrony correctly syncs with the pps input.

/dts-v1/;
/plugin/;

/ {
    overlay-name = "PPS Overlay";
    jetson-header-name = "Jetson 40pin Header";
    compatible = "nvidia,p3449-0000-b00+p3448-0000-b00";

    fragment@0 {
        target-path = "/";
        __overlay__ {
            pps_gpio {
                compatible = "pps-gpio";
                gpios = <0x5b 0xd8 0x0>;
                status = "okay";
            };
        };
    };
};

Chrony results:

$ chronyc sources
210 Number of sources = 10
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#* PPS                           0   4   377    10    -10us[  -10us] +/-   18us
#? GPS                           0   4   377     7    -17ms[  -17ms] +/-  661us
$ chronyc sourcestats
210 Number of sources = 10
Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
==============================================================================
PPS                        24  18   366     +0.029      0.546   +126ns    56us
GPS                        24  12   366     -8.292      9.921    -15ms  1434us

TL;DR: Make sure you know what the signal looks like that your GPS device is outputting before naively applying a device tree overlay :)

@KevinFFF I’d still appreciate anything you can share on determining the hex values for the overlay.

1 Like

I just modify the source of device tree and get the desired hex value.
Then, repeat the whole steps to apply overlay dtbo as your need.

gpios = <0x5b 0xd8 0x0>;

0x5b is the phandle for your GPIO controller.
0xd8 is value for pin PBB.00, you could get this from the following definition in tegra-gpio.h. (27*8+0 = 216 = 0xd8)

#define TEGRA_GPIO_PORT_BB 27

#define TEGRA_GPIO(port, offset) \
  	((TEGRA_GPIO_PORT_##port * 8) + offset)

and the active level in gpio.h

#define GPIO_ACTIVE_HIGH 0
#define GPIO_ACTIVE_LOW 1

Thanks Kevin!

I’ve run into a new issue, while applying my device tree overlay does enable PPS it also disables/removes the device tree overlays from my camera driver. How can I have multiple overlays applied at the same time so that the camera and PPS can both work simultaneously? (when re-applying the camera driver overlay it removes PPS…)

I feel like it could be something as simple as specifying the device tree overlay compatibility in dts file, or perhaps specifying to jetson-io tools which device tree to apply the overlay to.

From other posts I’ve read that the jetson-io tools apply a newoverlay to the dtb located in/boot/dtb, which AFAIK is the “base” device tree. It appears I need to apply my PPS overlay to one located at /boot/kernel_tegra210-p3448-0000-b00-p3449-0000-b00-user-custom.dtb which is generated after installing the camera driver/overlay.

Update: I appear to have made this work by copying the “user-custom” device tree into the /boot/dtb directory, replacing the original one (after making a backup), then re-applying the additional overlay.

After a reboot both overlays are now applied and working. I’m not sure if this is the recommended approach however, please let me know if there is a “safer” way.

It should be okay to replace the original dtb with XXX-user-custom.dtb.

In addition, you could also run the following command to check the device tree from fs in runtime.

$ sudo dtc -I fs -O dts -o extracted_proc.dts /proc/device-tree