/dev/spi0.0 not work in l4t32.3.1

Hello guys,

There are spi0 node and spi1 node in the runing l4t32.3.1 of Nano dev kit. But when I use spidev_test tool test the /dev/spi0.0, it seem not work.

The borad info:

garret:~/nano/l4t32.3.1/Linux_for_Tegra$ sudo ./flash.sh jetson-nano-qspi-sd mmcblk0p1
###############################################################################
# L4T BSP Information:
# R32 , REVISION: 3.1
###############################################################################
# Target Board Information:
# Name: jetson-nano-qspi-sd, Board Family: t210ref, SoC: Tegra 210,
# OpMode: production, Boot Authentication: ,
###############################################################################
...
Board ID(3448) version(200)
...

The spi on l4t32.3.1:

sercomm@localhost:~$ ls /dev/spi*
/dev/spidev0.0  /dev/spidev1.0

sercomm@localhost:~$ cat /etc/nv_tegra_release
# R32 (release), REVISION: 3.1, GCID: 18186506, BOARD: t210ref, EABI: aarch64, DATE: Tue Dec 10 06:58:34 UTC 2019

sercomm@localhost:~$ sudo ./spidev_test_500 -D /dev/spidev0.0
spi mode: 0x0
bits per word: 8
max speed: 5000000 Hz (5000 KHz)
mode & SPI_TX_QUAD=0
mode & SPI_TX_DUAL=0
mode & SPI_RX_QUAD=0
mode & SPI_RX_DUAL=0
mode & SPI_LOOP=0
output_file=0
Function:[transfer]--LineNum:[193]
RX | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................................

But the /dev/spi0.0 on l4t32.2.1 with the jetson-nano-support method works fine.

rcomm:~$ head /etc/nv_tegra_release -n1
# R32 (release), REVISION: 2.1, GCID: 16294929, BOARD: t210ref, EABI: aarch64, DATE: Tue Aug 13 04:28:29 UTC 2019

sercomm:~$ sudo gpioinfo | grep -i spi0
        line  16:  "SPI0_MOSI"       unused   input  active-high
        line  17:  "SPI0_MISO"       unused   input  active-high
        line  18:   "SPI0_SCK"       unused   input  active-high
        line  19:   "SPI0_CS0"    "cs_gpio"  output  active-high [used]
        line  20:   "SPI0_CS1"       unused   input  active-high
sercomm:~$ ls /dev/spidev0.0
/dev/spidev0.0

sercomm:~$ sudo ./spidev_test_500 -D /dev/spidev0.0
spi mode: 0x0
bits per word: 8
max speed: 5000000 Hz (5000 KHz)
mode & SPI_TX_QUAD=0
mode & SPI_TX_DUAL=0
mode & SPI_RX_QUAD=0
mode & SPI_RX_DUAL=0
mode & SPI_LOOP=0
output_file=0
Function:[transfer]--LineNum:[193]
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@....â–’.

It should be the problem of uboot, how should I change it?

Thanks

I just saw the new jetpack/l4t release. I’ll test it out tonight.

Dear gtj,

Thanks so much.
Look forward to that.The uboot source seem change a lot, so your uboot patch can’t be patched through normal way.

Could you verify GPIO PinMux by below command
After rebooting, check tegra_gpio again, and now row C should be changed to 0x00, verifying those GPIO pins are now mapped to SPI mode:

$ sudo cat /sys/kernel/debug/tegra_gpio

Name:Bank:Port CNF OE OUT IN INT_STA INT_ENB INT_LVL
A: 0:0 24 00 00 24 00 00 000000
B: 0:1 0f 00 00 00 00 00 000000
C: 0:2 00 00 00 00 00 00 000000
D: 0:3 10 10 00 00 00 00 000000
E: 1:0 70 00 00 00 00 00 000000

Hi ShaneCCC,

Here it is.

