From 8091319472793f362d8a8e62e08c9538b9d25b93 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 24 Nov 2023 10:36:31 +0100 Subject: [PATCH 1/3] chore(spi): avoid SPI_TRANSFER_TIMEOUT as argument SPI_TRANSFER_TIMEOUT is always passed as an argument while it is a constant definition. So simply function call and check. Signed-off-by: Frederic Pillon --- libraries/SPI/src/SPI.cpp | 8 ++- libraries/SPI/src/SPI.h | 5 -- libraries/SPI/src/utility/spi_com.c | 75 ++++++++++++++--------------- libraries/SPI/src/utility/spi_com.h | 10 +++- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index f42f2e88d7..04d77bded7 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, sizeof(uint8_t), skipReceive); 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, sizeof(uint16_t), skipReceive); if (_spiSettings.bitOrder) { tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); @@ -208,8 +207,7 @@ 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), count, skipReceive); } } diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 1c8bbc11cd..f6dba43b29 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) diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index bd582681bd..ce4e83864d 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -502,69 +502,68 @@ void spi_deinit(spi_t *obj) * @param obj : pointer to spi_t structure * @param buffer : tx data to send before reception * @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, uint8_t *buffer, uint16_t len, bool skipReceive) { spi_status_e ret = SPI_OK; uint32_t tickstart, size = len; SPI_TypeDef *_SPI = obj->handle.Instance; uint8_t *tx_buffer = 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_buffer++); - if (!skipReceive) { + if (!skipReceive) { #if defined(SPI_SR_RXP) - while (!LL_SPI_IsActiveFlag_RXP(_SPI)); + while (!LL_SPI_IsActiveFlag_RXP(_SPI)); #else - while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); + 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; + *buffer++ = 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..b0a920936d 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, uint8_t *buffer, uint16_t len, bool skipReceive); uint32_t spi_getClkFreq(spi_t *obj); #ifdef __cplusplus From 0b9c63d1b1338b96cdf2b3d30567874469ed1984 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 24 Nov 2023 15:44:41 +0100 Subject: [PATCH 2/3] chore(spi): remove virtual function specifier Signed-off-by: Frederic Pillon --- libraries/SPI/src/SPI.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index f6dba43b29..136a8d2f68 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -122,21 +122,21 @@ 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); /* These methods are deprecated and kept for compatibility. * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. From 9df4fe06d4e15bf132dc7fa7246aa363ee3ca7ff Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 24 Nov 2023 10:45:21 +0100 Subject: [PATCH 3/3] feat(spi): add transfer api with tx/rx buffer Fixes #2205 Signed-off-by: Frederic Pillon --- libraries/SPI/README.md | 32 +++++++++++++++++++++-------- libraries/SPI/src/SPI.cpp | 26 ++++++++++++++++++----- libraries/SPI/src/SPI.h | 5 +++++ libraries/SPI/src/utility/spi_com.c | 21 +++++++++++-------- libraries/SPI/src/utility/spi_com.h | 2 +- 5 files changed, 62 insertions(+), 24 deletions(-) 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 04d77bded7..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), skipReceive); + spi_transfer(&_spi, &data, (!skipReceive) ? &data : NULL, sizeof(uint8_t)); return data; } @@ -184,7 +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), 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); @@ -206,11 +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, 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 136a8d2f68..1105991dc7 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -138,6 +138,11 @@ class SPIClass { 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 ce4e83864d..b92b44aea9 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -500,17 +500,18 @@ 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 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, 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) { ret = SPI_ERROR; @@ -530,15 +531,17 @@ spi_status_e spi_transfer(spi_t *obj, uint8_t *buffer, uint16_t len, bool skipRe #else 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)); + while (!LL_SPI_IsActiveFlag_RXP(_SPI)); #else - while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); + while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); #endif - *buffer++ = LL_SPI_ReceiveData8(_SPI); + 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)) { diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index b0a920936d..c6e287b8d5 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -110,7 +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, 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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy