TX2 SPI+DMA Slave

I am having an issue, which I believe is coming from the hardware of the TX2.

Here’s my hardware setup.

  • TX2 Development Kit (Pinmux configured for SPI4 on the J21 header).
  • TX2 Linux configured device tree to run SPI4 (spi@3240000) as a slave.
  • Raspberry Pi 3b connected to the TX2’s SPI4 pins, configured as master.

Transfers which require DMA (larger than the 64 byte SPI fifo), will randomly fail at clock speeds in the 1Mhz range and up.

The failure is an RX overflow: the RX DMA channel either is freezing or stopping or cannot keep up with the line rate. I suppose it could potentially be an issue with the RPI, but that seems unlikely (though I don’t have an oscilloscope to confirm or deny this).

I’ve also tested this outside of linux and spidev using a custom OS with a SPI and DMA driver I wrote myself. The same issue occurs, and it generally seems to require a full reset of the SPI and DMA devices.

Has anyone else experienced this? I am well under the theoretical maximum transfer rates for this device.

What’s your BSP version?

cat /etc/nv_tegra_release

# R32 (release), REVISION: 5.1, GCID: 26202423, BOARD: t186ref, EABI: aarch64, DATE: Fri Feb 19 16:50:29 UTC 2021

I’ve reproduced this on two TX2 boards.

On the SPI master (I’m using a PI) you run something that sends SPI (could be C spidev, or some python library):

import time
import periphery

if __name__ == "__main__":
    #spi = periphery.SPI("/dev/spidev0.0", 1, 15600000)
    spi = periphery.SPI("/dev/spidev0.0", 1, 7800000)
    #spi = periphery.SPI("/dev/spidev0.0", 1, 3900000)
    #spi = periphery.SPI("/dev/spidev0.0", 1, 1953000)
    #spi = periphery.SPI("/dev/spidev0.0", 1, 488000)
    spi.bits_per_word = 8
    message_size = 1024*16
    for i in range(0, 10000):
        time.sleep(0.006)
        current_message = [i%128]*(message_size)
        print("Sending message {}".format(i))
        incoming_message = spi.transfer(current_message)
        print(("{:02x} "*8).format(*incoming_message[0:8]))

After modifying the device tree so SPI4 is set as a slave, and enabling SPI on the pinmux… On the TX2 I run something like this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>


int main(int argc, char *argv[])
{
	int spi_fd = open("/dev/spidev3.0", O_RDWR);
	if(spi_fd < 0) {
		perror("open");
	}

	uint32_t mode = SPI_MODE_1;	
	uint32_t speed = 15600000;
	//uint32_t speed = 122000;
	uint32_t bits_per_word = 8;
	int64_t	message_size = 4096;
	size_t iterations = 1;

	int a = 0;
	while(++a < argc)
	{
		if(strcmp(argv[a], "--speed") == 0 && ++a < argc)
		{
			speed = atoi(argv[a]);	
		}
		else if(strcmp(argv[a], "--size") == 0 && ++a < argc)
		{
			message_size = atoi(argv[a]);
		}
		else if(strcmp(argv[a], "-n") == 0 && ++a < argc)
		{
			iterations = atoi(argv[a]);
		}
	}

	printf("mode=0x%x, bits=%u, speed=%u, message_size=%lu, n=%lu\n", mode, bits_per_word, speed, message_size, iterations);

	if(ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0) {
		perror("mode");
	}

	if(ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
		perror("speed");
	}

	if(ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) {
		perror("bits_per_word");
	}

	struct spi_ioc_transfer xfer[1] = {0};

	uint8_t message[message_size];
	memset(message, 0, sizeof(message));
	message[0] = 0xaa;
	message[1] = 0xbb;

	xfer[0].tx_buf = (uintptr_t)message;
	xfer[0].rx_buf = (uintptr_t)message;
	xfer[0].len = sizeof(message);


	for(int i = 0; i < iterations; i++) {
		int status = ioctl(spi_fd, SPI_IOC_MESSAGE(1), xfer);
		if(status < 0) {
			perror("msg");
			return 1;
		}

		printf("%02x %02x %02x %02x\n",
				message[0],
				message[1],
				message[2],
				message[3]);
		usleep(1000*30);
		message[0]++;
		message[1]++;
	}
	close(spi_fd);

	return 0;
}

The usleep is needed because of a different bug (in the PI’s output there’s CS glitch).

HI @richard.habeeb,

I’m also trying to get tx2 spi working as spi slave. Can you provide the steps you followed? If I configured right would it show up on /sys/class/spi_slave ? on TX2 I can’t see a spi_slave node and as I got to know this node comes in linux kernel version greater than 4.13 can you explain this?