sercomm:~$ cat /etc/nv_tegra_release
# R32 (release), REVISION: 3.1, GCID: 18186506, BOARD: t210ref, EABI: aarch64, DATE: Tue Dec 10 06:58:34 UTC 2019
sercomm:~$  sudo cat /sys/kernel/debug/tegra_gpio
Name:Bank:Port CNF OE OUT IN INT_STA INT_ENB INT_LVL
 A: 0:0 64 40 40 04 00 00 000000
 B: 0:1 00 00 00 00 00 00 000000
 C: 0:2 00 00 00 00 00 00 000000
 D: 0:3 00 00 00 00 00 00 000000

sercomm:~$ ./test_spi.sh
spi mode: 0x4
bits per word: 8
max speed: 5000000 Hz (5000 KHz)
mode & SPI_TX_QUAD=0
mode & SPI_TX_DUAL=0
mode & SPI_RX_QUAD=0
mode & SPI_RX_DUAL=0
mode & SPI_LOOP=0
Function:[transfer]--LineNum:[172]
verbose=1
TX | 74 65 73 74 20 73 65 72 63 6F 6D 6D 20 49 53 42 55 32 __ __ __ __ __ __ __ __ __ __ __ __ __ __  | test.sercomm.ISBU2 
Function:[transfer]--LineNum:[193]
RX | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __  | ..................

Thanks

@garretzou

I tested 32.3.1 and am not having any issues. I’m looping the actual mosi and miso pins and comparing the results so I know it’s working.

Did you run the jetson-io utility to set up the pins? The new standard dtb has the spidev device nodes but it doesn’t set up the pins.

Follow the instructions here…
https://docs.nvidia.com/jetson/archives/l4t-archived/l4t-3231/index.html#page/Tegra%2520Linux%2520Driver%2520Package%2520Development%2520Guide%2Fhw_setup_jetson_io.html%23

There’s one additional issue not mentioned in the docs, the jetson-io tool expects the base DTBs to be in /boot/dtb but they’re in /boot. You’ll have to copy them from /boot to /boot/dtb to get jetson-io to work.

I did just find an issue though… it’s not actually using hardware chip select and it does seem quite slow. I’ll see if I can correct that with another dtb overlay.

Hi gtj,

Thanks for the specific information from you.

Yes, the spi0.0 works after I use the jetson-io utility to select spi0. But it’s weird the spi0.0 still works even after I flash the old dtb to the dtb partition.So I think the jetson-io utility make a change to u-boot partition as well as dtb partition when enabling spi0.But the log of jetson-io utility shows only “write dtb partition successfully.” Could you tell me your opinion about this ?

Thanks again.

jetson-io doesn’t actually modify any partitions. It creates a dtb overlay file (dtbo) with the changes and combines that with the original dtb from /boot/dtb to create a custom dtb file (-user-custom.dtb). Then it modifies /boot/extlinux/extlinux.conf to add a new boot entry with an FDT statement pointing to the custom dtb. When u-boot loads that boot entry, it takes that new dtb and passes that to the kernel instead of the dtb that was flashed to the sd card partitions.

Hi gtj,

Thanks a million.

I check the new /boot/extlinux/extlinux.conf as the below code section, it is exactly as what you say.

LABEL JetsonIO
        MENU LABEL Custom 40-pin Header Config
        LINUX /boot/Image
        FDT /boot/tegra210-p3448-0000-p3449-0000-a02-user-custom.dtb
        INITRD /boot/initrd
        APPEND ${cbootargs}

Actually, the DTB partition is still there, but the uboot load the new “tegra210-p3448-0000-p3449-0000-a02-user-custom.dtb” to sysRAM.

As #1 mentions, the old dtb can show /dev/spidev0.0, that means the device matchs the driver, as we can see as below.

// on host 
garret:~/nano$ grep "/spi@7000d400" /boot/tegra210-p3448-0000-p3449-0000-a02.dts
                spi0 = "/spi@7000d400";
// on nano dev kit
sercomm:/sys/firmware$ ls  devicetree/base/ | grep "spi@7000d400"
spi@7000d400

sercomm@localhost:~$ ls /dev/spi0*
/dev/spidev0.0

