Updated instructions for SPI on Nano DevelopmentKit with L4T 32.2.1

So, I’ve spent the last week trying to piece together information on getting SPI to work on the Nano DeveloperKit and finally got it working yesterday. To save others some pain, I’ve documented the steps and created both patch and binary files. This only applies to the tegra210-p3448-0000-p3449-0000-a02 but I’m sure it can be adapted to other boards.

Just FYI… My first mistake was using the pinmux “helper” spreadsheets. Not only do you have to use a real Excel to get the macros to work, they produce files that cause the Nano to not boot. In my case, even though I only modified the spi1 pins, the resulting dtsi files had qspi and sdmmc1 disabled which prevents the device from booting.

So I went back to my previous experience with creating/modifying device trees for other boards and started from scratch. Once you know where all the pieces are, it’s actually not that hard. Here’s the result:

At the end of this, you should have:
/dev/spidev0.0
/dev/spidev0.1
/dev/spidev1.0
/dev/spidev1.1

and they should be routed to the appropriate pins on the 40-pin expansion connector.


See this post for the latest info
https://devtalk.nvidia.com/default/topic/1062646/jetson-nano/updated-instructions-for-spi-on-nano-developmentkit-with-l4t-32-2-1/post/5409864/#5409864

This looks good!

What I don’t understand is why NVIDIA doesn’t just configure all the functions for the GPIO header as default. When opening/exporting a GPIO pin, it’s really easy for the device driver to override that pin to be a GPIO function, even if it’s by default configured for a peripheral, and then when closing the GPIO pin, the driver can undo the GPIO override.

Yeah I’m not sure either. It wouldn’t be too bad if you could just let u-boot load the dtb from /boot and pass it to the kernel as other platforms do but the whole TegraBoot → cboot → u-boot 12 partition thing just makes the process overly complex.

Anyway, thanks for the feedback!

1 Like

@gtj do we really need an updated gpio driver AND a patched u-boot AND the DTB itself?
I see there is an alternative, however it is hit and miss, in my case a miss https://devtalk.nvidia.com/default/topic/1050427/jetson-nano/enabling-spidev-on-the-jetson-nano-is-hanging-when-flashing/post/5401379/#5401379 but I’m not the only one.

I also see people do just this:

sudo ./flash.sh -r -k DTB jetson-nano-qspi-sd mmcblk0p1

which should only update the DTB partition(?!) is this supposed to be enough?

could you please confirm? any chance you have an SD image with SPI enabled?
thanks

@gtj, so I tried your approach and wanted to enable spi1/spidev0.0 but I ended up with both enabled and not working anyway:
root@jetson:/home/jetson# 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 24 00 00 000000
B: 0:1 80 80 80 00 00 00 000000
C: 0:2 18 18 18 00 00 00 000000

root@jetson:/home/jetson# ls /dev/spi*
/dev/spidev0.0 /dev/spidev0.1

root@jetson:/home/jetson/Work/spi# ./spidev_test -D /dev/spidev0.0
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
root@jetson:/home/jetson/Work/spi#

root@jetson:/home/jetson/Work/spi# ./spidev_test -D /dev/spidev0.1
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
root@jetson:/home/jetson/Work/spi#

root@jetson:/home/jetson/Work/spi# dpkg-query --show nvidia-l4t-core
nvidia-l4t-core 32.2.1-20190812212815

any thoughts? I started with fresh SD image
thanks

The only way I’ve gotten it to work consistently is flashing all 4 partitions: DTB, EBT (cboot), LNX(uboot) and RP1(another dtb).

I’m using that Nano to control a 3D printer via the SPI bus and it’s been working solidly since September.

I don’t actually run the standard Nano Ubuntu image but I can try and build one. Givce me a day or two.

Try adding the speed to the spidev_test command line:

./spidev_test -D /dev/spidev0.1 -s 1000000

I’ve seen it do funny things if it’s not supplied.

Also ret the following…

gpioinfo

gpiochip0 - 256 lines:

line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: “GPIO12” unused input active-high
line 13: “GPIO13” “dsf-event-monitor” input active-high [used]
line 14: “GPIO14” unused input active-high
line 15: “GPIO15” unused output active-high
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” “cs_gpio” output active-high [used]
line 21: unnamed unused input active-high
line 22: unnamed unused input active-high

Are lines 16-20 assigned as above?

I’ve created an SD card image based on Tegra_Linux_Sample-Root-Filesystem_R32.2.1_aarch64.tbz2
that has spidev0.0 and spidev0.1 enabled. It also has the Tegra XUSB driver included in the kernel which should allow using a USB drive as the root filesystem.

Please test before using in production!

