diff --git a/targets/TARGET_STM/TARGET_STM32H7/spi_device.h b/targets/TARGET_STM/TARGET_STM32H7/spi_device.h index ce5afb1a2f..a3c8453ea2 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/spi_device.h +++ b/targets/TARGET_STM/TARGET_STM32H7/spi_device.h @@ -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) diff --git a/targets/TARGET_STM/stm_spi_api.c b/targets/TARGET_STM/stm_spi_api.c index 44b6d13d96..63572659b8 100644 --- a/targets/TARGET_STM/stm_spi_api.c +++ b/targets/TARGET_STM/stm_spi_api.c @@ -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));