diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 2c6e798b33..3b364c0bc7 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -176,7 +176,7 @@ uint8_t SPIClass::transfer(uint8_t data, bool skipReceive) * Optional, default: SPI_TRANSMITRECEIVE. * @return bytes received from the slave in 16 bits format. */ -uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive) +uint16_t SPIClass::transfer16_obsoleted(uint16_t data, bool skipReceive) { uint16_t tmp; @@ -194,6 +194,26 @@ uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive) return data; } +uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive) +{ + uint16_t tmp; + uint16_t out; + + if (_spiSettings.bitOrder) { + tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); + data = tmp; + } + + spi_transfer16(&_spi, (uint16_t *)&data, (!skipReceive) ? (uint16_t *)&out : NULL); + + if (_spiSettings.bitOrder) { + tmp = ((out & 0xff00) >> 8) | ((out & 0xff) << 8); + out = tmp; + } + + return out; +} + /** * @brief Transfer several bytes. Only one buffer used to send and receive data. * begin() or beginTransaction() must be called at least once before. diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 1105991dc7..6aa814b2bb 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -136,6 +136,7 @@ class SPIClass { */ uint8_t transfer(uint8_t data, bool skipReceive = SPI_TRANSMITRECEIVE); uint16_t transfer16(uint16_t data, bool skipReceive = SPI_TRANSMITRECEIVE); + uint16_t transfer16_obsoleted(uint16_t data, bool skipReceive = SPI_TRANSMITRECEIVE); void transfer(void *buf, size_t count, bool skipReceive = SPI_TRANSMITRECEIVE); /* Expand SPI API diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index 6bfd683a53..615020b67d 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -544,6 +544,67 @@ spi_status_e spi_transfer(spi_t *obj, const uint8_t *tx_buffer, uint8_t *rx_buff return ret; } +spi_status_e spi_transfer16(spi_t *obj, const uint16_t *tx_buffer, uint16_t *rx_buffer) +{ + spi_status_e ret = SPI_OK; + uint32_t tickstart; + SPI_TypeDef *_SPI = obj->handle.Instance; + uint16_t *tx_buf = (uint16_t *)tx_buffer; + + tickstart = HAL_GetTick(); + +#if defined(SPI_CR2_TSIZE) + /* Start transfer */ + LL_SPI_SetTransferSize(_SPI, 1); + LL_SPI_Enable(_SPI); + LL_SPI_StartMasterTransfer(_SPI); +#endif + +#if defined(SPI_SR_TXP) + while (!LL_SPI_IsActiveFlag_TXP(_SPI)); +#else + while (!LL_SPI_IsActiveFlag_TXE(_SPI)); +#endif + + LL_SPI_TransmitData16(_SPI, tx_buf ? *tx_buf : 0XFF); + +#if defined(SPI_SR_RXP) + while (!LL_SPI_IsActiveFlag_RXP(_SPI)); +#else + while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); +#endif + + if (rx_buffer) { + *rx_buffer = LL_SPI_ReceiveData16(_SPI); + } else { + LL_SPI_ReceiveData16(_SPI); + } + + if ((SPI_TRANSFER_TIMEOUT != HAL_MAX_DELAY) && + (HAL_GetTick() - tickstart >= SPI_TRANSFER_TIMEOUT)) { + ret = SPI_TIMEOUT; + } + +#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); +#else + /* Wait for end of transfer */ + while (LL_SPI_IsActiveFlag_BSY(_SPI)); +#endif + + return ret; +} + #ifdef __cplusplus } #endif diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index 4d145ff7fd..4132c7f5f1 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -85,6 +85,7 @@ typedef enum { 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, const uint8_t *tx_buffer, uint8_t *rx_buffer, uint16_t len); +spi_status_e spi_transfer16(spi_t *obj, const uint16_t *tx_buffer, uint16_t *rx_buffer); uint32_t spi_getClkFreq(spi_t *obj); #ifdef __cplusplus