diff --git a/libraries/SPI/README.md b/libraries/SPI/README.md index 59564fd7e5..7a0595c1cc 100644 --- a/libraries/SPI/README.md +++ b/libraries/SPI/README.md @@ -7,16 +7,18 @@ User have 2 possibilities about the management of the CS pin: * the CS pin is managed directly by the user code before to transfer the data (like the Arduino SPI library) * the user uses a hardware CS pin linked to the SPI peripheral -### New API functions +## New API functions -* `SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)`: alternative class constructor -_Params_ SPI `mosi` pin -_Params_ SPI `miso` pin -_Params_ SPI `sclk` pin -_Params_ (optional) SPI `ssel` pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral. +#### Alternative class constructor +* `SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)` + +_Param_ SPI `mosi` pin - * `SPI_HandleTypeDef *getHandle(void)`: Could be used to mix Arduino API and STM32Cube HAL API (ex: DMA). **Use at your own risk.** +_Param_ SPI `miso` pin +_Param_ SPI `sclk` pin + +_Params_ (optional) SPI `ssel` pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral. ##### Example @@ -35,9 +37,15 @@ void setup() { } ``` -### Extended API +#### Transfer with Tx/Rx buffer + +* `void transfer(const void *tx_buf, void *rx_buf, size_t count)` :Transfer several bytes. One constant buffer used to send and one to receive data. -* All `transfer()` API's have a new bool argument `skipReceive`. It allows to skip receive data after transmitting. Value can be `SPI_TRANSMITRECEIVE` or `SPI_TRANSMITONLY`. Default `SPI_TRANSMITRECEIVE`. + _Param_ `tx_buf`: constant array of Tx bytes that is filled by the user before starting the SPI transfer. If NULL, default dummy 0xFF bytes will be clocked out. + + _Param_ `rx_buf`: array of Rx bytes that will be filled by the slave during the SPI transfer. If NULL, the received data will be discarded. + + _Param_ `count`: number of bytes to send/receive. #### Change default `SPI` instance pins It is also possible to change the default pins used by the `SPI` instance using above API: @@ -63,3 +71,9 @@ It is also possible to change the default pins used by the `SPI` instance using SPI.setMOSI(PC2); // using pin number PYn SPI.begin(2); ``` + +* `SPI_HandleTypeDef *getHandle(void)`: Could be used to mix Arduino API and STM32Cube HAL API (ex: DMA). **Use at your own risk.** + +## Extended API + +* All defaustatndard `transfer()` API's have a new bool argument `skipReceive`. It allows to skip receive data after transmitting. Value can be `SPI_TRANSMITRECEIVE` or `SPI_TRANSMITONLY`. Default `SPI_TRANSMITRECEIVE`. diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index f42f2e88d7..2c6e798b33 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -163,7 +163,7 @@ void SPIClass::setClockDivider(uint8_t divider) */ uint8_t SPIClass::transfer(uint8_t data, bool skipReceive) { - spi_transfer(&_spi, &data, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT, skipReceive); + spi_transfer(&_spi, &data, (!skipReceive) ? &data : NULL, sizeof(uint8_t)); return data; } @@ -184,8 +184,7 @@ uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive) tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); data = tmp; } - spi_transfer(&_spi, (uint8_t *)&data, sizeof(uint16_t), - SPI_TRANSFER_TIMEOUT, skipReceive); + spi_transfer(&_spi, (uint8_t *)&data, (!skipReceive) ? (uint8_t *)&data : NULL, sizeof(uint16_t)); if (_spiSettings.bitOrder) { tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); @@ -207,12 +206,27 @@ uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive) */ void SPIClass::transfer(void *buf, size_t count, bool skipReceive) { - if ((count != 0) && (buf != NULL)) { - spi_transfer(&_spi, ((uint8_t *)buf), count, - SPI_TRANSFER_TIMEOUT, skipReceive); - } + spi_transfer(&_spi, (uint8_t *)buf, (!skipReceive) ? (uint8_t *)buf : NULL, count); + +} + +/** + * @brief Transfer several bytes. One constant buffer used to send and + * one to receive data. + * begin() or beginTransaction() must be called at least once before. + * @param tx_buf: array of Tx bytes that is filled by the user before starting + * the SPI transfer. If NULL, default dummy 0xFF bytes will be + * clocked out. + * @param rx_buf: array of Rx bytes that will be filled by the slave during + * the SPI transfer. If NULL, the received data will be discarded. + * @param count: number of bytes to send/receive. + */ +void SPIClass::transfer(const void *tx_buf, void *rx_buf, size_t count) +{ + spi_transfer(&_spi, ((const uint8_t *)tx_buf), ((uint8_t *)rx_buf), count); } + /** * @brief Not implemented. */ diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 1c8bbc11cd..1105991dc7 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -41,11 +41,6 @@ extern "C" { #define SPI_TRANSMITRECEIVE false #define SPI_TRANSMITONLY true -// Defines a default timeout delay in milliseconds for the SPI transfer -#ifndef SPI_TRANSFER_TIMEOUT - #define SPI_TRANSFER_TIMEOUT 1000 -#endif - class SPISettings { public: constexpr SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) @@ -127,21 +122,26 @@ class SPIClass { _spi.pin_ssel = (ssel); }; - virtual void begin(void); + void begin(void); void end(void); /* This function should be used to configure the SPI instance in case you * don't use default parameters. */ void beginTransaction(SPISettings settings); - virtual void endTransaction(void); + void endTransaction(void); /* Transfer functions: must be called after initialization of the SPI * instance with begin() or beginTransaction(). */ - virtual uint8_t transfer(uint8_t data, bool skipReceive = SPI_TRANSMITRECEIVE); - virtual uint16_t transfer16(uint16_t data, bool skipReceive = SPI_TRANSMITRECEIVE); - virtual void transfer(void *buf, size_t count, bool skipReceive = SPI_TRANSMITRECEIVE); + uint8_t transfer(uint8_t data, bool skipReceive = SPI_TRANSMITRECEIVE); + uint16_t transfer16(uint16_t data, bool skipReceive = SPI_TRANSMITRECEIVE); + void transfer(void *buf, size_t count, bool skipReceive = SPI_TRANSMITRECEIVE); + + /* Expand SPI API + * https://github.com/arduino/ArduinoCore-API/discussions/189 + */ + void transfer(const void *tx_buf, void *rx_buf, size_t count); /* These methods are deprecated and kept for compatibility. * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index bd582681bd..b92b44aea9 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -500,71 +500,73 @@ void spi_deinit(spi_t *obj) * @brief This function is implemented by user to send/receive data over * SPI interface * @param obj : pointer to spi_t structure - * @param buffer : tx data to send before reception + * @param tx_buffer : tx data to send before reception + * @param rx_buffer : rx data to receive if not numm * @param len : length in byte of the data to send and receive - * @param Timeout: Timeout duration in tick - * @param skipReceive: skip receiving data after transmit or not * @retval status of the send operation (0) in case of error */ -spi_status_e spi_transfer(spi_t *obj, uint8_t *buffer, uint16_t len, - uint32_t Timeout, bool skipReceive) +spi_status_e spi_transfer(spi_t *obj, const uint8_t *tx_buffer, uint8_t *rx_buffer, + uint16_t len) { spi_status_e ret = SPI_OK; uint32_t tickstart, size = len; SPI_TypeDef *_SPI = obj->handle.Instance; - uint8_t *tx_buffer = buffer; + uint8_t *tx_buf = (uint8_t *)tx_buffer; - if ((len == 0) || (Timeout == 0U)) { - return Timeout > 0U ? SPI_ERROR : SPI_TIMEOUT; - } - tickstart = HAL_GetTick(); + if (len == 0) { + ret = SPI_ERROR; + } else { + tickstart = HAL_GetTick(); #if defined(SPI_CR2_TSIZE) - /* Start transfer */ - LL_SPI_SetTransferSize(_SPI, size); - LL_SPI_Enable(_SPI); - LL_SPI_StartMasterTransfer(_SPI); + /* Start transfer */ + LL_SPI_SetTransferSize(_SPI, size); + LL_SPI_Enable(_SPI); + LL_SPI_StartMasterTransfer(_SPI); #endif - while (size--) { + while (size--) { #if defined(SPI_SR_TXP) - while (!LL_SPI_IsActiveFlag_TXP(_SPI)); + while (!LL_SPI_IsActiveFlag_TXP(_SPI)); #else - while (!LL_SPI_IsActiveFlag_TXE(_SPI)); + while (!LL_SPI_IsActiveFlag_TXE(_SPI)); #endif - LL_SPI_TransmitData8(_SPI, *tx_buffer++); + LL_SPI_TransmitData8(_SPI, tx_buf ? *tx_buf++ : 0XFF); - if (!skipReceive) { #if defined(SPI_SR_RXP) while (!LL_SPI_IsActiveFlag_RXP(_SPI)); #else while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); #endif - *buffer++ = LL_SPI_ReceiveData8(_SPI); - } - if ((Timeout != HAL_MAX_DELAY) && (HAL_GetTick() - tickstart >= Timeout)) { - ret = SPI_TIMEOUT; - break; + if (rx_buffer) { + *rx_buffer++ = LL_SPI_ReceiveData8(_SPI); + } else { + LL_SPI_ReceiveData8(_SPI); + } + if ((SPI_TRANSFER_TIMEOUT != HAL_MAX_DELAY) && + (HAL_GetTick() - tickstart >= SPI_TRANSFER_TIMEOUT)) { + ret = SPI_TIMEOUT; + break; + } } - } #if defined(SPI_IFCR_EOTC) - // Add a delay before disabling SPI otherwise last-bit/last-clock may be truncated - // See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294 - // Computed delay is half SPI clock - delayMicroseconds(obj->disable_delay); - - /* Close transfer */ - /* Clear flags */ - LL_SPI_ClearFlag_EOT(_SPI); - LL_SPI_ClearFlag_TXTF(_SPI); - /* Disable SPI peripheral */ - LL_SPI_Disable(_SPI); + // Add a delay before disabling SPI otherwise last-bit/last-clock may be truncated + // See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294 + // Computed delay is half SPI clock + delayMicroseconds(obj->disable_delay); + + /* Close transfer */ + /* Clear flags */ + LL_SPI_ClearFlag_EOT(_SPI); + LL_SPI_ClearFlag_TXTF(_SPI); + /* Disable SPI peripheral */ + LL_SPI_Disable(_SPI); #else - /* Wait for end of transfer */ - while (LL_SPI_IsActiveFlag_BSY(_SPI)); + /* Wait for end of transfer */ + while (LL_SPI_IsActiveFlag_BSY(_SPI)); #endif - + } return ret; } diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index 7562c08118..c6e287b8d5 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -78,6 +78,13 @@ typedef struct spi_s spi_t; #define SPI_SPEED_CLOCK_DIV128_MHZ ((uint32_t)128) #define SPI_SPEED_CLOCK_DIV256_MHZ ((uint32_t)256) +// Defines a default timeout delay in milliseconds for the SPI transfer +#ifndef SPI_TRANSFER_TIMEOUT +#define SPI_TRANSFER_TIMEOUT 1000 +#elif SPI_TRANSFER_TIMEOUT <= 0 +#error "SPI_TRANSFER_TIMEOUT cannot be less or equal to 0!" +#endif + ///@brief specifies the SPI mode to use //Mode Clock Polarity (CPOL) Clock Phase (CPHA) //SPI_MODE0 0 0 @@ -103,8 +110,7 @@ typedef enum { /* Exported functions ------------------------------------------------------- */ void spi_init(spi_t *obj, uint32_t speed, SPIMode mode, uint8_t msb); void spi_deinit(spi_t *obj); -spi_status_e spi_transfer(spi_t *obj, uint8_t *buffer, uint16_t len, - uint32_t Timeout, bool skipReceive); +spi_status_e spi_transfer(spi_t *obj, const uint8_t *tx_buffer, uint8_t *rx_buffer, uint16_t len); uint32_t spi_getClkFreq(spi_t *obj); #ifdef __cplusplus
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: