inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

SPI errors using spidev

Mon Jul 17, 2017 1:04 pm

Greetings all, I have used the SPI loopback test program from the https://www.raspberrypi.org/documentati ... /README.md page . I can open the SPI device, set the bits and set the frequency, but when I try to set the mode, I get an error. dmesg shows "spidev spi0.0: setup: unsupported mode bits 20".

I have added group spi to the pi users group list,
ls -al /dev/spi*
crw-rw---- 1 root spi 153, 0 Jul 14 16:45 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Jul 14 16:45 /dev/spidev0.1

Code: Select all

static const char *device = "/dev/spidev0.0";
static uint8_t spi_mode = SPI_LOOP | SPI_MODE_0;
static uint8_t bits = 8;
static uint32_t speed = 8000000; // 8MHz
static uint16_t delay;
int spiInit(void)
{
	int spi_filestream;
	int ret;
	
	spi_filestream = open(device, O_RDWR);
	if (spi_filestream < 0)
		printf("\n\n***********\ncan't open device - (%i)\n***********\n\n", spi_filestream);

	/*
	 * spi mode
	 */
	//ret = ioctl(spi_filestream, SPI_IOC_WR_MODE32, &mode);
	ret = ioctl(spi_filestream, SPI_IOC_WR_MODE, &spi_mode);
	if (ret == -1)
		printf("can't set spi mode to %d\n", spi_mode);

	ret = ioctl(spi_filestream, SPI_IOC_RD_MODE, &spi_mode);
	if (ret == -1)
		printf("can't get spi mode\n");

	/*
	 * bits per word
	 */
	ret = ioctl(spi_filestream, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		printf("can't set bits per word\n");

	ret = ioctl(spi_filestream, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		printf("can't get bits per word\n");

	/*
	 * max speed hz
	 */
	ret = ioctl(spi_filestream, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		printf("can't set max speed hz\n");

	ret = ioctl(spi_filestream, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		printf("can't get max speed hz\n");

	printf("Read from SPI:\nspi mode: %d\n", spi_mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
	return spi_filestream;
} // spiInit()


int spiTransaction(int spi_filestream, unsigned int nosBytes, uint8_t *pcTxBuf, uint8_t *pcRxBuf)
{
	int ret;
	// structure used to transfer the data to the Linux driver
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)pcTxBuf,
		.rx_buf = (unsigned long)pcRxBuf,
		.len = nosBytes,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

	if (spi_filestream >= 0)
	{
		ret = ioctl(spi_filestream, SPI_IOC_MESSAGE(1), &tr);
		if (ret < 1)
		{
			printf("can't send spi message");
			return -1;
		}
		for (ret = 0; ret < nosBytes; ret++) {
			if (!(ret % 6))
				puts("");
			printf("%.2X ", pcRxBuf[ret]);
		}
	} else 
		printf("!!! No SPI device\n");
	return 0;
} // spiTransaction()
On the console, I get:
can't set spi mode to 32
Read from SPI:
spi mode: 0
bits per word: 8
max speed: 8000000 Hz (8000 KHz)
can't send spi message
Does someone know what I am doing wrong and how to fix it?
System:
- RaspberryPi3
- raspbian jessie (kernel 4.9.28v7+ #998 SMP Mon May 15 16:55:39)

Modules:

Code: Select all

Module                  Size  Used by
nls_utf8                1656  2
ntfs                  248169  2
bnep                   12051  2
hci_uart               19956  1
btbcm                   7916  1 hci_uart
bluetooth             365511  22 hci_uart,bnep,btbcm
brcmfmac              222874  0
spidev                  7373  0
brcmutil                9092  1 brcmfmac
cfg80211              543027  1 brcmfmac
rfkill                 20851  4 bluetooth,cfg80211
snd_bcm2835            24427  1
snd_pcm                98501  1 snd_bcm2835
snd_timer              23904  1 snd_pcm
i2c_bcm2835             7167  0
snd                    70032  5 snd_timer,snd_bcm2835,snd_pcm
bcm2835_gpiomem         3940  0
spi_bcm2835             7596  0
uio_pdrv_genirq         3923  0
fixed                   3285  0
uio                    10204  1 uio_pdrv_genirq
i2c_dev                 6913  0
fuse                   99603  3
ipv6                  406751  48

User avatar
DougieLawson
Posts: 37088
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: SPI errors using spidev

Mon Jul 17, 2017 8:39 pm

Here's a sample of opening an SPI device and writing a byte to it. The most important part is the memset() call

Code: Select all

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

static char *spiDevice = "/dev/spidev0.1";
static uint8_t spiBPW = 8;
static uint32_t spiSpeed = 5000000;
static uint16_t spiDelay = 0;

int
spi_open (char *dev)
{
  if ((spi_fd = open (dev, O_RDWR)) < 0)
    {
      printf ("error opening %s\n", dev);
      return -1;
    }
  return 0;
}

static void
writeByte (uint8_t reg, uint8_t data)
{
  uint8_t spiBufTx[3];
  uint8_t spiBufRx[3];
  struct spi_ioc_transfer spi;
  memset (&spi, 0, sizeof (spi));
  spiBufTx[0] = CMD_WRITE;
  spiBufTx[1] = reg;
  spiBufTx[2] = data;
  spi.tx_buf = (unsigned long) spiBufTx;
  spi.rx_buf = (unsigned long) spiBufRx;
  spi.len = 3;
  spi.delay_usecs = spiDelay;
  spi.speed_hz = spiSpeed;
  spi.bits_per_word = spiBPW;
  ioctl (spi_fd, SPI_IOC_MESSAGE (1), &spi);
}

int 
main()
{
  spi_open (spiDevice);
  writeByte (IODIRB, 0x00);
}

Note: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

Re: SPI errors using spidev

Mon Jul 17, 2017 9:00 pm

Thanks for the reply :)

I had seen the memset() thing before, but that doesn't explain why I can not set the mode after opening the device. I would like to do the looptest.

I will add in the memset() and see if I get data on the lines.

Ian

inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

Re: SPI errors using spidev

Tue Jul 18, 2017 8:06 am

Added the memset() before setting other variables, no change.

As expected, I still get the printf() for the unable to set mode to loopback (mode 32).

I still get the same error on transmit "can't send spi message".

So, what is different in my setup from 'working' set ups and how to fix it?

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: SPI errors using spidev

Tue Jul 18, 2017 9:24 pm

The spi controller driver spi_bcm2835 doesn't support SPI_LOOP, so if you look in the kernel log (dmesg), you will probably see: setup: unsupported mode bits

SPI_LOOP is for controllers that can do internal loopback.

inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

Re: SPI errors using spidev

Wed Jul 19, 2017 7:44 am

OK, thanks for that. As stated in my original post, I did see that message.

Taken it out, added a jumper wire, so it 'loops back', but I still can't send messages - according to the command line, the ioctl() returns -1

Looking on my logic analyser, nothing is coming out of the SPI, no clocks or cs, let alone data.

So, I conclude the way I set the data up for the SPI transaction must be incorrect. Seen different ways of setting it up. The example I used, had one struct for the entire message (but that also had the SPI_LOOP....), other ways I've seen are more an array of structs for the SPI. So, for 10 data bytes, a 10 element array of transfer structs. Going to play with this for a while......

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: SPI errors using spidev

Wed Jul 19, 2017 2:18 pm

If you print errno, you'll see the actuall error returned from spidev.
Armed with that you can look at the spidev code to see if you can find out why: http://elixir.free-electrons.com/linux/ ... dev.c#L356 (spidev_ioctl())

inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

Re: SPI errors using spidev

Wed Jul 19, 2017 2:38 pm

What I expected, I get -1 returned, so that is EPERM, or sod off, yo are not allowed to do that.

Hmm, so, even though I have permissions set (user pi has groups pi adm dialout cdrom sudo audio video plugdev games users input netdev gpio i2c spi) and the spi devices are crw-rw---- root spi, then I should have access.......

So, problem is here

Code: Select all

/* Check access direction once here; don't repeat below.
	 * IOC_DIR is from the user perspective, while access_ok is
	 * from the kernel perspective; so they look reversed.
	 */
	if (_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE,
				(void __user *)arg, _IOC_SIZE(cmd));
	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
		err = !access_ok(VERIFY_READ,
				(void __user *)arg, _IOC_SIZE(cmd));
	if (err)
		return -EFAULT;
Why does my code cause this?

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: SPI errors using spidev

Mon Jul 24, 2017 2:27 pm

Is errno -1 or does ioctl() return -1?

inky699
Posts: 8
Joined: Mon Mar 20, 2017 11:27 am

Re: SPI errors using spidev

Mon Jul 24, 2017 3:21 pm

ioctl() returns -1

I assumed from the code snippet in the driver, they are the same......

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: SPI errors using spidev

Tue Jul 25, 2017 5:00 pm

You have to look at errno to know the real error code: https://linux.die.net/man/3/errno

Return to “Interfacing (DSI, CSI, I2C, etc.)”