Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I select() on a /dev/spidev file descriptor?

I'm maintaining some userspace code that talks to a FPGA via SPI. Right now it's polling to see if there's data to act on, which I'm not thrilled about. The (heavily-simplified) structure of the comm thread looks like this:

int spi_fd;

void do_transfer(char *buf, int len)
{
    struct spi_ioc_transfer xfer;
    memset(xfer, 0, sizeof(xfer));

    ioctl_tell_some_fpga_register_heads_up();

    xfer[0].len = len;
    xfer[0].tx_buf = NULL;
    xfer[0].rx_buf = buf;
    ioctl(spi_fd, SPI_IOC_MESSAGE(1), xfer);

    ioctl_tell_some_fpga_register_were_done();
}

void *comm_thread(void arg)
{
    uint8_t config = SPI_MODE_3;
    __u32 speed = 4000000;
    char buffer[5120];

    spi_fd = open("/dev/spidev1.0", O_RDWR);
    ioctl(spi_fd, SPI_IOC_WR_MODE, &config);
    ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

    while(1) {
        sleep(2); //ugh
        if(ioctl_read_some_fpga_register_that_says_if_theres_data())
        {
            do_transfer(buffer, some_small_number_of_bytes());
            do_stuff(buffer); //you get the picture
        }
    }
}

I'd really prefer an event-based solution over poll-and-sleep. The first thing that came to mind was doing a select() on the spidev file descriptor instead of checking some register every X seconds, something like

fd_set myset;

while(1) {
    FD_ZERO(&myset);
    FD_SET(spi_fd, &myset);
    select(spi_fd + 1, &myset, NULL, NULL, NULL);
    do_transfer(buffer, some_small_number_of_bytes());
    do_stuff(buffer);
}

Thing is I can't find any examples of people handling SPI like that, and I'm wondering if maybe there's a good reason for it. Can /dev/spidev be used this way? Will it do something goofy like always/never being "ready to read"? Can it be made to behave the way I want? Is it hardware dependent? I'm not averse to a little kernel driver hacking if it's necessary, but I'm not really sure if/where I need to be looking.

like image 993
laughingcoyote Avatar asked Apr 14 '16 14:04

laughingcoyote


People also ask

Why is/Dev/spidev not showing up?

/dev/spidev wasn't showing up because files were missing in /lib/modules. I cross compiled the rt kernel and when I was installing it on the target I forgot to copy the /lib/modules/4.9.80-rt62-v7+ and /lib/firmware. After copying the contents of those directories onto the taget and rebooting /dev/spidev exists!

How to use spidev on Raspberry Pi?

1 Enable SPI on the Raspberry Pi In your Pi’s terminal, run sudo raspi-config Go to Advanced Options > SPI Choose “Yes” for both questions then select Finish to ... 2 Install spidev Spidev is a python module that allows us to interface with the Pi’s SPI bus. ... 3 Python script

When should you not use a file descriptor?

Under most circumstances, we should avoid the use of file descriptors 0, 1 and 2, since these file descriptors are assigned to standard in, standard out and standard error. In the example shown, each time we read from infile, our position in the file will be incremented by one line.

How do I assign a file descriptor to an input file?

First, you can assign a file descriptor to an input file with this syntax: where 3 is the file descriptor we have chosen to use and file is the name of the file. Under most circumstances, we should avoid the use of file descriptors 0, 1 and 2, since these file descriptors are assigned to standard in, standard out and standard error.


1 Answers

Can I select() on a /dev/spidev file descriptor?

No.
The spidev documentation states

At this time there is no async I/O support; everything is purely synchronous.

More importantly the spidev driver does not support a poll file operation. The select() syscall requires the device driver to support a poll fops.

670 static const struct file_operations spidev_fops = {
671         .owner =        THIS_MODULE,
672         /* REVISIT switch to aio primitives, so that userspace
673          * gets more complete API coverage.  It'll simplify things
674          * too, except for the locking.
675          */
676         .write =        spidev_write,
677         .read =         spidev_read,
678         .unlocked_ioctl = spidev_ioctl,
679         .compat_ioctl = spidev_compat_ioctl,
680         .open =         spidev_open,
681         .release =      spidev_release,
682         .llseek =       no_llseek,
683 };
like image 144
sawdust Avatar answered Sep 21 '22 03:09

sawdust