But why it doesn’t work while the new dtb, “tegra210-p3448-0000-p3449-0000-a02-user-custom.dtb” can make “/dev/spidev0.0” work. What the “-user-custom.dtb” do? I git-diff the two dtb source files resulted in the attachment. But don’t understand why it need to change the old dtb to make /dev/spidev0.0 work under the condition that the device of spidev0.0 derived from the old dtb matches its driver.

Thanks again.
tegra210-p3448-0000-p3449-0000-a02-user-custom.patch.txt (52.1 KB)

I’m not quite sure what you’re asking but see if this is it…

You’re asking the difference between the 32.3.1 unmodified dtb and the one customized with jetson-io?

So the unmodified dtbs have always had the device nodes for the spi controller itself. spi@7000d400 is the address of the first spi controller. The 32.2.x dtbs didn’t have the spidev device nodes nor did they assign the mosi, miso, clk and cs pins to the controller. This is why spidev never showed up under /dev in 32.2.x

My patches added the spidev device nodes under the spi controller nodes AND set up the mosi, miso, clk and cs pins to be assigned to the controller.

Ihe unmodified 32.3.1 dtbs do have the spidev nodes under the spi controllers but do NOT have the pins assigned. This is why the spidev entries show up under /dev but can’t be used. This is actually the correct way to do it because the user might want to use them for GPIOs instead (which is their default).

The jetson-io tool, when you use “Configure 40-pin expansion header” to select spi1 and/or spi2, creates the “overlay” that assigns the pins to the spi controllers, takes the unmodified dtb as a base, applies the overlay, the writes it as the -user-custom.dtb and adds that to extlinux.conf as an FDT entry.

u-boot normally takes the dtb that it got from cboot (which it got from the signed dtb partition), and simply tells the kernel the address in memory to retrieve the unsigned version from. But u-boot can also (and, for quite some time, has been able to) read the file specified in the FDT entry in extlinux.conf, load that into memory and pass its address to the kernel. So now, u-boot loads the -user-custom.dtb file and passes its address to the kernel and that’s what the kernel goes with.

The dtb partitions are still needed because those device trees contain the memory and other basic information needed by tboot and without which the boot process can’t continue past tboot.

Did I cover it?

Just FYI… My performance issues with spi were resolved by completely powering off the Nano. Just doing a reboot after running jetson-io produces weird results.

Hi gtj,

Thanks you for the friendly detail.

Yes, you catch my point, but I need some more time to grasp those cboot like information.

Thanks for keeping me informed of this point. I will try it later.

Yeah it’s not exactly straightforward.

  1. The BootROM (burned into the SoC) starts running on the BPMP processor (a processor just for bootloading and firmware upgrading)
  2. The BootROM passes control to TBoot which is loaded from the small NAND storage on the SoC and also run on the BPMP.
  3. TBoot initializes the main CPU and reads the DTB from the SDCard into memory.
  4. TBoot passes control to another TBoot component that runs on the CPU.
  5. TBoot-CPU performs memory training and adds the results to the in-memory DTB.
  6. TBoot-CPU loads CBoot from the SDCard and passes control to it with the address of the in-memory DTB.
  7. CBoot creates the kernel command line and also updates the in-memory DTB.
  8. CBoot loads u-boot from the SDCard and runs it with the address od the in-memory DTB.
  9. u-boot searches for a /boot directory on the SDCard partition 1.
  10. u-boot loads the /boot/extlinux/extlinux.conf file.
  11. u-boot loads the Linux kernel into memory from the file pointed to by the KERNEL parameter in extlinux.conf.
  12. u-boot loads initial ramdisk into memory from the INITRD parameter in extlinux.conf.
  13. u-boot loads the DTB into memory from the FDT parameter in extlinux.conf IF IT EXISTS.
  14. u-boot loads any kernel command line parameters specified in the APPEND parameter in extlinux.conf and appends them to the kernel command line it got from CBoot.
  15. u-boot starts the in-memory kernel passing it the accumulated command line parameters, the address of the INITRD and the address of the DTB. If it loaded a DTB from the FDT entry in extlinux.conf, it passes that address. If not, it passes the address of the in-memory DTB it got from CBoot.
  16. The kernel starts using whatever DTB u-boot told it to use.

