Problem Getting SPI Working on Jetson Nano

I have no problems opening the spidev1.0 and sending a string to it without errors, but I see no activity on any SPI pins. (I did configure the GPIO for SPI using the jetson-io.py utility.) Any suggestions on what could the issue?

Hi markg3,

Are you using the devkit or custom board for Jetson Nano?
What’s the Jetpack version in use?

How do you confirm this that you’ve sent the data successfully?
Do you use the scope to check their state?

Hi KevinFFF,

Yes, I am using oscilloscope to check for activity on SPI output signals. The SPI demo code that somebody sent to me has error checking that does not indicate an error when the function is called to open the SPI or to send a string to it. I’ve included bits of this demo code below. The version is as follows:

R32 (release), REVISION: 7.4, GCID: 33514132, BOARD: t210ref, EABI: aarch64, DATE: Fri Jun 9 04:25:08 UTC 2023

Version: 32.7.4-20230608212426

I’ve tested on both my custom board and on the devkit, with the result of no activity on any of the SPI outputs on both boards. The only difference between the boards is that on my board the chip selects are high - a default inactive state which is what I would expect. On the devkit board the chip selects stay low which it the default active state.

This ‘open/init’ code:

fd = open(device, O_RDWR);
if (fd < 0)
pabort(“can’t open device”);

/*

  • spi mode
    /
    /
    WR is make a request to assign ‘mode’ */
    request = mode;
    ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
    if (ret == -1)
    pabort(“can’t set spi mode”);

/* RD is read what mode the device actually is in /
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort(“can’t get spi mode”);
/
Drivers can reject some mode bits without returning an error.

  • Read the current value to identify what mode it is in, and if it
  • differs from the requested mode, warn the user.
    */
    if (request != mode)
    printf(“WARNING device does not support requested mode 0x%x\n”,
    request);

/*

  • bits per word
    */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
    pabort(“can’t set bits per word”);

ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort(“can’t get bits per word”);

/*

  • max speed hz
    */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
    pabort(“can’t set max speed hz”);

ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort(“can’t get max speed hz”);

This is ‘send’ code:

//---------------------------------------------------------------------------
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
int out_fd;
struct spi_ioc_transfer tr;
// = {
// .tx_buf = (unsigned long)tx,
// .rx_buf = (unsigned long)rx,
//.len = len,
//.delay_usecs = delay,
//.speed_hz = speed,
//.bits_per_word = bits,
//len : len,
//delay_usecs : delay,
//speed_hz : speed,
//bits_per_word : bits,
//};

tr.tx_buf = (unsigned long)tx;
tr.rx_buf = (unsigned long)rx;
tr.len = len;
tr.delay_usecs = delay;
tr.speed_hz = speed;
tr.bits_per_word = bits;

if (mode & SPI_TX_OCTAL)
tr.tx_nbits = 8;
else if (mode & SPI_TX_QUAD)
tr.tx_nbits = 4;
else if (mode & SPI_TX_DUAL)
tr.tx_nbits = 2;
if (mode & SPI_RX_OCTAL)
tr.rx_nbits = 8;
else if (mode & SPI_RX_QUAD)
tr.rx_nbits = 4;
else if (mode & SPI_RX_DUAL)
tr.rx_nbits = 2;
if (!(mode & SPI_LOOP)) {
if (mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
tr.rx_buf = 0;
else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL))
tr.tx_buf = 0;
}

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort(“can’t send spi message”);

if (verbose)
hex_dump(tx, len, 32, “TX”);

if (output_file) {
out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (out_fd < 0)
pabort(“could not open output file”);

ret = write(out_fd, rx, len);
if (ret != len)
pabort(“not all bytes written to output file”);

close(out_fd);
}

if (verbose)
hex_dump(rx, len, 32, “RX”);
}
//---------------------------------------------------------------------------

I would suggest you verifying on the devkit for all related operations first.
Please refer to Jetson Nano SPI Bus Not Working - #10 by KevinFFF for the steps to verify SPI loopback test on Jetson Nano.

Hi KevinFFF,

Thank you for the reference to the “SPI loopback” post. The “Remove GPIO usage of SPI pins” step is beyond our capabilities at this time, which is limited to downloading the latest Jenson Nano flash image to a Windows-based workstation and running a tool that creates a Jetson Nano bootable SD card. Perhaps the NVIDIA already has Jetson Nano flash image with the “remove GPIO usage of SPI pins” modification in it that we would be able to download and to make bootable SD card from it.

Sorry that we don’t have that kind of image available currently since they are configurable by customer with their specific use case.

Alternative, could you decompile the DTB on your board(/boot/dtb/kernel_xxx.dtb) to dts manually and modify that line manually to check if it could work?

Hi KevinFFF,

I did try your suggestion of disassembling dtb, editing, assembling back on the Jetson Nano itself. After all that, the results are the same - no activity on the SPI outputs.

