From c12ba000a8f7437deb9fe0606cce708d9b83b2b0 Mon Sep 17 00:00:00 2001 From: Alexandre Bourdiol Date: Thu, 23 Sep 2021 14:31:50 +0200 Subject: [PATCH] spi: Add delay before disabling SPI to avoid truncated clock/data signals 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. Signed-off-by: Alexandre Bourdiol --- libraries/SPI/src/utility/spi_com.c | 33 +++++++++++++++++++++++++++++ libraries/SPI/src/utility/spi_com.h | 5 +++++ 2 files changed, 38 insertions(+) diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index 93b3a7cc0d..65599d764a 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -35,6 +35,7 @@ * ****************************************************************************** */ +#include "wiring_time.h" #include "core_debug.h" #include "stm32_def.h" #include "utility/spi_com.h" @@ -183,6 +184,28 @@ uint32_t spi_getClkFreq(spi_t *obj) return spi_freq; } + +#if defined(STM32H7xx) || defined(STM32MP1xx) +/** + * @brief Compute delay before disabling SPI + * See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294 + * Computed delay is half SPI clock + * @param obj : pointer to spi_t structure + * @retval Disable delay in microsecondes + */ +static uint32_t compute_disable_delay(spi_t *obj) +{ + uint32_t spi_freq = spi_getClkFreqInst(obj->spi); + uint32_t disable_delay; + uint32_t prescaler; + SPI_HandleTypeDef *handle = &(obj->handle); + + prescaler = 1 << ((handle->Init.BaudRatePrescaler >> SPI_CFG1_MBR_Pos) + 1); + disable_delay = ((prescaler * 1000000) / spi_freq) / 2; + return disable_delay; +} +#endif + /** * @brief SPI initialization function * @param obj : pointer to spi_t structure @@ -258,6 +281,11 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; } +#if defined(STM32H7xx) || defined(STM32MP1xx) + // Compute disable delay as baudrate has been modified + obj->disable_delay = compute_disable_delay(obj); +#endif + handle->Init.Direction = SPI_DIRECTION_2LINES; if ((mode == SPI_MODE_0) || (mode == SPI_MODE_2)) { @@ -490,6 +518,11 @@ spi_status_e spi_transfer(spi_t *obj, uint8_t *tx_buffer, uint8_t *rx_buffer, } #if defined(STM32H7xx) || defined(STM32MP1xx) + // 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); diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index abf611cba7..da96b72b86 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -56,6 +56,11 @@ struct spi_s { PinName pin_mosi; PinName pin_sclk; PinName pin_ssel; +#if defined(STM32H7xx) || defined(STM32MP1xx) + // Delay before disabling SPI. + // See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294 + uint32_t disable_delay; +#endif }; typedef struct spi_s spi_t;