Jetson Nano + L4T R32.3.1: SPI not working even after enabling via jetson-io.py

This is to report an issue I encountered in R32.3.1, using the jetson-io.py tool to enable SPI.

Note: Thanks for providing this new tool!

I am porting my sensor from Raspberry Pi 3B to Nvidia Jetson Nano.
I am using SPI0 to connect my sensor, specifically pins 19, 21, 23, 24, 26.
Those pins are properly enabled by jetson-io.py when I choose the enable SPI option.
My sensor slave is using pin 26 for CS, so that’s CS1, and thus, will be CS pin for SPI0 channel 1.

When I checked spidev devices, I saw these:

nvidia@nvidia:~/$ ll /dev/*spi*
crw-rw---- 1 root gpio 153, 0 Jan 31 17:18 /dev/spidev0.0
crw-rw---- 1 root gpio 153, 2 Jan 31 17:18 /dev/spidev1.0

I tried sending data to /dev/spidev1.0 (used linux’s spidev_test.c as reference) but I don’t receive any signals in SPI0 pins when I did that (checked via oscilloscope).

So next, I tried to read/write data at /dev/spidev0.0 and there was CLK, MOSI, but my sensor wasn’t responding.
The CS being driven by Nano as the Master was pin 24 (CS0), which was for channel 0.
Since wrong CS was being triggered by Nano, I can’t use the SPI0 channel 1 connection properly.

So I checked my working SPI setup in Raspberry Pi Model 3B and that one had this:

raspi@raspi:~/$ ll /dev/*spi*
crw-rw---- 1 root gpio 153, 0 Jan 31 18:21 /dev/spidev0.0
crw-rw---- 1 root gpio 153, 2 Jan 31 18:21 /dev/spidev0.1

This means that:

  • /dev/spidev0.x is actually for SPI0 (19, 21, 23, 24, 26);and
  • /dev/spidev1.x is actually for SPI1 (13, 16, 18, 22, 37).

And if 2 channels will be used for SPI0, there should have been /dev/spidev0.0 and /dev/spidev0.1 for each.

So my problem seems to be, the jetson-io.py tool only generated pin-config for /dev/spidev0.0 but not /dev/spidev0.1 - and I need to use /dev/spidev0.1 if my SPI slave’s CS is connected at pin 26 (CS1).
I believe both /dev/spidev0.0 and /dev/spidev0.1 should be available for SPI0 when you enable SPI0 via jetson-io.py, considering both pin 24 (CS0) and pin 26 (CS1) are both enabled and available for use anyway.

In any case, I had to check if my theory is right so I did the following steps.

  1. I decompiled the generated dtb (for the compatible dtb, I had to check which one was before I found the correct one) by Nano at /boot/dtb, and extracted its DTS. I saw this part in that DTS:
spi@7000d400 {
<snipped this part>
<snipped this part>
                spi@0 {
                        compatible = "spidev";
                        reg = <0x0>;
                        spi-max-frequency = <0x1f78a40>;
                        nvidia,enable-hw-based-cs;
                        nvidia,rx-clk-tap-delay = <0x7>;
                };
  1. I figured I had to add another entry like this just below that spi@0 block, to make /dev/spidev0.1 appear:
+                spi@1 {
+                        compatible = "spidev";
+                        reg = <0x1>;
+                        spi-max-frequency = <0x1f78a40>;
+                        nvidia,enable-hw-based-cs;
+                        nvidia,rx-clk-tap-delay = <0x7>;
                };
  1. After saving the new dts (tegra210-p3448-0000-p3449-0000-b00-user-custom-modified-spidev0-1-enabled.dtb), I re-compiled the dts into a new dtb;

  2. Pasted that new dtb to both /boot/dtb (for jetson-io.py use) and /boot (for actual reference of kernel upon boot-up);

  3. Changed the /boot/extlinux/extlinux.conf to let kernel refer that new dtb upon boot-up like this:

LABEL JetsonIO
        MENU LABEL Custom 40-pin Header Config
        LINUX /boot/Image
-        FDT /boot/tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb
+        FDT /boot/tegra210-p3448-0000-p3449-0000-b00-user-custom-modified-spidev0-1-enabled.dtb
        INITRD /boot/initrd
        APPEND ${cbootargs}
  1. Did a reboot.

  2. After that I rechecked my spidev, and /dev/spidev0.1 is finally added there:

nvidia@nvidia:~/$ ll /dev/*spi*
crw-rw---- 1 root gpio 153, 0 Jan 31 19:36 /dev/spidev0.0
crw-rw---- 1 root gpio 153, 1 Jan 31 19:36 /dev/spidev0.1
crw-rw---- 1 root gpio 153, 2 Jan 31 19:36 /dev/spidev1.0

I tried and my SPI was working properly, using pin 26 (CS1) and sending/writing data to /dev/spidev0.1.

My question is, are the steps I did above correct? Did I miss or misunderstood anything?

  1. If the steps above are NOT correct, can you please advise the correct way of doing this?
  2. If the steps above are correct, can I request for Nvidia to fix this in their next release (ie, make jetson-io.py automatically add spidev pin config for channel 1 too, not just channel 0)? Otherwise, us using the channel 1 will anyway still need to re-compile the dts and all, which I avoid as much as possible which was the reason why I moved from R32.2.0 to R32.3.1 (since dts/dtb stuff are like a blackhole for the most of us... I think).

I tried checking around the forums but I haven’t found a similar issue (maybe because R32.3.1 is new).

Thank you very much in advance.

Note: If I don’t do the above change, I can make my SPI work with my current setup by shorting pin 24 and pin 26, but that defeats the purpose of having 2 channels for SPI0.

Update the dtb file by flash command instead of modified the extlinux.conf would be safe due to some plugin manager need to modify the device tree context dynamically.

  1. replace the dtb …/Linux_for_tegra/kernel/dtb/xxxx.dtb
  2. sudo ./flash.sh -r -k kernel-dtb jetson-xxx mmcblk0p1

https://docs.nvidia.com/jetson/l4t/Tegra%20Linux%20Driver%20Package%20Development%20Guide/flashing.html#wwpID0E03E0HA

I see. Thanks for the answer Shane - I’m looking into this now.

So does this mean, that the only incorrect thing I did was how I reflashed the new DTB (meaning, how I changed the DTS before that was correct)?

Also, was I right that the problem was that the /dev/spidev0.1 (channel 1 for SPI0) was not enabled by the “enable SPI” feature of jetson-io.py? If I was right, may I ask where I can request this as a Change Request for the next L4T release?

Please confirm. Thank you!

One more thing.

I tried doing it this way, although I had to change the step (2) to:

sudo ./flash.sh -k DTB -d xxxxx.dtb jetson-nano-qspi-sd mmcblk0p1

… because putting ‘-r’ results to “cannot find system.img”, and ‘kernel-dtb’ results to “unknown partition”. I executed modified flash.sh during FRC mode (FRC pins shorted plus USB cable connected to host PC), and so after the flash.sh execution, it says “DTB flashed successfully” and then a reboot was automatically triggered. During that session, I can see my DTB changes, however, if I do a reboot, like get out of FRC mode, or turn off/on the device - my DTB changes are not there anymore. It’s as if my flash.sh execution is only in RAM.

Can you please advise on this?
Thank you.

Please have apply below patch for the DTB back to original after reboot.

https://devtalk.nvidia.com/default/topic/1069873/jetson-nano/j4-3-r32-3-update-the-dtb-failed-on-jetson-nano-a02-sd-card-version-/post/5419857/#5419857

Hey, Shane. Thanks for the reply. Tried the link you gave but it wasn’t working even after a few times. Tried searching the topic number, also failed.

Could you check the file /opt/nvidia/l4t-bootloader-config/nv-l4t-bootloader-config.sh content is modify in Nano after boot to ubuntu.

Hi majiiiiiiiiiiii,

Have you managed to get issue resolved? Any result can be shared?

Hi ShaneCCC and kayccc:

After I read this comment, I found that this thread might just go back and forth with 1 comment a day and I’m kinda in a hurry and needed to move on since my task is more than just enabling the SPI (that’s just the first step).
My first reaction was, “What changes exactly are you expecting?” You should have placed some other info in the same comment like, “You should see this line there, and after that, you can check if . And if you see something else like , then that means you didn’t do properly so you should do next”.

So since my SPI is working with the solution I posted as the first post in this thread here which just follows the flow of jetson-io.py anyway:
https://devtalk.nvidia.com/default/topic/1070741/jetson-nano/jetson-nano-l4t-r32-3-1-spi-not-working-even-after-enabling-via-jetson-io-py/post/5424509/#5424509

… and ShaneCCC’s advise seems to not work as I mentioned here:
https://devtalk.nvidia.com/default/topic/1070741/jetson-nano/jetson-nano-l4t-r32-3-1-spi-not-working-even-after-enabling-via-jetson-io-py/post/5427246/#5427246

… I’ll stick with my solution “for now”, unless I find problems somewhere. As much as I want to spend more time on ShaneCCC’s solution since it came from NVIDIA officially, I can’t wait day per day with 1 vague comment each for the update on how to work that out properly… I hope you understand.

I do really appreciate you guys at least looking over my problem over thousands of posts here though. If you do comment with a solution with complete steps unlike the one I’m saying, I’ll still try that for the sake of everyone else watching out this thread. Thank you!

There’s two things need to check.

  1. Check the if the pins are enable as gpio pin by below command like https://elinux.org/Jetson/TX1_SPI to check the C and B group.
    sudo cat /sys/kernel/debug/tegra_gpio

  2. Check below pin address by devmem2 to make sure the bit [0-1] is 0

70003050: PINMUX_AUX_SPI1_MOSI_0
70003054: PINMUX_AUX_SPI1_MISO_0
70003058: PINMUX_AUX_SPI1_SCK_0
7000305c: PINMUX_AUX_SPI1_CS0_0
70003060: PINMUX_AUX_SPI1_CS1_0
70003064: PINMUX_AUX_SPI2_MOSI_0
70003068: PINMUX_AUX_SPI2_MISO_0
7000306c: PINMUX_AUX_SPI2_SCK_0
70003070: PINMUX_AUX_SPI2_CS0_0
70003074: PINMUX_AUX_SPI2_CS1_0