It’s simple really. :)

Hi gtj,

Thanks for the clear boot flow.

As for step 10 “u-boot loads the /boot/extlinux/extlinux.conf file.”, that means the filesystem is loaded first, right?

During the cboot span, the cboot “load” kernel from LNX, update bootarg and update DTB in-momory, no rootfs is loaded and running at this stage, so in my opinio, the uboot can’t find the /boot/extlinux/ directoy.

Thnaks

Yes. u-boot has everything it needs compiled into it to open mmc devices, read partitions and read ext2/4 and fat filesystems. Most ARM platforms only use u-boot on its own without any of the other components nvidia uses. In those cases, u-boot is usually flashed to an internal flash device or is located at the beginning of an external storage device.

Each vendor who uses u-boot creates configurations and drivers similar to kernel configurations and drivers that instruct u-boot how to do things like find and do basic initialization of things like MMC (sdcard), ethernet adapters, USB devices, etc. Those things are actually quite easy for u-boot because it’s a tiny, single-purpose, single-user environment. Unfortunately, nvidia has not yet added the ethernet or USB stuff so we’re limited to MMC storage devices.

When u-boot starts, it runs a script that looks for partition 1 on the first MMC device. It then uses ext2/4 or fat to find the /boot/extlinux.conf file, reads the kernel initrd and fdt files into memory, and starts the kernel.

If you want to see just what u-boot is doing, watch for the following on the serial console and hit enter.

U-Boot 2016.07-g0536cf2a27 (Dec 09 2019 - 22:40:32 -0800)

TEGRA210
Model: NVIDIA P3450-Porg
Board: NVIDIA P3450-PORG
DRAM:  4 GiB
MMC:   Tegra SD/MMC: 0, Tegra SD/MMC: 1
SF: Detected MX25U3235F with page size 256 Bytes, erase size 4 KiB, total 4 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   No ethernet found.
Hit any key to stop autoboot:  0

Just type “help” to see the list of commands available and “printenv” to see the scripts and variables that are built in. Booting starts with the “bootcmd” script.

Hi gtj, I’ve been seeing you around all these nvidia spi posts, so I’d like to ask about this one you said in particular.

Basically, that’s how I also think on 32.3.1’s jetson-io is doing, so to enable SPI0 channel 1, I just decompiled that *user-custom.dtb to see its *user-custom.dts file, add my dts changes, created a *user-custom-modified.dtb under /boot/dtb and /boot, and made extlinux.conf point to that *user-custom-modified.dtb.
It does seem to work at least for SPI0 channel 1, but according to the NVIDIA guy in my post 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/5424784/#5424784, doing it via modifying extlinux.conf “might miss some dependencies” (that I am not sure of like what exactly) so it is still recommended to update the dtb through the usual flash.sh command.

So I’m now not sure, maybe it might not be as simple as we think?
Maybe doing it the extlinux.conf way might really not be sufficient? (That or I’m missing something critical here).

I am getting more convinced that I indeed miss some dependencies, after I enabled all 2 SPI ports and its 2 channels each.
All the loopback tests work when I short MOSI-MISO lines, for all SPI0 CH0 (/dev/spidev0.0), SPI0 CH1 (/dev/spidev0.1), SPI1 CH0 (/dev/spidev1.0) and SPI1 CH1 (/dev/spidev1.1) - but that it is because they don’t rely on CS behavior unlike when an actual external SPI slave is connected.

Specifically, if you connect an actual external SPI device on say, SPI0, and then you use channel 1 (so CS1). Once CS0 is triggered Low (for example, you tried sending to /dev/spidev0.0 before), the CS0 does not come back to High. So CS0 being stuck at Low is messing up with the data exchange in the /dev/spidev0.1 (because it seems like CS0 is also enabled).

In RasPi this is not the case. Specifically, the CS line used automatically goes back to High as soon as data comm is done at /dev/spidevX.Y.

