TX1 L4T R28.1 spidev slave performance

May be I missing some point…

I try to run some tests with spidev in slave mode with device that sends data.

But TX1 can not handle the speed of master and missing frames constantly.

It gets only one frame from 3-4 frames sent by master.

I tried to use ioctl with many frames allocated, but it looks like the problem is deeper than copying buffers between user and kernel memory. Because even in that case I get non continues frame numbers in frame set that was successfully received. And I do not get many of them if I allocate more frames (more chance to fail in the middle of set).

Any ideas?

I edited spidev_test.c from Documentation/spi, and added some functionality.

Command: sudo ./test -D /dev/spidev0.0 -H -s 16000000 -b 32 -L -S 4
where “-S 4” is the number of spi_ioc_transfer structs allocated for single ioctl call

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

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

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static volatile int keepRunning = 1;

static void sig_handler(int signo)
{
	printf("Ctrl+C catched, exiting...");
	keepRunning = 0;
	abort();
}

static const char *device = "/dev/spidev0.0";
static char *input_tx;
static uint32_t mode = 1;
static uint8_t bits = 32;
static uint32_t speed = 160000;
static uint16_t delay;
static int verbose;
static uint8_t trs_size = 1;
//define trs_size 64

static unsigned short lsb = 0x0F;
static unsigned short d0_0;
static unsigned short d0_1;
static unsigned short d1_0;

#define frame_size_bytes 128
static uint8_t default_tx[frame_size_bytes] = {0, };

static void pabort(const char *s)
{
	perror(s);
	//keepRunning = 0;
	//abort();
}

// parse frame number
unsigned short get_frame_num(const uint8_t *data)
{
	d0_0 = (data[0] >> 4);
	d0_1 = (data[0] & lsb);
	d1_0 = (data[1] >> 4);
	return (d0_0 << 8) + (d0_1 << 4) + d1_0;
}

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3S]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev0.0)\n"
	     "  -S --size     buffer size\n"
	     "  -s --speed    max speed (Hz)\n"
	     "  -d --delay    delay (usec)\n"
	     "  -b --bpw      bits per word \n"
	     "  -l --loop     loopback\n"
	     "  -H --cpha     clock phase\n"
	     "  -O --cpol     clock polarity\n"
	     "  -L --lsb      least significant bit first\n"
	     "  -C --cs-high  chip select active high\n"
	     "  -3 --3wire    SI/SO signals shared\n"
	     "  -v --verbose  Verbose (show tx buffer)\n"
	     "  -p            Send data (e.g. \"1234\xde\xad\")\n"
	     "  -N --no-cs    no chip select\n"
	     "  -R --ready    slave pulls low to pause\n"
	     "  -2 --dual     dual transfer\n"
	     "  -4 --quad     quad transfer\n");
	exit(1);
}

