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.
select()
should work. Data is ready to read as soon as there is a single byte ready in the kernel's buffer. However, I cannot guarantee that the author of the device driver didn't cut any corners. – Gazeselect()
should work. While you're mindful of these issues would be a good time write a suitable test -- even if everything works on the device you're now targeting, you will be thankful for the test if you later try to build for a device or driver on which it fails. – Boguszioctl_read_some_fpga_register_that_says_if_theres_data()
? It sounds like that's the issue, not SPI. How wouldselect
even help you? It's not SPI that tells whether there's data to read or not but some FPGA register. Does that FPGA register supportselect
? That's what you're waiting for, not SPI. – Pragmaticread
and see if it works. – Pragmatic