Have you encountered this somehow?
This is my DTS diff for your reference (tegra210-p3448-0000-p3449-0000-b00-user-custom.dts is the after enabling SPI0 via jetson-io and the other one are my “manual” changes in DTS file).

--- tegra210-p3448-0000-p3449-0000-b00-user-custom.dts  2020-02-10 11:26:27.904756600 -0500
+++ tegra210-p3448-0000-p3449-0000-b00-spi-enable-all-plus-pinmux.dts   2020-02-10 11:26:28.215817200 -0500
@@ -1559,6 +1559,47 @@
                                nvidia,pins = "gen2_i2c_sda_pj3";
                                nvidia,function = "i2c2";
                        };
+
+                       pin16 {
+                               nvidia,enable-input = <0x1>;
+                               nvidia,tristate = <0x0>;
+                               nvidia,pull = <0x2>;
+                               nvidia,pins = "spi2_cs1_pdd0";
+                               nvidia,function = "spi2";
+                       };
+
+                       pin18 {
+                               nvidia,enable-input = <0x1>;
+                               nvidia,tristate = <0x0>;
+                               nvidia,pull = <0x2>;
+                               nvidia,pins = "spi2_cs0_pb7";
+                               nvidia,function = "spi2";
+                       };
+
+                       pin13 {
+                               nvidia,enable-input = <0x1>;
+                               nvidia,tristate = <0x0>;
+                               nvidia,pull = <0x1>;
+                               nvidia,pins = "spi2_sck_pb6";
+                               nvidia,function = "spi2";
+                       };
+
+                       pin22 {
+                               nvidia,enable-input = <0x1>;
+                               nvidia,tristate = <0x0>;
+                               nvidia,pull = <0x1>;
+                               nvidia,pins = "spi2_miso_pb5";
+                               nvidia,function = "spi2";
+                       };
+
+                       pin37 {
+                               nvidia,enable-input = <0x1>;
+                               nvidia,tristate = <0x0>;
+                               nvidia,pull = <0x1>;
+                               nvidia,pins = "spi2_mosi_pb4";
+                               nvidia,function = "spi2";
+                       };
+
                };

                clkreq_0_bi_dir {
@@ -3757,6 +3798,14 @@
                        nvidia,enable-hw-based-cs;
                        nvidia,rx-clk-tap-delay = <0x7>;
                };
+
+               spi@1 {
+                       compatible = "spidev";
+                       reg = <0x1>;
+                       spi-max-frequency = <0x1f78a40>;
+                       nvidia,enable-hw-based-cs;
+                       nvidia,rx-clk-tap-delay = <0x7>;
+               };
        };

        spi@7000d600 {
@@ -3801,6 +3850,14 @@
                        spi-max-frequency = <0x1f78a40>;
                        nvidia,enable-hw-based-cs;
                        nvidia,rx-clk-tap-delay = <0x6>;
+               };
+
+               spi@1 {
+                       compatible = "spidev";
+                       reg = <0x1>;
+                       spi-max-frequency = <0x1f78a40>;
+                       nvidia,enable-hw-based-cs;
+                       nvidia,rx-clk-tap-delay = <0x6>;
                };
        };

I’m still studying if I’m missing some pin configurations, but you know, I’m a bit of a device tree noob and I just worked out my changes by getting patterns from existing SPI0 configurations.
BTW, I can open another topic for this “enable all SPI channel thing” if that’s more appropriate - I was just really curious on your statement on extlinux.conf.

Thanks!

SPI is in a sorry state on the Jetson platforms and unfortunately nvidia doesn’t seem to be interested in supporting it properly. The jetson-io tool is a great idea but it only provides basic configuration as you’ve discovered. The spi-tegra114 driver has several bugs which make it impossible to change timings and even if they fixed the driver, the stock device tree has “prod-settings” which cause the driver to ignore any timings an overlay might specify. The device tree even has parameters that aren’t even in the correct sections. It’s pretty disappointing. Having said all of that, here’s an excerpt from my own stuff that you can use to replace the relevant sections in a dts file that’s been decompiled from a dtb…