static void parse_opts(int argc, char *argv[])
{
	while (1) {
		static const struct option lopts[] = {
			{ "trs_size",  0, 0, 'S' },
			{ "device",  1, 0, 'D' },
			{ "speed",   1, 0, 's' },
			{ "delay",   1, 0, 'd' },
			{ "bpw",     1, 0, 'b' },
			{ "loop",    0, 0, 'l' },
			{ "cpha",    0, 0, 'H' },
			{ "cpol",    0, 0, 'O' },
			{ "lsb",     0, 0, 'L' },
			{ "cs-high", 0, 0, 'C' },
			{ "3wire",   0, 0, '3' },
			{ "no-cs",   0, 0, 'N' },
			{ "ready",   0, 0, 'R' },
			{ "dual",    0, 0, '2' },
			{ "verbose", 0, 0, 'v' },
			{ "quad",    0, 0, '4' },
			{ NULL, 0, 0, 0 },
		};
		int c;

		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24pS:v", lopts, NULL);

		if (c == -1)
			break;

		switch (c) {
		case 'D':
			device = optarg;
			break;
		case 'S':
			trs_size = atoi(optarg);
			break;
		case 's':
			speed = atoi(optarg);
			break;
		case 'd':
			delay = atoi(optarg);
			break;
		case 'b':
			bits = atoi(optarg);
			break;
		case 'l':
			mode |= SPI_LOOP;
			break;
		case 'H':
			mode |= SPI_CPHA;
			break;
		case 'O':
			mode |= SPI_CPOL;
			break;
		case 'L':
			mode |= SPI_LSB_FIRST;
			break;
		case 'C':
			mode |= SPI_CS_HIGH;
			break;
		case '3':
			mode |= SPI_3WIRE;
			break;
		case 'N':
			mode |= SPI_NO_CS;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'R':
			mode |= SPI_READY;
			break;
		case 'p':
			input_tx = optarg;
			break;
		case '2':
			mode |= SPI_TX_DUAL;
			break;
		case '4':
			mode |= SPI_TX_QUAD;
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
	if (mode & SPI_LOOP) {
		if (mode & SPI_TX_DUAL)
			mode |= SPI_RX_DUAL;
		if (mode & SPI_TX_QUAD)
			mode |= SPI_RX_QUAD;
	}
}

int setup_spidev()
{
	int ret = 0;
	int fd;

	fd = open(device, O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	/*
	 * spi mode
	 */
	ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
	 * 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");

	printf("spi mode: 0x%x\n", mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

	return fd;
}

void setup_tr(struct spi_ioc_transfer *tr, int size)
{
	tr->rx_buf = (unsigned long)malloc(size);
	tr->len = size;
	if (mode & SPI_TX_QUAD)
		tr->tx_nbits = 4;
	else if (mode & SPI_TX_DUAL)
		tr->tx_nbits = 2;
	if (mode & SPI_RX_QUAD)
		tr->rx_nbits = 4;
	else if (mode & SPI_RX_DUAL)
		tr->rx_nbits = 2;
}

int main(int argc, char *argv[])
{
	signal(SIGINT, sig_handler);

	int spi_ret;
	int fd;
	int size = ARRAY_SIZE(default_tx);
	int ind;

	parse_opts(argc, argv);

	fd = setup_spidev();


	struct spi_ioc_transfer *trs = malloc(sizeof(struct spi_ioc_transfer) * trs_size);

	for (ind=0; ind<trs_size; ind++)
	{
		setup_tr(&trs[ind], size);
	}

    while (keepRunning)
    {
        spi_ret = ioctl(fd, SPI_IOC_MESSAGE(trs_size), trs);
        if (spi_ret < 1)
        {
            pabort("can't send spi message");
            continue;
        }

        for (ind=0; ind<trs_size; ind++)
        {
            printf("%02X %02X\n", ((uint8_t*)trs[ind].rx_buf)[0], ((uint8_t*)trs[ind].rx_buf)[1]);
            //((uint8_t*)trs[ind].rx_buf)[0] = 0;
            //((uint8_t*)trs[ind].rx_buf)[1] = 0;
            //memset(((uint8_t*)(trs[ind].rx_buf)), 0, size);
        }
    }

	close(fd);

	return 0;
}

Example output (first 3 digits it is frame number in hex):

nvidia@tegra-ubuntu:~$ sudo ./test -D /dev/spidev0.0 -H -s 16000000 -b 32 -L -S 4
[sudo] password for nvidia: 
spi mode: 0x9
bits per word: 32
max speed: 16000000 Hz (16000 KHz)
can't send spi message: Input/output error
can't send spi message: Input/output error
can't send spi message: Input/output error
06 E0
06 F0
07 00
07 10
can't send spi message: Input/output error
09 D0
09 F0
0A 00
0A 10
0A 30
0A 40
0A 50
0A 60
0A 70
0A 80
0A 90
0A A0
0A B0
0A C0
0A D0
0A E0
can't send spi message: Input/output error
can't send spi message: Input/output error
can't send spi message: Input/output error
can't send spi message: Input/output error
can't send spi message: Input/output error
can't send spi message: Input/output error

From dmesg:

[16020.589676] spi_master spi0: transferred[14] != requested[32]
[16020.595928] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff000e]:BSY I:255 B:14
                FIFO[07400004]:RxF:14 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.615669] spi_master spi0: cpu-xfer-err [status:07400004]
[16020.621911] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff000e]:BSY I:255 B:14
                FIFO[07400004]:RxF:14 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.641613] spi_master spi0: failed to transfer one message from queue