Here are steps my steps:

  1. Found kernel_tegra210-p3448-0000-p3449-0000-b00.dtb in /boot/dtb/ folder

  2. Used ‘sudo dtc -I dtb -O dts -o temp.dts kernel_tegra210-p3448-0000-p3449-0000-b00.dtb’ to disassemble (got some warning message but the file was created)

  3. Using editor replaced ‘gpio-input = <0xd8 0xc 0xd 0xe 0xf 0xe8 0x26 0x95 0x5 0xbc 0xbd 0xbe 0xc1 0xc2 0xa8 0xc8 0xca 0x4d 0x4e 0x4c 0x4f 0x32 0x33 0x10 0x11 0x12 0x13 0x14 0x3a 0x3d 0x3e 0x41 0xe4>;’ with ‘gpio-input = <0xd8 0x26 0x95 0x5 0xbc 0xbd 0xbe 0xc1 0xc2 0xa8 0xc8 0xca 0x4d 0x4e 0x4c 0x4f 0x32 0x33 0x3a 0x3d 0x3e 0x41 0xe4>;’ in the temp.dts file

  4. Used ‘sudo dtc -I dts -O dtb -o kernel_tegra210-p3448-0000-p3449-0000-b00.dtb temp.dts’ to assemble back (got some warning messages but timestamp of the file was updated)

  5. Rebooted the Jetson Nano.

  6. Tried running ‘sudo /opt/nvidia/jetson-io/jetson-io.py’ but it exited quickly. (It worked before this procedure.)

  7. Ran ‘sudo modprobe spidev’. It worked.

  8. Got, complied and ran the spidev_test.c. It ran with no issues but there was no activity SPI outputs.

I’ve attached the dtb and dts files from /boot/dtb/ folder. Anything the matter with these steps? What else to try?

(Attachment temp.dts is missing)

(attachments)

kernel_tegra210-p3448-0000-p3449-0000-b00.txt (232 KB)
tegra210-p3448-0000-p3449-0000-b00.txt (232 KB)

I would suggest you performing this before modifying the line of gpio-input in device tree.

Please also share the /boot/extlinux/extlinux.conf after you’ve used Jetson-IO to configure the pins for SPI usage.

Hi KevinFFF,

I did successfully configure GPIO for the SPI0 and SPI1

Hi KevinFFF,

(My last post was not complete)
I did successfully configure GPIO for the SPI0 and SPI1 using jetson-io.py prior to modification to gpio-input line.

Here is a copy of extlinux.conf file from my Jetson Nano.
extlinux_conf.txt (1.2 KB)

DEFAULT JetsonIO
..
LABEL JetsonIO
	MENU LABEL Custom Header Config: <HDR40 User Custom [2024-07-27-105615]>
	LINUX /boot/Image
	FDT /boot/kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb
	INITRD /boot/initrd
	APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0

From the extlinux.conf you shared as above, it loads /boot/kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb as device tree in kernel.
As a result, please decompile the dtb to dts and modify the gpio-input line to check if it could help.

Hi KevinFFF,

I found the /boot/kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb on my Jetson Nano and repeated decompile/edit/recompile procedure for it, but it made no difference - still no activity on the SPI outputs. I’ve attached the final dtb and intermediate dts. What do I try now?
tegra210-p3448-0000-p3449-0000-b00.txt (231.8 KB)
kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom-EditedStep2.txt (320.7 KB)
kernel_tegra210-p3448-0000-p3449-0000-b00-user-custom_dtb.txt (233.0 KB)

If you go to “/proc/device-tree”, this is a reflection of the current device tree in RAM. You can look directly in those files, or you can create a source tree via:
dtc -I fs -O dts -o extracted.dts /proc/device-tree

Are the changes you made found in the “/proc/device-tree” or its extracted source tree? If they are, then you know the device tree changes are not doing what you want; if not, then your changes never made it in.

Do you reboot the board to apply the change?

As linuxdev said, please run dtc -I fs -O dts -o extracted.dts /proc/device-tree on your board to check the current configuration. You can share extracted.dts here for further check.

Hi KevinFFF,

I looked at the files in the /proc/device-tree and produced a source tree via the “dtc -I fs -O dts -o extracted.dts /proc/device-tree” command. I’ve attached the data. I don’t think we did anything to this Jetson Nano to add SPI devices other than to run “sudo modprobe spidev” every time before running the app that exercises SPI. Please let me know if there is a procedure that we need follow add SPI devices to the tree.
dev-tree-files.txt (2.0 KB)
extracted_dts.txt (323.0 KB)

Hi KevinFFF,

Yes, rebooted the Jetson Nano after the decompile/edit/recompile step.

Your device tree looks good to me.

Yes, it is expected operation to load spidev driver.

Do you get /dev/spidev0.0 after running sudo modprobe spidev on the board?

Could you get SPI to work in a loopback test through shorting MISO and MOSI externall?
If not, please also share the result of the following command on your board.

$ sudo cat /sys/kernel/debug/tegra_gpio

Hi KevinFFF,

I’ve attached the output of the ‘sudo cat /sys/kernel/debug/tegra_gpio’.

I can compile and run the spidev_test.c program without errors but I see no activity when I probe the SPI outputs at the GPIO header.

After I run “sudo modprobe spidev” then “ls -lah /dev/spidev*” I see this output:

crw-rw---- 1 root gpio 153, 0 Jul 27 11:08 /dev/spidev0.0
crw-rw---- 1 root gpio 153, 1 Jul 27 11:08 /dev/spidev0.1
crw-rw---- 1 root gpio 153, 2 Jul 27 11:08 /dev/spidev1.0
crw-rw---- 1 root gpio 153, 3 Jul 27 11:08 /dev/spidev1.1

gpio.txt (1.1 KB)

Hi KevinFFF,

Were you able to glean anything useful from the contents of ‘tegra_gpio’ that I’ve included in my last post?

Since my last post, I’ve loaded the SD card with pristine Jetson Nano image and repeated all the steps of the decompile/edit/recompile and jetson-io.py but the results were the same - no activity on the SPI signal. Any other suggestions?

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 f0 00 00 00 00 00 000000
 C: 0:2 1f 00 00 18 00 00 000000
..

The result shared from you is not expected to me that they are still used as GPIO rather than SPI.

Please let me share mine as following.

$ 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
..

For B and C, they should be all zeros.

I would suggest you configure pinmux manually for those pins used as SPI.