Replace in their entirety the spi@7000d400 (for spidev 0.0 and 0.1) and/or spi@7000d600 (for spidev 1.0 and 1.1) sections in your decompiled dts file with the below fragments.

spi@7000d400 {
        nvidia,polling-mode;
        compatible = "nvidia,tegra210-spi";
        reg = <0x00000000 0x7000d400 0x00000000 0x00000200>;
        interrupts = <0x00000000 0x0000003b 0x00000004>;
        iommus = <0x0000002b 0x0000000e>;
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        dmas = <0x0000004c 0x0000000f 0x0000004c 0x0000000f>;
        dma-names = "rx", "tx";
        nvidia,clk-parents = "pll_p", "clk_m";
        clocks = <0x00000021 0x00000029 0x00000021 0x000000f3 0x00000021 0x000000e9>;
        clock-names = "spi", "pll_p", "clk_m";
        resets = <0x00000021 0x00000029>;
        reset-names = "spi";
        status = "okay";
        linux,phandle = <0x0000010c>;
        phandle = <0x0000010c>;
        spi@0 {
            status = "okay";
            compatible = "spidev";
            reg = <0x00000000>;
            spi-max-frequency = <0x0337f980>;
            controller-data {
                nvidia,enable-hw-based-cs;
            };
        };
        spi@1 {
            spi-max-frequency = <0x0337f980>;
            reg = <0x00000001>;
            status = "okay";
            compatible = "spidev";
            controller-data {
                nvidia,enable-hw-based-cs;
            };
        };
    };
    spi@7000d600 {
        nvidia,polling-mode;
        compatible = "nvidia,tegra210-spi";
        reg = <0x00000000 0x7000d600 0x00000000 0x00000200>;
        interrupts = <0x00000000 0x00000052 0x00000004>;
        iommus = <0x0000002b 0x0000000e>;
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        dmas = <0x0000004c 0x00000010 0x0000004c 0x00000010>;
        dma-names = "rx", "tx";
        nvidia,clk-parents = "pll_p", "clk_m";
        clocks = <0x00000021 0x0000002c 0x00000021 0x000000f3 0x00000021 0x000000e9>;
        clock-names = "spi", "pll_p", "clk_m";
        resets = <0x00000021 0x0000002c>;
        reset-names = "spi";
        status = "okay";
        linux,phandle = <0x0000010d>;
        phandle = <0x0000010d>;
        spi@0 {
            status = "okay";
            compatible = "spidev";
            reg = <0x00000000>;
            spi-max-frequency = <0x0337f980>;
            controller-data {
                nvidia,enable-hw-based-cs;
            };
        };
        spi@1 {
            spi-max-frequency = <0x0337f980>;
            reg = <0x00000001>;
            status = "okay";
            compatible = "spidev";
            controller-data {
                nvidia,enable-hw-based-cs;
            };
        };
    };

Replace the pins defintions in pinmux@700008d4 / header-40pin-pinmux with those below as appropriate.

pin16 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000002>;
                nvidia,pins = "spi2_cs1_pdd0";
                nvidia,function = "spi2";
            };
            pin18 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000002>;
                nvidia,pins = "spi2_cs0_pb7";
                nvidia,function = "spi2";
            };
            pin13 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000001>;
                nvidia,pins = "spi2_sck_pb6";
                nvidia,function = "spi2";
            };
            pin22 {
                nvidia,enable-input = <0x00000001>;
                nvidia,tristate = <0x00000001>;
                nvidia,pull = <0x00000000>;
                nvidia,pins = "spi2_miso_pb5";
                nvidia,function = "spi2";
            };
            pin37 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000001>;
                nvidia,pins = "spi2_mosi_pb4";
                nvidia,function = "spi2";
            };
            pin26 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000002>;
                nvidia,pins = "spi1_cs1_pc4";
                nvidia,function = "spi1";
            };
            pin24 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000002>;
                nvidia,pins = "spi1_cs0_pc3";
                nvidia,function = "spi1";
            };
            pin23 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000001>;
                nvidia,pins = "spi1_sck_pc2";
                nvidia,function = "spi1";
            };
            pin21 {
                nvidia,enable-input = <0x00000001>;
                nvidia,tristate = <0x00000001>;
                nvidia,pull = <0x00000000>;
                nvidia,pins = "spi1_miso_pc1";
                nvidia,function = "spi1";
            };
            pin19 {
                nvidia,enable-input = <0x00000000>;
                nvidia,tristate = <0x00000000>;
                nvidia,pull = <0x00000001>;
                nvidia,pins = "spi1_mosi_pc0";
                nvidia,function = "spi1";
            };