[16020.654744] spi_master spi0: transferred[6] != requested[32]
[16020.660479] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0006]:BSY I:255 B:6
                FIFO[03400004]:RxF:6 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.681829] spi_master spi0: cpu-xfer-err [status:03400004]
[16020.689157] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0006]:BSY I:255 B:6
                FIFO[03400004]:RxF:6 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.708683] spi_master spi0: failed to transfer one message from queue
[16020.720678] spi_master spi0: transferred[31] != requested[32]
[16020.727014] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001f]:BSY I:255 B:31
                FIFO[0fc00004]:RxF:31 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.746509] spi_master spi0: cpu-xfer-err [status:0fc00004]
[16020.752587] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001f]:BSY I:255 B:31
                FIFO[0fc00004]:RxF:31 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.772344] spi_master spi0: failed to transfer one message from queue
[16020.793127] spi_master spi0: transferred[5] != requested[32]
[16020.798954] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0005]:BSY I:255 B:5
                FIFO[02c00004]:RxF:5 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.824370] spi_master spi0: cpu-xfer-err [status:02c00004]
[16020.830526] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0005]:BSY I:255 B:5
                FIFO[02c00004]:RxF:5 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.850016] spi_master spi0: failed to transfer one message from queue
[16020.901351] spi_master spi0: transferred[20] != requested[32]
[16020.907237] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0014]:BSY I:255 B:20
                FIFO[0a400004]:RxF:20 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.928623] spi_master spi0: cpu-xfer-err [status:0a400004]
[16020.934542] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0014]:BSY I:255 B:20
                FIFO[0a400004]:RxF:20 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.954178] spi_master spi0: failed to transfer one message from queue
[16020.962127] spi_master spi0: transferred[26] != requested[32]
[16020.968017] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001a]:BSY I:255 B:26
                FIFO[0d400004]:RxF:26 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16020.987571] spi_master spi0: cpu-xfer-err [status:0d400004]
[16020.995662] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001a]:BSY I:255 B:26
                FIFO[0d400004]:RxF:26 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.015476] spi_master spi0: failed to transfer one message from queue
[16021.033756] spi_master spi0: transferred[21] != requested[32]
[16021.039627] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0015]:BSY I:255 B:21
                FIFO[0ac00004]:RxF:21 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.059259] spi_master spi0: cpu-xfer-err [status:0ac00004]
[16021.065171] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0015]:BSY I:255 B:21
                FIFO[0ac00004]:RxF:21 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.084648] spi_master spi0: failed to transfer one message from queue
[16021.099966] spi_master spi0: transferred[22] != requested[32]
[16021.105852] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0016]:BSY I:255 B:22
                FIFO[0b400004]:RxF:22 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.125783] spi_master spi0: cpu-xfer-err [status:0b400004]
[16021.131623] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff0016]:BSY I:255 B:22
                FIFO[0b400004]:RxF:22 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.151186] spi_master spi0: failed to transfer one message from queue
[16021.160088] spi_master spi0: transferred[31] != requested[32]
[16021.166580] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001f]:BSY I:255 B:31
                FIFO[0fc00004]:RxF:31 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.187324] spi_master spi0: cpu-xfer-err [status:0fc00004]
[16021.193063] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff001f]:BSY I:255 B:31
                FIFO[0fc00004]:RxF:31 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.213018] spi_master spi0: failed to transfer one message from queue
[16021.220576] spi_master spi0: transferred[11] != requested[32]
[16021.226498] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff000b]:BSY I:255 B:11
                FIFO[05c00004]:RxF:11 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.246047] spi_master spi0: cpu-xfer-err [status:05c00004]
