Skip to content

Commit c12ba00

Browse files
committed
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 #1294 Computed delay is half SPI clock. Signed-off-by: Alexandre Bourdiol <[email protected]>
1 parent 6dec3b6 commit c12ba00

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

Diff for: libraries/SPI/src/utility/spi_com.c

+33
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
*
3636
******************************************************************************
3737
*/
38+
#include "wiring_time.h"
3839
#include "core_debug.h"
3940
#include "stm32_def.h"
4041
#include "utility/spi_com.h"
@@ -183,6 +184,28 @@ uint32_t spi_getClkFreq(spi_t *obj)
183184
return spi_freq;
184185
}
185186

187+
188+
#if defined(STM32H7xx) || defined(STM32MP1xx)
189+
/**
190+
* @brief Compute delay before disabling SPI
191+
* See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294
192+
* Computed delay is half SPI clock
193+
* @param obj : pointer to spi_t structure
194+
* @retval Disable delay in microsecondes
195+
*/
196+
static uint32_t compute_disable_delay(spi_t *obj)
197+
{
198+
uint32_t spi_freq = spi_getClkFreqInst(obj->spi);
199+
uint32_t disable_delay;
200+
uint32_t prescaler;
201+
SPI_HandleTypeDef *handle = &(obj->handle);
202+
203+
prescaler = 1 << ((handle->Init.BaudRatePrescaler >> SPI_CFG1_MBR_Pos) + 1);
204+
disable_delay = ((prescaler * 1000000) / spi_freq) / 2;
205+
return disable_delay;
206+
}
207+
#endif
208+
186209
/**
187210
* @brief SPI initialization function
188211
* @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)
258281
handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
259282
}
260283

284+
#if defined(STM32H7xx) || defined(STM32MP1xx)
285+
// Compute disable delay as baudrate has been modified
286+
obj->disable_delay = compute_disable_delay(obj);
287+
#endif
288+
261289
handle->Init.Direction = SPI_DIRECTION_2LINES;
262290

263291
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,
490518
}
491519

492520
#if defined(STM32H7xx) || defined(STM32MP1xx)
521+
// Add a delay before disabling SPI otherwise last-bit/last-clock may be truncated
522+
// See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294
523+
// Computed delay is half SPI clock
524+
delayMicroseconds(obj->disable_delay);
525+
493526
/* Close transfer */
494527
/* Clear flags */
495528
LL_SPI_ClearFlag_EOT(_SPI);

Diff for: libraries/SPI/src/utility/spi_com.h

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ struct spi_s {
5656
PinName pin_mosi;
5757
PinName pin_sclk;
5858
PinName pin_ssel;
59+
#if defined(STM32H7xx) || defined(STM32MP1xx)
60+
// Delay before disabling SPI.
61+
// See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294
62+
uint32_t disable_delay;
63+
#endif
5964
};
6065

6166
typedef struct spi_s spi_t;

0 commit comments

Comments
 (0)