Recompile the dts to a dtb and use that dtb in your extlinux.conf file.

1 Like

Agree. My browser is literally all over the NVIDIA forum just to make this work. I’ve jumped from R32.2.0 to R32.3.1 to rely on jetson-io, only to know it is still incomplete. And then when I studied how it works and updates a new DTB and modifies extlinux.conf, I was told that I should flash the new DTB using the old way via flash.sh. I’m terribly confused. I just wanted the SPI. :(

Hi gtj. Thanks for this. I tried this new DTS/DTB just now (and modified extlinux.conf to point to it), and… it works if the full 40-pin of the SPI slave is directly attached to the Nano (we have this 40-pin connector in our SPI slave that is compatible with Nano’s 40-pin).

(For this whole comment from me, “works” mean I consistently get correct data, and I’m currently testing ONLY SPI0 channel 1 (since my SPI slave is connected to SPI0 CS1) in all my tests.)

However, if I manually wire only SPI0 pins (19, 21, 23, 24, 26) + 1 3.3V VDD pin (17) and 1 GND pin (39), it doesn’t work, it gets rubbish data most of the time and at very rare times, correct data.

Note: “Manual wires” are those male-female colored wires.

(I was doing the manual wiring because the intent is to attach 4 SPI slaves in the Nano, or at least 2 SPI slaves in different ports SPI0 and SPI1).

I tried the same setup in my RasPi for comparison:

  • [WORKS] SPI slave's 40-pin is directly attached to RasPi's 40-pin
  • [WORKS] SPI slave's 5-pin SPI + pin 17 VDD + pin 39 GND is manually wired to RasPi's 5-pin SPI + pin 17 VDD + pin 39 GND
  • [WORKS] SPI slave's 40-pin is directly attached to Nano's 40-pin
  • [DOES NOT WORK] SPI slave's 5-pin SPI + pin 17 VDD + pin 39 GND is manually wired to Nano's 5-pin SPI + pin 17 VDD + pin 39 GN

And by the way, if I connect 40 manual wirings as in literally 40 male-female wires (not the usual 40-pin header/connector) for the Nano setup, SPI also works.

With this, it does seem like some other pin configuration within the 40-pin connector is affecting my SPI behavior. Not sure if that’s due to some post I read saying “current flowing in Nano is less than what flows in RPi”.

So my question is, how do you connect your SPI slave? 5 SPI pins + 1 VDD + 1 GND as well? Or your SPI slave also has a 40-pin Nano-compatible port and then you directly plug all 40-pin in?

And, did you intend to make the pulldown of the MISO as 0x00000000? Not 0x00000001? (though I tried reverting it to 0x00000001 and it also doesn’t work).

The slave I have actually has an old-style 26 pin connector so I have a 40 pin to 26 pin cable. I’ve also tested with just wiring the signal pins plus several grounds. Without knowing anything about your slave, it’s hard to tell what’s going on but I’d try with multiple grounds connected, especially those near the signal pins. How long are the connector wires and are they part of the same ribbon? I.E. Do you have an 8 conductor cable with the conductors being individually pinned? Depending on speed and length, those kinds of things can make a big difference.

On the master side, you don’t want any pulldown on MISO, especially if you are going to have multiple slaves. If you have a pulldown enabled, the slaves are going to have to drive the line a little harder to overcome it. Most slaves are fine with that but some aren’t. Those pins are also marked as TRISTATE for the same reason. In the end though, do whatever you need to to make it work. :)