diff --git a/docs/spi.md b/docs/spi.md index 5986621..9a53c52 100644 --- a/docs/spi.md +++ b/docs/spi.md @@ -15,6 +15,7 @@ int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags); int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); +int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count); int spi_close(spi_t *spi); void spi_free(spi_t *spi); @@ -108,6 +109,30 @@ Returns 0 on success, or a negative [SPI error code](#return-value) on failure. ------ +``` c +typedef struct spi_msg { + const uint8_t *txbuf; + uint8_t *rxbuf; + size_t len; + bool deselect; + uint16_t deselect_delay_us; + uint8_t word_delay_us; +} spi_msg_t; + +int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count); +``` +Transfer messages, shifting out `len` word counts of the `txbuf` buffer, while shifting in `len` word counts to the `rxbuf` buffer for each message. If `deselect` is true, deselect the device before reselecting it for the following transfer. + +`deselect_delay_us` specifies a delay in microseconds before deselection when `deselect` is true. `word_delay_us` specifies a delay in microseconds between words within a transfer. Note that `deselect_delay_us` and `word_delay_us` may not by supported by all SPI controllers and may be silently ignored. + +`spi` should be a valid pointer to an SPI handle opened with `spi_open()` or `spi_open_advanced()`. + +`rxbuf` may be NULL. `txbuf` and `rxbuf` may point to the same buffer. + +Returns 0 on success, or a negative [SPI error code](#return-value) on failure. + +------ + ``` c int spi_close(spi_t *spi); ``` diff --git a/src/spi.c b/src/spi.c index 14790df..a7d6e94 100644 --- a/src/spi.c +++ b/src/spi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "spi.h" @@ -164,6 +165,31 @@ int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len) { return 0; } +int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count) { + struct spi_ioc_transfer spi_xfer[count]; + + /* Prepare SPI transfer structures */ + memset(spi_xfer, 0, count * sizeof(struct spi_ioc_transfer)); + for (size_t i = 0; i < count; i++) { + spi_xfer[i].tx_buf = (uintptr_t)msgs[i].txbuf; + spi_xfer[i].rx_buf = (uintptr_t)msgs[i].rxbuf; + spi_xfer[i].len = msgs[i].len; + spi_xfer[i].speed_hz = 0; + spi_xfer[i].delay_usecs = msgs[i].deselect_delay_us; + spi_xfer[i].bits_per_word = 0; + spi_xfer[i].cs_change = msgs[i].deselect; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) + spi_xfer[i].word_delay_usecs = msgs[i].word_delay_us; + #endif + } + + /* Transfer */ + if (ioctl(spi->fd, SPI_IOC_MESSAGE(count), spi_xfer) < 0) + return _spi_error(spi, SPI_ERROR_TRANSFER, errno, "SPI transfer"); + + return 0; +} + int spi_close(spi_t *spi) { if (spi->fd < 0) return 0; diff --git a/src/spi.h b/src/spi.h index 5b761c2..e8f2b0a 100644 --- a/src/spi.h +++ b/src/spi.h @@ -12,6 +12,7 @@ extern "C" { #endif #include +#include #include enum spi_error_code { @@ -29,6 +30,15 @@ typedef enum spi_bit_order { LSB_FIRST, } spi_bit_order_t; +typedef struct spi_msg { + const uint8_t *txbuf; + uint8_t *rxbuf; + size_t len; + bool deselect; + uint16_t deselect_delay_us; + uint8_t word_delay_us; +} spi_msg_t; + typedef struct spi_handle spi_t; /* Primary Functions */ @@ -42,6 +52,7 @@ int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags); int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); +int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count); int spi_close(spi_t *spi); void spi_free(spi_t *spi);