A blog by Devendra Tewari
Synchronous Peripheral Interface aka SPI is a rather fast and flexible bidirectional serial interface although it is unable to support as many devices per bus as the I2C bus. The Linux SPI interface supports accessing devices from user space applications using ioctl
calls, which is less developer-friendly than the linux/spi/spi.h
API available from kernel space.
In this post, we explore the different means of transferring data using the linux/spi/spidev.h
header and ioctl
call available in sys/ioctl.h
.
The following code snippet shows how to open an SPI device
fd = open("/dev/spidev0.0", O_RDWR);
if (fd < 0)
{
// error
}
Subsequently, the file descriptor can be used to configure the SPI interface, and to transfer data.
The following code snippet shows how to configure SPI interface characteristics such as transfer mode, bits per word, and clock speed
ioctl(fd, SPI_IOC_WR_MODE, SPI_MODE_2);
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, 8);
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, 8000000U);
Configuration can also be read via similar ioctl
calls but using different requests such as SPI_IOC_RD_MODE
, SPI_IOC_RD_BITS_PER_WORD
, and SPI_IOC_RD_MAX_SPEED_HZ
.
The following code snippet demonstrates how to send data to a device without receiving any data from it
struct spi_ioc_transfer tr[1] = {
{
.tx_buf = (unsigned long)tx,
.len = len,
.delay_usecs = 10,
},
};
errno = 0;
ioctl(fd, SPI_IOC_MESSAGE(1), &(tr));
if (errno != 0)
{
// failed
}
Here, tx
is a preconfigured buffer of length len
, and we want to wait 10
microseconds after the last bit has been transferred.
The following code snippet demonstrates how to send data to a device such as a command, and then receive data from it
struct spi_ioc_transfer tr[2] = {
{
.tx_buf = (unsigned long)tx,
.len = tx_len,
.delay_usecs = 10,
},
{
.rx_buf = (unsigned long)rx,
.len = rx_len,
.delay_usecs = 10,
},
};
errno = 0;
ioctl(fd, SPI_IOC_MESSAGE(2), &(tr));
if (errno != 0)
{
// failed
}
The following code snippet demonstrates how to send data to a device and receive data at the same time i.e. transceive
struct spi_ioc_transfer tr[1] = {
{
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = 10,
},
};
errno = 0;
ioctl(fd, SPI_IOC_MESSAGE(1), &(tr));
if (errno != 0)
{
// failed
}