Page 1 of 1

(resolved) unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 6:50 pm
by toxibunny
here's my code, copy/pasted into nano through mobaxterm through SSH:

Code: Select all

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <[email protected]>
 *
 * 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 <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.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 void pabort(const char *s)
{
	perror(s);
	abort();
}

static const char *device = "/dev/spidev1.1";
static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void transfer(int fd)
{
	int ret;
	uint8_t tx[] = {
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
		0xF0, 0x0D,
	};
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = ARRAY_SIZE(tx),
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

	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;
	if (!(mode & SPI_LOOP)) {
		if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
			tr.rx_buf = 0;
		else if (mode & (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");

	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
		if (!(ret % 6))
			puts("");
		printf("%.2X ", rx[ret]);
	}
	puts("");
}

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev1.1)\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"
	     "  -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[] = {
			{ "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' },
			{ "quad",    0, 0, '4' },
			{ NULL, 0, 0, 0 },
		};
		int c;

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

		if (c == -1)
			break;

		switch (c) {
		case 'D':
			device = 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 'R':
			mode |= SPI_READY;
			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 main(int argc, char *argv[])
{
	int ret = 0;
	int fd;

	parse_opts(argc, argv);

	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);

	transfer(fd);

	close(fd);

	return ret;
}
I'm told to compile it thus:

Code: Select all

gcc -o spidevtester spidevtester.c
But I just get a load of error messages, like this:

Code: Select all

spidevtester.c: In function âtransferâ:
spidevtester.c:60:13: error: âSPI_TX_QUADâ undeclared (first use in this function)
spidevtester.c:60:13: note: each undeclared identifier is reported only once for each function it a                                                         ppears in
spidevtester.c:61:5: error: âstruct spi_ioc_transferâ has no member named âtx_nbitsâ
spidevtester.c:62:18: error: âSPI_TX_DUALâ undeclared (first use in this function)
spidevtester.c:63:5: error: âstruct spi_ioc_transferâ has no member named âtx_nbitsâ
spidevtester.c:64:13: error: âSPI_RX_QUADâ undeclared (first use in this function)
spidevtester.c:65:5: error: âstruct spi_ioc_transferâ has no member named ârx_nbitsâ
spidevtester.c:66:18: error: âSPI_RX_DUALâ undeclared (first use in this function)
spidevtester.c:67:5: error: âstruct spi_ioc_transferâ has no member named ârx_nbitsâ
spidevtester.c: In function âparse_optsâ:
spidevtester.c:172:12: error: âSPI_TX_DUALâ undeclared (first use in this function)
spidevtester.c:175:12: error: âSPI_TX_QUADâ undeclared (first use in this function)
spidevtester.c:184:12: error: âSPI_RX_DUALâ undeclared (first use in this function)
spidevtester.c:186:12: error: âSPI_RX_QUADâ undeclared (first use in this function)
spidevtester.c: In function âmainâ:
spidevtester.c:204:18: error: âSPI_IOC_WR_MODE32â undeclared (first use in this function)
spidevtester.c:208:18: error: âSPI_IOC_RD_MODE32â undeclared (first use in this function)
What am I doing wrong? I don't have much experience with C - I'm planning to use python for the real project, but my python test code isn't working yet either, so I'm just using this confirmed, working test code to make sure that my ports are working at all...

Re: unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 6:57 pm
by toxibunny
...Extra info - I'm using non-noobs raspbian, fully updated, on a model A, and following instructions about the loopback test from here: http://elinux.org/RPi_SPI , and setup instructions from here: http://www.brianhensley.net/2012/07/get ... ry-pi.html

Re: unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 6:59 pm
by joan
The constants SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32, SPI_TX_QUAD, and SPI_TX_DUAL are not present in spidev.h on my laptop or the Pi.

Where did you get the code from?

Re: unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 7:13 pm
by toxibunny
I got it from the spi loopback section on the elinux.org page I linked to in the second post.

Looking at the code now, I can see that it's no good. Others have said it works though. Strange :S

Re: unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 7:19 pm
by joan
toxibunny wrote:I got it from the spi loopback section on the elinux.org page I linked to in the second post.

Looking at the code now, I can see that it's no good. Others have said it works though. Strange :S
I wonder if the code was written before SPI was supported on the Pi by the bcm drivers. The constants look like they are from a more more recent version of spidev.h.

Perhaps when proper support was added an older version of spidev.h was used for compatibility with the rest of the kernel modules.

Re: unable to compile spi loopback tester :(

Posted: Mon Apr 28, 2014 7:32 pm
by toxibunny
Well, I've done enough for tonight. Finally got the headless, usb-hubless model A connecting to wifi on boot, so continuing tomorrow will be easier. Thanks for the info - I was getting really frustrated there...

G'night!

Re: unable to compile spi loopback tester :(

Posted: Tue Apr 29, 2014 12:59 am
by notro
Use this instead:

Code: Select all

wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-3.10.y/Documentation/spi/spidev_test.c
QUAD and DUAL came in 3.12 and Linus' tree is now what's to become 3.15
I'll update the elinux page tomorrow.

Re: unable to compile spi loopback tester :(

Posted: Tue Apr 29, 2014 5:38 am
by toxibunny
notro wrote:Use this instead:

Code: Select all

wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-3.10.y/Documentation/spi/spidev_test.c
QUAD and DUAL came in 3.12 and Linus' tree is now what's to become 3.15
I'll update the elinux page tomorrow.

Thanks! That compiled first time no problems. I had to change the line

Code: Select all

static const char *device = "/dev/spidev1.1";
to

Code: Select all

static const char *device = "/dev/spidev0.0";
to get it to work properly though. But again, thanks very much! Now I know my wires are working... :)

Re: unable to compile spi loopback tester :(

Posted: Tue Apr 29, 2014 12:06 pm
by notro
I had to change the line
Using this argument would achieve the same:

Code: Select all

-D /dev/spidev0.0