Merge pull request #15028 from jeromecoutant/PR_SPI_V2

STM32 SPI: Update and improvement
pull/15061/head
Martin Kojtal 2021-09-08 14:37:14 +01:00 committed by GitHub
commit 3eae29b01d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 142 additions and 39 deletions

View File

@ -19,6 +19,8 @@
#include "stm32h7xx_ll_rcc.h"
#include "stm32h7xx_ll_spi.h"
#define SPI_IP_VERSION_V2
// Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0xFFFFFFF8)

View File

@ -197,9 +197,27 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
spiobj->spi = (SPIName)pinmap->peripheral;
MBED_ASSERT(spiobj->spi != (SPIName)NC);
#if defined(SPI_IP_VERSION_V2)
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
#endif /* SPI_IP_VERSION_V2 */
#if defined SPI1_BASE
// Enable SPI clock
if (spiobj->spi == SPI_1) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
__HAL_RCC_SPI1_CLK_ENABLE();
spiobj->spiIRQ = SPI1_IRQn;
}
@ -207,6 +225,20 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#if defined SPI2_BASE
if (spiobj->spi == SPI_2) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI2_FORCE_RESET();
__HAL_RCC_SPI2_RELEASE_RESET();
__HAL_RCC_SPI2_CLK_ENABLE();
spiobj->spiIRQ = SPI2_IRQn;
}
@ -214,6 +246,20 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#if defined SPI3_BASE
if (spiobj->spi == SPI_3) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI3;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi3ClockSelection = RCC_SPI3CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI3_FORCE_RESET();
__HAL_RCC_SPI3_RELEASE_RESET();
__HAL_RCC_SPI3_CLK_ENABLE();
spiobj->spiIRQ = SPI3_IRQn;
}
@ -221,6 +267,16 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#if defined SPI4_BASE
if (spiobj->spi == SPI_4) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI4;
PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI4_FORCE_RESET();
__HAL_RCC_SPI4_RELEASE_RESET();
__HAL_RCC_SPI4_CLK_ENABLE();
spiobj->spiIRQ = SPI4_IRQn;
}
@ -228,6 +284,16 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#if defined SPI5_BASE
if (spiobj->spi == SPI_5) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI5;
PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI5_FORCE_RESET();
__HAL_RCC_SPI5_RELEASE_RESET();
__HAL_RCC_SPI5_CLK_ENABLE();
spiobj->spiIRQ = SPI5_IRQn;
}
@ -235,6 +301,16 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
#if defined SPI6_BASE
if (spiobj->spi == SPI_6) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI6;
PeriphClkInit.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PCLK4;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */
__HAL_RCC_SPI6_FORCE_RESET();
__HAL_RCC_SPI6_RELEASE_RESET();
__HAL_RCC_SPI6_CLK_ENABLE();
spiobj->spiIRQ = SPI6_IRQn;
}
@ -242,13 +318,14 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
// Configure the SPI pins
pin_function(pinmap->mosi_pin, pinmap->mosi_function);
pin_mode(pinmap->mosi_pin, PullNone);
pin_mode(pinmap->mosi_pin, PullDown); // Pull Down is set for output line
pin_function(pinmap->miso_pin, pinmap->miso_function);
pin_mode(pinmap->miso_pin, PullNone);
pin_function(pinmap->sclk_pin, pinmap->sclk_function);
pin_mode(pinmap->sclk_pin, PullNone);
spiobj->pin_miso = pinmap->miso_pin;
spiobj->pin_mosi = pinmap->mosi_pin;
spiobj->pin_sclk = pinmap->sclk_pin;
@ -289,10 +366,21 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
handle->Init.TIMode = SPI_TIMODE_DISABLE;
#if TARGET_STM32H7
#if defined (SPI_IP_VERSION_V2)
handle->Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
handle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
handle->Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
handle->Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
handle->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
handle->Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
handle->Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
handle->Init.IOSwap = SPI_IO_SWAP_DISABLE;
#if defined(SPI_RDY_MASTER_MANAGEMENT_INTERNALLY)
handle->Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
handle->Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
#endif
#endif /* SPI_IP_VERSION_V2 */
/*
* According the STM32 Datasheet for SPI peripheral we need to PULLDOWN
@ -580,16 +668,21 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
handle->Init.NSS = (slave) ? SPI_NSS_HARD_INPUT : SPI_NSS_HARD_OUTPUT;
}
handle->Init.Mode = (slave) ? SPI_MODE_SLAVE : SPI_MODE_MASTER;
if (slave) {
handle->Init.Mode = SPI_MODE_SLAVE;
if (slave && (handle->Init.Direction == SPI_DIRECTION_1LINE)) {
/* SPI slave implemtation in MBED does not support the 3 wires SPI.
* (e.g. when MISO is not connected). So we're forcing slave in
* 2LINES mode. As MISO is not connected, slave will only read
* from master, and cannot write to it. Inform user.
*/
debug("3 wires SPI slave not supported - slave will only read\r\n");
handle->Init.Direction = SPI_DIRECTION_2LINES;
if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
/* SPI slave implemtation in MBED does not support the 3 wires SPI.
* (e.g. when MISO is not connected). So we're forcing slave in
* 2LINES mode. As MISO is not connected, slave will only read
* from master, and cannot write to it. Inform user.
*/
debug("3 wires SPI slave not supported - slave will only read\r\n");
handle->Init.Direction = SPI_DIRECTION_2LINES;
}
pin_mode(spiobj->pin_mosi, PullNone);
pin_mode(spiobj->pin_miso, PullDown); // Pull Down is set for output line
}
/*
@ -699,7 +792,11 @@ static inline int ssp_readable(spi_t *obj)
SPI_HandleTypeDef *handle = &(spiobj->handle);
// Check if data is received
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXP) != RESET) ? 1 : 0);
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXNE) != RESET) ? 1 : 0);
#endif /* SPI_IP_VERSION_V2 */
return status;
}
@ -710,7 +807,12 @@ static inline int ssp_writeable(spi_t *obj)
SPI_HandleTypeDef *handle = &(spiobj->handle);
// Check if data is transmitted
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_TXP) != RESET) ? 1 : 0);
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_TXE) != RESET) ? 1 : 0);
#endif /* SPI_IP_VERSION_V2 */
return status;
}
@ -719,11 +821,11 @@ static inline int ssp_busy(spi_t *obj)
int status;
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXWNE) != RESET) ? 1 : 0);
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_BSY) != RESET) ? 1 : 0);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
return status;
}
@ -845,11 +947,11 @@ static inline int datasize_to_transfer_bitshift(uint32_t DataSize)
*/
static inline int msp_writable(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return (int)LL_SPI_IsActiveFlag_TXP(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_TXE(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}
/**
@ -860,11 +962,11 @@ static inline int msp_writable(spi_t *obj)
*/
static inline int msp_readable(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return (int)LL_SPI_IsActiveFlag_RXP(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_RXNE(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}
/**
@ -891,11 +993,11 @@ static inline void msp_wait_readable(spi_t *obj)
*/
static inline int msp_busy(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return !(int)LL_SPI_IsActiveFlag_TXC(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_BSY(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}
/**
@ -962,15 +1064,15 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
/* Transmit data */
if (tx_length) {
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
LL_SPI_Enable(SPI_INST(obj));
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Master transfer start */
LL_SPI_StartMasterTransfer(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
for (int i = 0; i < tx_length; i++) {
msp_wait_writable(obj);
@ -982,19 +1084,19 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
LL_SPI_Disable(SPI_INST(obj));
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Clear transaction flags */
LL_SPI_ClearFlag_EOT(SPI_INST(obj));
LL_SPI_ClearFlag_TXTF(SPI_INST(obj));
/* Reset transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), 0);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}
/* Receive data */
if (rx_length) {
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_RX);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size and run SPI */
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length);
LL_SPI_Enable(SPI_INST(obj));
@ -1014,7 +1116,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
/* Reset transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), 0);
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
/* Unlike STM32H7 other STM32 families generates SPI Clock signal continuously in half-duplex receive mode
* till SPI is enabled. To stop clock generation a SPI should be disabled during last frame receiving,
* after generation at least one SPI clock cycle. It causes necessity of critical section usage.
@ -1044,7 +1146,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
rx_buffer[i] = msp_read_data(obj, bitshift);
}
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}
return rx_length + tx_length;
@ -1077,10 +1179,10 @@ int spi_master_write(spi_t *obj, int value)
* but this will increase performances significantly
*/
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Master transfer start */
LL_SPI_StartMasterTransfer(SPI_INST(obj));
#endif
#endif /* SPI_IP_VERSION_V2 */
/* Transmit data */
msp_wait_writable(obj);
@ -1241,7 +1343,7 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
NVIC_EnableIRQ(irq_n);
// flush FIFO
#if defined(SPI_FLAG_FRLVL) // STM32F0 STM32F3 STM32F7 STM32L4
#if defined(SPI_FLAG_FRLVL)
HAL_SPIEx_FlushRxFifo(handle);
#endif
@ -1306,11 +1408,10 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
obj->spi.event = event;
DEBUG_PRINTF("SPI: Transfer: %u, %u\n", tx_length, rx_length);
// register the thunking handler
IRQn_Type irq_n = spiobj->spiIRQ;
NVIC_SetVector(irq_n, (uint32_t)handler);
DEBUG_PRINTF("SPI: Transfer: tx %u (%u), rx %u (%u), IRQ %u\n", use_tx, tx_length, use_rx, rx_length, irq_n);
// enable the right hal transfer
if (use_tx && use_rx) {
@ -1355,7 +1456,7 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
// disable the interrupt
NVIC_DisableIRQ(obj->spi.spiIRQ);
NVIC_ClearPendingIRQ(obj->spi.spiIRQ);
#ifndef TARGET_STM32H7
#if !defined(SPI_IP_VERSION_V2)
if (handle->Init.Direction == SPI_DIRECTION_1LINE && obj->rx_buff.buffer != NULL) {
/**
* In case of 3-wire SPI data receiving we usually get dummy reads.
@ -1365,7 +1466,7 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
*/
spi_flush_rx(obj);
}
#endif
#endif /* SPI_IP_VERSION_V2 */
}
return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));