In this post we will see how to send and receive SPI messages to the device from userspace.
You can open the SPI device by using the below function call.
You can now set the configuration for the SPI using ioctl calls.
int fd = 0;
fd = open("/dev/spidev2.0", O_RDWR);
if (fd < 0)
{
printf("SPI : can't open device");
return -1;
}
To set the SPI mode
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);To get the SPI mode
if (ret == -1)
{
printf("SPI : can't set spi mode");
return 1;
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);Other SPI Bus properties can be manipulated in the same way.
if (ret == -1)
{
printf("SPI : can't get spi mode");
return 1;
}
Now the send a message over SPI Bus, You will need to fill up the message structure and pass it down.
struct spi_ioc_transfer mesg[1] = { 0, };To receive SPI message
mesg[0].tx_buf = (unsigned long)out_buffer;
mesg[0].len = num_out_bytes;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);
struct spi_ioc_transfer mesg[1] = { 0, };There may be requirements where a write has to be followed by a read without toggling the Chip Select signal. You can form 2 messages as below to handle such situations.
mesg[0].rx_buf = (unsigned long)out_buffer;
mesg[0].len = num_out_bytes;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);
int spidev_if_write_read(unsigned int num_out_bytes,The variable cs_change=0 disables the change in CS signal state between the two transactions.
unsigned char *out_buffer,
unsigned int num_in_bytes,
unsigned char *in_buffer)
{
struct spi_ioc_transfer mesg[2] = { 0, };
uint8_t num_tr = 0;
int ret;
if((out_buffer != NULL) && (num_out_bytes != 0))
{
mesg[0].tx_buf = (unsigned long)out_buffer;
mesg[0].rx_buf = (unsigned long)NULL;
mesg[0].len = num_out_bytes;
mesg[0].cs_change = 0;
num_tr++;
}
if((in_buffer != NULL) && (num_in_bytes != 0))
{
mesg[1].tx_buf = (unsigned long)NULL;
mesg[1].rx_buf = (unsigned long)in_buffer;
mesg[1].len = num_in_bytes;
num_tr++;
}
if(num_tr > 0)
{
ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), mesg);
if(ret == 1)
{
return 1;
}
}
return 0;
}
8 Responses to "Linux - Accessing SPI Bus from User Space - Part II"
this was really good script but actual i am fresh and don't know how to use it
Thats really helpful. how to transfer 16 bit data. I can able to transfer 8 bit data without any problem but transmitting 16 bit data fails.I changed the .bits per word in user space program to 16
web application development in usa
if you only have one message you don't have to make an array... e.g.:
struct spi_ioc_transfer mesg;
memset(&mesg, 0, sizeof mesg);
mesh.tx_buf = (unsigned long)out_buffer;
mesg.len = num_out_bytes;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &mesg);
In your final example (the full duplex transfer), is the response stored in the buffer pointed to by in_buffer? I have created a very similar function, but it accepts only one "buffer" argument that is initially stuffed with data to write and _should_ contain response data when execution completes. For some reason, my response buffer contains nothing but NULL characters. Using a logic analyzer I can verify that a response is sent out over the bus, but my buffer does not have this "read" data.
Let's say that for debugging purposes, you wanted to print the data you read in spidev_if_write_read(). How would you do that? Something like this?
unsigned char* buf_ptr;
printf( "\nSPI Response\n" );
for( buf_ptr = in_buffer; num_in_bytes; num_in_bytes-- )
{
printf( "%02x\n", *buf_ptr++ );
}
Is it possible to increase the array beyond 2? For example, I setup an array with 4 transfers: (TX, RX, TX, RX) and used SPI_IOC_MESSAGE(4).
ret = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
However, I wasn't having any success. Any ideas?
Is it possible to create SPI slave appliction using this ioctl ie (RX, TX)?
I read your blog post of web application development its very useful for me thank you for sharing this amazing post with me.
web-application-development
Post a Comment