[16021.251709] spi_master spi0:   CMD[13f1101f]:  Sl M1 CS0 [HHHH] MSB LSb Rx  Un 32b TRANS[00ff000b]:BSY I:255 B:11
                FIFO[05c00004]:RxF:11 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00000000]:    RxTr:0 TxTr:0 B:31
[16021.271507] spi_master spi0: failed to transfer one message from queue
[16023.263560] spi-tegra124-slave 7000d400.spi: waiting for master was interrupted
[16023.271649] spi_master spi0: failed to transfer one message from queue

Hi alexyr,

Have you tried to force system to max performance to see if improved?
[url]http://elinux.org/Jetson/TX1_Controlling_Performance[/url]

Thanks

I can not see any difference, also looks like this script a little bit outdated:

Enabling fan for safety...
./jetson_max_l4t.sh: 10: ./jetson_max_l4t.sh: cannot create /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable: Directory nonexistent
./jetson_max_l4t.sh: 11: ./jetson_max_l4t.sh: cannot create /sys/kernel/cluster/immediate: Directory nonexistent
./jetson_max_l4t.sh: 12: ./jetson_max_l4t.sh: cannot create /sys/kernel/cluster/force: Directory nonexistent
./jetson_max_l4t.sh: 13: ./jetson_max_l4t.sh: cannot create /sys/kernel/cluster/active: Directory nonexistent
cat: /sys/kernel/cluster/active: No such file or directory
Cluster: 
onlining CPUs: ignore errors...
./jetson_max_l4t.sh: 19: ./jetson_max_l4t.sh: cannot create /sys/devices/system/cpu/cpu0/online: Permission denied
Online CPUs: 0-3
CPU0: 1734000
CPU1: 1734000
CPU2: 1734000
CPU3: 1734000

@alexyr
Did you try the SPI loopback? Could you post the kernel/DT what you modify.

No problems with loopback.

I changed the size of spidev buffer in drivers/spi/spidev.c:
static unsigned bufsiz = 65534;

Compiled spidev.ko and spi_tegra124_slave.ko

Extracted /boot/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb, added section for SPI slave:

nvidia@tegra-ubuntu:~$ dtc -I dtb -O dts -o ~/current1.dts /boot/tegra210-jetson-tx1-p2597-2180-a01-devkit-modified.dtb 
nvidia@tegra-ubuntu:~$ dtc -I dtb -O dts -o ~/original.dts /boot/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb 
nvidia@tegra-ubuntu:~$ diff current1.dts original.dts 
3103,3108d3102
< 
< 		default {
< 			gpio-hog;
< 			function;
< 			gpios = <0x10 0x0 0x11 0x0 0x12 0x0 0x13 0x0 0x14 0x0>;
< 		};
3513c3507
< 		compatible = "nvidia,tegra124-spi-slave";
---
> 		compatible = "nvidia,tegra210-spi";
3546,3553d3539
< 
< 		spi0_0 {
< 			compatible = "spidev";
< 			#address-cells = <0x1>;
< 			#size-cells = <0x0>;
< 			reg = <0x0>;
< 			spi-max-frequency = <0x2faf080>;
< 		};
3571c3557
< 		status = "okay";
---
> 		status = "disabled";
3589,3596d3574
< 		};
< 
< 		spi1_0 {
< 			compatible = "spidev";
< 			#address-cells = <0x1>;
< 			#size-cells = <0x0>;
< 			reg = <0x0>;
< 			spi-max-frequency = <0x1312d00>;

Then added to /boot/extlinux/extlinux.conf:
FDT /boot/tegra210-jetson-tx1-p2597-2180-a01-devkit-modified.dtb

First I tried to feed it by simple python script from Raspberry Pi, and I needed to add some sleep between frames to keep it working without problems. Now I use my master device, that sends 128 byte frames (32 bit words, LSB first) and TX1 can not handle it.

If the loopback is working well,
I got no idea for it now. Maybe check the device or try the master mode if any find out.