Blocking Transfer and Non - Blocking Transfer
In the context of SPI (Serial Peripheral Interface) data transfers using the spi_sync_transfer() and spi_async_transfer() functions in the Linux kernel, the concepts of blocking and non - blocking transfers are crucial for understanding how data is exchanged between the master and slave devices.
Blocking Transfer (spi_sync_transfer())
Meaning
A blocking transfer, as implemented by the spi_sync_transfer() function, means that the calling thread or process is halted or "blocked" until the entire data transfer operation is completed. In other words, the program execution pauses at the point where the spi_sync_transfer() function is called and does not proceed further until the SPI transfer has finished successfully or encountered an error.
Use - cases
Example
#include <linux/spi/spi.h>
// Assume spi is a valid pointer to a struct spi_device
struct spi_transfer xfer = {
.tx_buf = tx_data,
.rx_buf = rx_data,
.len = data_length,
.bits_per_word = 8,
};
struct spi_message msg;
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
// Blocking transfer
int ret = spi_sync_transfer(spi, &msg);
if (ret < 0) {
// Handle error
}
Non - Blocking Transfer (spi_async_transfer())
Meaning
A non - blocking transfer, implemented by the spi_async_transfer() function, allows the calling thread or process to continue executing other tasks while the SPI data transfer is taking place in the background. Instead of waiting for the transfer to finish, the function schedules the transfer and returns immediately. The transfer is often performed using Direct Memory Access (DMA), which can move data between the memory and the SPI device without the intervention of the CPU for each data byte, making it more efficient for large - scale data transfers.
Use - cases
Example
#include <linux/spi/spi.h>
// Assume spi is a valid pointer to a struct spi_device
struct spi_transfer xfer = {
.tx_buf = tx_data,
.rx_buf = rx_data,
.len = data_length,
.bits_per_word = 8,
};
struct spi_message msg;
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
// Callback function to be called when the transfer is complete
static void spi_transfer_complete(void *context) {
// Handle transfer completion, e.g., check for errors
}
msg.complete = spi_transfer_complete;
msg.context = NULL;
// Non - blocking transfer
int ret = spi_async_transfer(spi, &msg);
if (ret < 0) {
// Handle error in scheduling the transfer
}
// The calling thread can continue with other tasks here
In summary, the choice between blocking and non - blocking transfers depends on the specific requirements of your application, such as performance, simplicity, and the need for concurrent task execution.