How To Enable SPI/SPIDev on 28.1 (On-Target)

Hi, guys.

I’ve had several private messages with people asking me how to get SPI working on the TX2 using 28.1. I can easily understand why people struggle given the changes to 27.1 and 28.1. I feel the guides referring to the enabling SPI (https://elinux.org/Jetson/TX1_SPI) are no longer valid anymore.

I’d like to give a shoutout to JetsonHacks(http://www.jetsonhacks.com) and LinuxDev for their indirect help towards this post.

Guide for (on-target) enabling SPI / SPIDev on the Jetson TX2:

Wheres the SPI Pins?
On the J21 header: http://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout/

  • Pin 19 - SPI(3) MOSI
  • Pin 21 - SPI(3) MISO
  • Pin 23 - SPI(3) CLK
  • Pin 24 - SPI(3) CS#0

Get the kernel sources
I recommend Jetsonhacks (https://github.com/jetsonhacks/buildJetsonTX2Kernel)

$ git clone http://github.com/jetsonhacks/buildJetsonTX2Kernel.git
$ cd buildJetsonTX2Kernel
$ ./getKernelSources.sh

An application will come up (xconfig), I generally ignore this (close) as I usually build on a host machine.
The JetsonHacks script should have downloaded the kernel sources to the /usr/src/ folder, I suggest adding ‘SPIDEV’ to the tegra18_def_config file

$ cd /usr/src
$ cd /kernel/kernel-4.4/
$ cd /arch/arm64/configs/
$ sudo gedit tegra18_defconfig

Add the following to just below ‘CONFIG_SPI_TEGRA114_SPI=y

CONFIG_SPI=y
CONFIG_SPI_TEGRA114=y
<b>CONFIG_SPI_SPIDEV=m</b>
CONFIG_QSPI_TEGRA186=y

Build the kernel
Get your .conf file

$ cd /usr/src/kernel/kernel-4.4
$ sudo make tegra18_defconfig
$ cd ~/GIT/buildJetsonTX2Kernel 
$ sudo ./makeKernel.sh
//Ensure the SPIDev Kernel module is copied to /lib/modules...
$ sudo cp /usr/src/kernel/kernel-4.4/drivers/spi/spidev.ko /lib/modules/$(uname -r)/kernel/drivers/
// Module dependencies
$ sudo depmod
$ sudo ./copyImage.sh
// Reboot
$ sudo reboot

Once the Jetson has rebooted, navigate to /lib/modules/$(uname -r)

$ cd /lib/modules/$(uname -r)
$ cat modules.dep
// print the contents of modules.dep to the screen, and ensure spidev.ko is in there
// e.g. @line 23 
//kernel/drivers/spi/spidev.ko

Modify Device-Tree
I generally build on a host machine, and find its easier. But some people might need to modify the device tree on the device itself. Since 28.1 FDT has been taken out of the extlinux.conf file in /boot/extlinux/

First we need the device-tree-compiler

$ sudo apt-get update
$ sudo apt-get install device-tree-compiler

Decompile Device-Tree

$ cd /boot/dtb/
$ sudo dtc -I dtb -O dts -o myTX2DeviceTreeSource.dts tegra186-quill-p3310-1000-c03-00-base.dtb

Update The Device-Tree

$ sudo gedit myTX2DeviceTreeSource.dts
spi@3240000{
   compatible = "nvidia,tegra186-spi";
   reg = <0x0 0x3240000 0x0 0x10000>;
   ....
   ....
   ....
 linux,phandle = <0x80>;
 [b]spi@0 {
    compatible = "spidev";
    reg = <0x0>;
    spi-max-frequency = <0x1312D00>;
    nvidia,enable-hw-based-cs;
    nvidia,cs-setup-clk-count = <0x1e>;
    nvidia,cs-hold-clk-count = <0x1e>;
    nvidia,rx-clk-tap-delay = <0x1f>;
    nvidia,tx-clk-tap-delau = <0x0>;
  };
 [/b]
};

Recompile The Device-Tree

$ cd /boot/dtb/
$ sudo dtc -I dts -O dtb -o tegra186-quill-p3310-1000-c03-00-base.dtb myTX2DeviceTreeSource.dts

Add /boot/dtb/ to FDT
Since 27.1 FDT has been removed from extlinux.conf (this is where this step falls over https://elinux.org/Jetson/TX1_SPI#Booting_with_the_New_DTB)

$ cd /boot/extlinux/
$ sudo gedit extlinux.conf

Add the FDT line to your extlinux.conf file

TIMEOUT 30
DEFAULT PRIMARY

MENU TITLE p2771-0000 eMMC boot options

LABEL primary
      MENU LABEL primary kernel
      LINUX /boot/Image
      <b>FDT /boot/dtb/tegra186-quill-p3310-1000-c03-00-base.dtb</b>
      APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4

That should be it… Reboot for things to take effect

$ sudo reboot

Check if Spidev is available in your /dev/ folder

$ ls /dev/spi*
$ /dev/spidev.3.0

This method is by no means perfect, it’s more of a bodge if anything, but hopefully it should let you add SPI without using a host machine. I will try make this post a bit more cleaner in the coming days, but I think it’s necessary to have a more up-to-date guide on adding SPI to the TX2.

Thanks for this! When I run the exact first sequence I don’t end up with a spidev.ko in /usr/src/kernel/kernel-4.4/drivers/spi/. I’m not sure how to track this down - there is a spi.o file but not a spidev.o file as if it isn’t being built. I tried adding the CONFIG_SPI_SPIDEV=m line in the other deconfigs as well.

ensure you modify the tegra18_defconfig:
cd /usr/src cd /kernel/kernel-4.4/
cd /arch/arm64/configs/ sudo gedit tegra18_defconfig

Add the following to just below ‘CONFIG_SPI_TEGRA114_SPI=y’
CONFIG_SPI=y
CONFIG_SPI_TEGRA114=y
CONFIG_SPI_SPIDEV=m
CONFIG_QSPI_TEGRA186=y

cd /usr/src/kernel/kernel-4.4 sudo make tegra18_defconfig

Then make the kernel.

Sorry about my last post - I missed one of the steps - got my spidev in modules.dep!

WORKS! I lost my ethernet jack, but it works. Question - do you know of a sample project out there that shows the use of GPIO to select a slave and SPI to communicate with it? I have a gyro sensor connected over J21. Thanks again!!

Hello,
I followed your tuto, and everything is ok !!
But I have a question :
Trying to wire an adafruit ssd1351 128x128 rgb oled screen, and I need
Clock mosi cs/oc and dc(data control)

After your tuto, i have mosi miso clk and cs but not DC.

Do you know what I should do ? ( newbie )
Thanks too much.
Vincent

Hi, elpimous12.

I was just looking for your other post to respond to https://devtalk.nvidia.com/default/topic/1022429/spi-configuration-for-tx2/#5214262

I’ve been looking at the datasheet for the adafruit ssd1351 and it doesn’t specify what ‘dc’ is (I’ve never worked with a SPI OLED screen before). Going by Adafruit’s github https://github.com/adafruit/Adafruit-SSD1351-library/, ‘DC’ Data Control appears to be an output from the Arduino example and from what their library suggests it’s just a Digital Out.

See https://github.com/adafruit/Adafruit-SSD1351-library/blob/master/Adafruit_SSD1351.cpp and the function Adafruit_SSD1351::Adafruit_SSD1351(uint8_t cs, uint8_t rs, uint8_t sid, uint8_t sclk, uint8_t rst)

I think you just need a Digital Out pin from the Jetson, which should be available on the J21 headers.

Here’s a starting point for GPIO on the Jetson, bear in mind this is for the TX1 and not for the TX2, but it’s very similar (only thing is some GPIO pin numbers have changed) http://www.jetsonhacks.com/2015/12/29/gpio-interfacing-nvidia-jetson-tx1/

David.

Oh thank you so much for your quick answer
Wellp I am looking for digital pin on my Tx2,
Newbie question : can i use the port I want on the j21 ?
Like i2c gpx data or uart0_tx ?? (There is no spécific digital out port on j21)
And just assign j21 pin number as DC, in arduino program ?

this chart shows where the GPIO pins are:

I was only able to get gpio398 and gpio481 (pins 18 and 29) on the header to work, but I only needed two. Definitely
try getting them to work from the command line first - easy to setup and test, make sure you do ‘sudo su’ and
try from the root prompt.

What if the Chip Select for the SPI device is not directly on a GPIO port? For example
lots of SPI devices on one bus where the Chip Selects are controlled through an external FPGA?

The accepted answer has some issues with it:

  1. Adding the DTB to extlinux.conf is not necessarily the way to do things as of L4T 28.1. As a result, following the accepted answer will break networking (and maybe other pieces of hardware). See the discussion here: https://devtalk.nvidia.com/default/topic/1025762/provided-dtb-no-ethernet/.
  2. There is zero reason to rebuild the entire kernel image. Instead, you should just build the SPI module. Here is what I did:
# Get kernel sources, install in /usr/src
cd /usr/src/
sudo wget http://developer.download.nvidia.com/embedded/L4T/r28_Release_v1.0/BSP/source_release.tbz2
sudo tar -xvf source_release.tbz2 sources/kernel_src-tx2.tbz2
sudo tar -xvf sources/kernel_src-tx2.tbz2

# Edit kernel config
cd kernel/kernel-4.4/
sudo zcat /proc/config.gz > .config
sudo sed -i 's/# CONFIG_SPI_SPIDEV is not set/CONFIG_SPI_SPIDEV=m/' .config
sudo sed -i 's/CONFIG_LOCALVERSION=""/CONFIG_LOCALVERSION="-tegra"/' .config

# Build SPI module
sudo make prepare
sudo make modules_prepare
sudo make M=drivers/spi
sudo cp drivers/spi/spidev.ko /lib/modules/$(uname -r)/kernel/drivers
sudo depmod
sudo reboot

@dwd_pete.

Agreed, adding DTB to extlinux.conf is not the correct way to do it, it is just a very convenient way for on-target building to get SPI working. A lot of people want to get SPI working on-target without using a host, and these steps are aimed towards them.

The main issue is that the device tree has to be modified to include SPI and when you’re doing that on-target you’re quite limited (adding DTB to extlinux.conf).

You’re right, you don’t have to rebuild the kernel, I must have included that in my steps by mistake.

To clarify, you can edit extlinux.conf, but the problem is that you need to ensure that your modified DTB file has ALL the previous settings. De-compiling the DTB files that are in /boot/dtb won’t give you that. Instead, you need to get all these settings from /proc/device-tree.

See my accepted answer here: https://devtalk.nvidia.com/default/topic/1025762/provided-dtb-no-ethernet/

Thanks, my solution is my no means perfect (I much prefer to build it on a host), but I shall take what you’ve found on-board and improve the solution. :-)

The unfortunate thing about all this is, people often get referred to https://elinux.org/Jetson/TX1_SPI which is woefully out-of-date (and not for the TX2) and as a consequence they come here to figure out how to do it.

@david_evans_g
I am sure you are right the https://elinux.org/Jetson/TX1_SPI is out-of-date, it’s only for the JetPack 2.3 / 2.3.1 as it mention in the header.
Could you help to create a new wiki page for the r28.1/TX2/TX1 to help many of Users.

Hi, ShaneCCC.

Yes, I’ve started one, but I’ve been holding off until I’ve found a practical way to do it completely on-target. I’ve found that the only way to do it correctly (so far) requires building it using a host machine. This is because at some point you have to modify the device tree and I believe the changes made to 28.1+ prevent you from doing that conveniently and cleanly (solely) on-target.

I must admit I’ve put this task down since my initial post here due to work commitments, but I will happily pick it back up again and try get something uploaded soon.

For whatever it’s worth…

a) To create my own fdt file (on my host machine) I had to use the dtc that the kernel builds,
not the one built from the generic dtc source. If you wanted to compile a FDT on the target you might
need to use that source (that took a while to figure out).

b) I believe u-boot modifies the device tree with networking information. I have been able
to pull the fdt from /sys/firmware/… and use that in the extlinux.conf file, and keep
the networking. I did this to have a backup entry in extlinux.conf in case either the kernel
or fdt I created wouldn’t boot.

Good luck.

Cary

Thanks, Cobrien.

I have been down that road before with modifying the extlinux.conf but I didn’t like too much, I will investigate again!

Thanks,

David.

Thanks for the update @david_evans_g, we have archived it at: https://elinux.org/Jetson/TX2_SPI

Feel free to make updates there.

Thanks, Dusty.

As it stands, I believe what is on https://elinux.org/Jetson/TX2_SPI will break the network interface. I will try update the wiki as soon as possible.

Thanks,

David.