EDIT: Oops, there was an issue with that build. I’ve removed it for now.

thanks for your time on this.
and excuse my ignorance: are spidev0.0 and spidev0.1 both related to the SPI0 signals on the expander?
I’d like to avoid use of the SPI1 signals for now.

where can I find the ‘gpioinfo’ tool?

on spidev_test, I was using the code from the kernel, not the one from rpi fork, that’s why I couldn’t see the actual transfer. using verbose (-v) was showing it was working.

I found the gpio tools:
root@jetson:/home/jetson# gpioinfo | grep SPI
line 12: “SPI1_MOSI” unused input active-high
line 13: “SPI1_MISO” unused input active-high
line 14: “SPI1_SCK” unused input active-high
line 15: “SPI1_CS0” unused input active-high
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” unused input active-high
line 20: “SPI0_CS1” unused input active-high
line 232: “SPI1_CS1” unused input active-high

at the moment I’m not using your build, but the one from GitHub - rt-net/JetsonNano_DT_SPI at R32.2.1 because I didn’t know what to do about spidev0.1

I ran the tests as here https://devtalk.nvidia.com/default/topic/1050427/jetson-nano/enabling-spidev-on-the-jetson-nano-is-hanging-when-flashing/post/5401586/#5401586

my goal was to use an SPI-driver LCD but I wasn’t successful and ended up using a small HDMI display https://devtalk.nvidia.com/default/topic/1066616/jetson-nano/lcd-tft-piscreen-not-working-on-r32-2-1/post/5401868/#5401868

what have you been using the SPI for?

So, there are two SPI controllers exposed on the expansion connector: spi0 and spi1. Each of those has two chip select lines.

Signal      Pin
spi_0_mosi  19
spi_0_miso  21
spi_0_clk   23
spi_0_cs1   24  spidev0.0
spi_0_cs2   26  spidev0.1

spi_1_mosi  37
spi_1_miso  22
spi_1_clk   13
spi_1_cs1   18
spi_1_cs2   16

Both spi controllers are configured BUT only spi0 has spidev attached to it. So that’s spidev0.0 and spidev0.1. The pins assigned to spi1 should be free for other uses unless you attach a device driver to it.

The “gpiod” package has the gpio tools in it.

The spi bus on my Nano communicates with a 3D printer controller board. The controller board handles all the motion control stuff and the Nano handles all the admin stuff.

thanks for the info, that’s what I was expecting regarding CSs.

I also uploaded a tested image.

One of these days I’ll write some scripts to update the system partitions and kernel on a live system.

New image at

Just corrects an issue with user accounts.

I’ve also create a small installer that can flash the DTB partitions on a running Nano without disturbing the root filesystem or any other partitions.

cool! thanks for the image and tool.
the tool is definitely good to have as a quick approach to enable spi straight from the nano itself.
any chance it could be combined with this https://github.com/rt-net/JetsonNano_DT_SPI/ to build everything needed (the 4 images) on the nano itself or is cross-compiling the only option?

That’s a good question. I’d need to pick apart the things in L4T that would be required to build the images. That would include the kernel but at least you don’t have to actually compile the kernel, just the dtbs. I can give it a try.

Kernel and modules are easily compiled on the nano, see https://github.com/JetsonHacksNano/buildKernelAndModules
not sure about signature for images but that should also be available somehow.

thanks again

Yep. Just for SPI, you don’t have to build the kernel or modules themselves (thankfully), just the DTBs which takes only a few seconds. Building the kernel and modules on the Nano is a pretty serious time investment. :)

The L4T package has everything needed to create the signed images but there’s no out of the box way to flash them directly to the running sdcard. It’s easy enough using ‘dd’ though. Just have to create a script to do it.

‘dd’ should be more than enough, I think.
btw, your prebuilt image works ‘as advertised’ ;-)=
thank you

I have some bad news regarding the image. it seems it is incomplete as I get errors while trying to build the inference engine from https://github.com/dusty-nv/jetson-inference
upon cmake, I get these:
CUDA_TOOLKIT_ROOT_DIR not found or specified
– Could NOT find CUDA (missing: CUDA_TOOLKIT_ROOT_DIR CUDA_NVCC_EXECUTABLE CUDA_INCLUDE_DIRS CUDA_CUDART_LIBRARY)
[…]
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
CUDA_CUDART_LIBRARY (ADVANCED)
[…]
CUDA_TOOLKIT_INCLUDE (ADVANCED)

it might have something to do with missing repo: file:/var/cuda-repo-10-0-local-10.0.326 as I was seeing a Not Found on ‘apt update’.
I don’t get these errors with the original image.
anyway, I’d say leave this for now since it is possible to dd the images to enable SPI.
thanks and cheers