diff --git a/os/hal/include/hal_spi_v2.h b/os/hal/include/hal_spi_v2.h index e5e667e07..09269b599 100644 --- a/os/hal/include/hal_spi_v2.h +++ b/os/hal/include/hal_spi_v2.h @@ -165,7 +165,7 @@ struct hal_spi_config { #endif #if (SPI_SUPPORTS_SLAVE_MODE == TRUE) || defined(__DOXYGEN__) /** - * @brief Enables the circular buffer mode. + * @brief Enables the slave mode. */ bool slave; #endif diff --git a/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.c b/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.c index f3d0a9552..36ef2158e 100644 --- a/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.c +++ b/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.c @@ -15,8 +15,8 @@ */ /** - * @file SPIv2/hal_spi_lld.c - * @brief STM32 SPI subsystem low level driver source. + * @file SPIv2/hal_spi_v2_lld.c + * @brief STM32 SPI (v2) subsystem low level driver source. * * @addtogroup SPI * @{ diff --git a/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.h b/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.h index ae42be311..67dbfa8bc 100644 --- a/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.h +++ b/os/hal/ports/STM32/LLD/SPIv2/hal_spi_v2_lld.h @@ -15,8 +15,8 @@ */ /** - * @file SPIv2/hal_spi_lld.h - * @brief STM32 SPI subsystem low level driver header. + * @file SPIv2/hal_spi_v2_lld.h + * @brief STM32 SPI (v2) subsystem low level driver header. * * @addtogroup SPI * @{ diff --git a/os/hal/ports/STM32/LLD/SPIv3/driver_v2.mk b/os/hal/ports/STM32/LLD/SPIv3/driver_v2.mk new file mode 100644 index 000000000..ba12ce73f --- /dev/null +++ b/os/hal/ports/STM32/LLD/SPIv3/driver_v2.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3 diff --git a/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.c b/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.c new file mode 100644 index 000000000..4db485a87 --- /dev/null +++ b/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.c @@ -0,0 +1,1369 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file SPIv3/hal_spi_v2_lld.c + * @brief STM32 SPI (v2) subsystem low level driver source. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SPI1 driver identifier.*/ +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +SPIDriver SPID1; +#endif + +/** @brief SPI2 driver identifier.*/ +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +SPIDriver SPID2; +#endif + +/** @brief SPI3 driver identifier.*/ +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +SPIDriver SPID3; +#endif + +/** @brief SPI4 driver identifier.*/ +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +SPIDriver SPID4; +#endif + +/** @brief SPI5 driver identifier.*/ +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +SPIDriver SPID5; +#endif + +/** @brief SPI6 driver identifier.*/ +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +SPIDriver SPID6; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void spi_lld_start_master(SPIDriver *spip) { + uint32_t cr1; + + cr1 = spip->spi->CR1; + spip->spi->CR1 = cr1 | SPI_CR1_SPE; + spip->spi->CR1 = cr1 | SPI_CR1_SPE | SPI_CR1_CSTART; +} + +static void spi_lld_wait_complete(SPIDriver *spip) { + + while ((spip->spi->CR1 & SPI_CR1_CSTART) != 0) { + } + spip->spi->IFCR = 0xFFFFFFFF; +} + +/** + * @brief Stopping the SPI transaction quick and dirty. + */ +static void spi_lld_stop_abort(SPIDriver *spip) { + + /* Stopping DMAs and waiting for FIFOs to be empty.*/ +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamDisable(spip->tx.bdma); + bdmaStreamDisable(spip->rx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamDisable(spip->tx.dma); + dmaStreamDisable(spip->rx.dma); + } +#endif + + /* Resetting SPI, this will stop it for sure and leave it + in a clean state.*/ + if (false) { + } + +#if STM32_SPI_USE_SPI1 + else if (&SPID1 == spip) { + rccResetSPI1(); + } +#endif + +#if STM32_SPI_USE_SPI2 + else if (&SPID2 == spip) { + rccResetSPI2(); + } +#endif + +#if STM32_SPI_USE_SPI3 + else if (&SPID3 == spip) { + rccResetSPI3(); + } +#endif + +#if STM32_SPI_USE_SPI4 + else if (&SPID4 == spip) { + rccResetSPI4(); + } +#endif + +#if STM32_SPI_USE_SPI5 + else if (&SPID5 == spip) { + rccResetSPI5(); + } +#endif + +#if STM32_SPI_USE_SPI6 + else if (&SPID6 == spip) { + rccResetSPI6(); + } +#endif + + else { + osalDbgAssert(false, "invalid SPI instance"); + } + + /* Reconfiguring SPI.*/ + spip->spi->CFG1 = (spip->config->cfg1 & ~SPI_CFG1_FTHLV_Msk) | + SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN; + spip->spi->CFG2 = (spip->config->cfg2 | SPI_CFG2_MASTER | SPI_CFG2_SSOE) & + ~SPI_CFG2_COMM_Msk; + spip->spi->IER = SPI_IER_OVRIE; +} + +/** + * @brief Stopping the SPI transaction in the nicest possible way. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static msg_t spi_lld_stop_nicely(SPIDriver *spip) { + + /* Stopping DMAs and waiting for FIFOs to be empty.*/ +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamDisable(spip->tx.bdma); + + /* Waiting for the RX FIFO to become empty.*/ + while ((spip->spi->SR & (SPI_SR_RXWNE | SPI_SR_RXPLVL)) != 0U) { + /* Waiting.*/ + } + + bdmaStreamDisable(spip->rx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamDisable(spip->tx.dma); + + /* Waiting for the RX FIFO to become empty.*/ + while ((spip->spi->SR & (SPI_SR_RXWNE | SPI_SR_RXPLVL)) != 0U) { + /* Waiting.*/ + } + + dmaStreamDisable(spip->rx.dma); + } +#endif + + /* Stopping SPI.*/ + spip->spi->CR1 |= SPI_CR1_CSUSP; + spi_lld_wait_complete(spip); + spip->spi->CR1 &= ~SPI_CR1_SPE; + + return HAL_RET_SUCCESS; +} + +#if defined(STM32_SPI_BDMA_REQUIRED) +/** + * @brief Shared DMA end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_bdma_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & STM32_BDMA_ISR_TEIF) != 0U) { +#if defined(STM32_SPI_DMA_ERROR_HOOK) + STM32_SPI_DMA_ERROR_HOOK(spip); +#endif + + /* Aborting the transfer.*/ + spi_lld_stop_abort(spip); + + /* Reporting the failure.*/ + __spi_isr_error_code(spip, HAL_RET_HW_FAILURE); + } + + if (spip->config->circular) { + if ((flags & STM32_BDMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + __spi_isr_half_code(spip); + } + if ((flags & STM32_BDMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + __spi_isr_full_code(spip); + } + } + else { + /* Stopping the transfer.*/ + (void) spi_lld_stop_nicely(spip); + + /* Operation finished interrupt.*/ + __spi_isr_complete_code(spip); + } +} + +/** + * @brief Shared BDMA end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_bdma_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & STM32_BDMA_ISR_TEIF) != 0) { +#if defined(STM32_SPI_DMA_ERROR_HOOK) + STM32_SPI_DMA_ERROR_HOOK(spip); +#endif + + /* Aborting the transfer.*/ + spi_lld_stop_abort(spip); + + /* Reporting the failure.*/ + __spi_isr_error_code(spip, HAL_RET_HW_FAILURE); + } +} +#endif /* defined(STM32_SPI_BDMA_REQUIRED) */ + +#if defined(STM32_SPI_DMA_REQUIRED) +/** + * @brief Shared DMA end-of-rx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_dma_rx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) { +#if defined(STM32_SPI_DMA_ERROR_HOOK) + STM32_SPI_DMA_ERROR_HOOK(spip); +#endif + + /* Aborting the transfer.*/ + spi_lld_stop_abort(spip); + + /* Reporting the failure.*/ + __spi_isr_error_code(spip, HAL_RET_HW_FAILURE); + } + + if (spip->config->circular) { + if ((flags & STM32_DMA_ISR_HTIF) != 0U) { + /* Half buffer interrupt.*/ + __spi_isr_half_code(spip); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0U) { + /* End buffer interrupt.*/ + __spi_isr_full_code(spip); + } + } + else { + /* Stopping the transfer.*/ + (void) spi_lld_stop_nicely(spip); + + /* Operation finished interrupt.*/ + __spi_isr_complete_code(spip); + } +} + +/** + * @brief Shared DMA end-of-tx service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void spi_lld_serve_dma_tx_interrupt(SPIDriver *spip, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { +#if defined(STM32_SPI_DMA_ERROR_HOOK) + STM32_SPI_DMA_ERROR_HOOK(spip); +#endif + + /* Aborting the transfer.*/ + spi_lld_stop_abort(spip); + + /* Reporting the failure.*/ + __spi_isr_error_code(spip, HAL_RET_HW_FAILURE); + } +} +#endif /* defined(STM32_SPI_DMA_REQUIRED) */ + +/** + * @brief Shared SPI service routine. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void spi_lld_serve_interrupt(SPIDriver *spip) { + uint32_t sr; + + sr = spip->spi->SR & spip->spi->IER; + spip->spi->IFCR = sr; + + if ((sr & SPI_SR_OVR) != 0U) { + /* TODO: fault notification.*/ + } +} + +/** + * @brief DMA streams allocation. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] rxstream stream to be allocated for RX + * @param[in] txstream stream to be allocated for TX + * @param[in] priority streams IRQ priority + * @return The operation status. + */ +static msg_t spi_lld_get_dma(SPIDriver *spip, uint32_t rxstream, + uint32_t txstream, uint32_t priority){ + + spip->rx.dma = dmaStreamAllocI(rxstream, priority, + (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt, + (void *)spip); + if (spip->rx.dma == NULL) { + return HAL_RET_NO_RESOURCE; + } + + spip->tx.dma = dmaStreamAllocI(txstream, priority, + (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt, + (void *)spip); + if (spip->tx.dma == NULL) { + dmaStreamFreeI(spip->rx.dma); + return HAL_RET_NO_RESOURCE; + } + + return HAL_RET_SUCCESS; +} + +/** + * @brief BDMA streams allocation. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] rxstream stream to be allocated for RX + * @param[in] txstream stream to be allocated for TX + * @param[in] priority streams IRQ priority + * @return The operation status. + */ +static msg_t spi_lld_get_bdma(SPIDriver *spip, uint32_t rxstream, + uint32_t txstream, uint32_t priority){ + + spip->rx.bdma = bdmaStreamAllocI(rxstream, priority, + (stm32_bdmaisr_t)spi_lld_serve_bdma_rx_interrupt, + (void *)spip); + if (spip->rx.bdma == NULL) { + return HAL_RET_NO_RESOURCE; + } + + spip->tx.bdma = bdmaStreamAllocI(txstream, priority, + (stm32_bdmaisr_t)spi_lld_serve_bdma_tx_interrupt, + (void *)spip); + if (spip->tx.bdma == NULL) { + bdmaStreamFreeI(spip->rx.bdma); + return HAL_RET_NO_RESOURCE; + } + + return HAL_RET_SUCCESS; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) +#if !defined(STM32_SPI1_SUPPRESS_ISR) +#if !defined(STM32_SPI1_HANDLER) +#error "STM32_SPI1_HANDLER not defined" +#endif +/** + * @brief SPI1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI1_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI1 */ + +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) +#if !defined(STM32_SPI2_SUPPRESS_ISR) +#if !defined(STM32_SPI2_HANDLER) +#error "STM32_SPI2_HANDLER not defined" +#endif +/** + * @brief SPI2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI2_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI2 */ + +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) +#if !defined(STM32_SPI3_SUPPRESS_ISR) +#if !defined(STM32_SPI3_HANDLER) +#error "STM32_SPI3_HANDLER not defined" +#endif +/** + * @brief SPI3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI3_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI3 */ + +#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__) +#if !defined(STM32_SPI4_SUPPRESS_ISR) +#if !defined(STM32_SPI4_HANDLER) +#error "STM32_SPI4_HANDLER not defined" +#endif +/** + * @brief SPI4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID4); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI4_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI4 */ + +#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__) +#if !defined(STM32_SPI5_SUPPRESS_ISR) +#if !defined(STM32_SPI5_HANDLER) +#error "STM32_SPI5_HANDLER not defined" +#endif +/** + * @brief SPI5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID5); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI5_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI5 */ + +#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__) +#if !defined(STM32_SPI6_SUPPRESS_ISR) +#if !defined(STM32_SPI6_HANDLER) +#error "STM32_SPI6_HANDLER not defined" +#endif +/** + * @brief SPI6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SPI6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + spi_lld_serve_interrupt(&SPID6); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_SPI6_SUPPRESS_ISR) */ +#endif /* STM32_SPI_USE_SPI6 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if STM32_SPI_USE_SPI1 + spiObjectInit(&SPID1); + SPID1.spi = SPI1; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID1.is_bdma = false; +#endif + SPID1.rx.dma = NULL; + SPID1.tx.dma = NULL; + SPID1.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID1.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI1_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI1_NUMBER, STM32_SPI_SPI1_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI2 + spiObjectInit(&SPID2); + SPID2.spi = SPI2; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID2.is_bdma = false; +#endif + SPID2.rx.dma = NULL; + SPID2.tx.dma = NULL; + SPID2.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID2.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI2_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI2_NUMBER, STM32_SPI_SPI2_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI3 + spiObjectInit(&SPID3); + SPID3.spi = SPI3; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID3.is_bdma = false; +#endif + SPID3.rx.dma = NULL; + SPID3.tx.dma = NULL; + SPID3.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID3.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI3_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI3_NUMBER, STM32_SPI_SPI3_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI4 + spiObjectInit(&SPID4); + SPID4.spi = SPI4; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID4.is_bdma = false; +#endif + SPID4.rx.dma = NULL; + SPID4.tx.dma = NULL; + SPID4.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID4.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI4_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI4_NUMBER, STM32_SPI_SPI4_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI5 + spiObjectInit(&SPID5); + SPID5.spi = SPI5; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID5.is_bdma = false; +#endif + SPID5.rx.dma = NULL; + SPID5.tx.dma = NULL; + SPID5.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; + SPID5.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#if !defined(STM32_SPI5_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI5_NUMBER, STM32_SPI_SPI5_IRQ_PRIORITY); +#endif +#endif + +#if STM32_SPI_USE_SPI6 + spiObjectInit(&SPID6); + SPID6.spi = SPI6; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + SPID6.is_bdma = true; +#endif + SPID6.rx.bdma = NULL; + SPID6.tx.bdma = NULL; + SPID6.rxdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_P2M | + STM32_BDMA_CR_TCIE | + STM32_BDMA_CR_TEIE; + SPID6.txdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) | + STM32_BDMA_CR_DIR_M2P | + STM32_BDMA_CR_TEIE; +#if !defined(STM32_SPI6_SUPPRESS_ISR) + nvicEnableVector(STM32_SPI6_NUMBER, STM32_SPI_SPI6_IRQ_PRIORITY); +#endif +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_start(SPIDriver *spip) { + uint32_t dsize; + msg_t msg; + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (spip->state == SPI_STOP) { + if (false) { + } + +#if STM32_SPI_USE_SPI1 + else if (&SPID1 == spip) { + msg = spi_lld_get_dma(spip, + STM32_SPI_SPI1_RX_DMA_STREAM, + STM32_SPI_SPI1_TX_DMA_STREAM, + STM32_SPI_SPI1_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI1(true); + rccResetSPI1(); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI1_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI1_TX); + } +#endif + +#if STM32_SPI_USE_SPI2 + else if (&SPID2 == spip) { + msg = spi_lld_get_dma(spip, + STM32_SPI_SPI2_RX_DMA_STREAM, + STM32_SPI_SPI2_TX_DMA_STREAM, + STM32_SPI_SPI2_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI2(true); + rccResetSPI2(); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI2_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI2_TX); + } +#endif + +#if STM32_SPI_USE_SPI3 + else if (&SPID3 == spip) { + msg = spi_lld_get_dma(spip, + STM32_SPI_SPI3_RX_DMA_STREAM, + STM32_SPI_SPI3_TX_DMA_STREAM, + STM32_SPI_SPI3_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI3(true); + rccResetSPI3(); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI3_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI3_TX); + } +#endif + +#if STM32_SPI_USE_SPI4 + else if (&SPID4 == spip) { + msg = spi_lld_get_dma(spip, + STM32_SPI_SPI4_RX_DMA_STREAM, + STM32_SPI_SPI4_TX_DMA_STREAM, + STM32_SPI_SPI4_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI4(true); + rccResetSPI4(); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI4_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI4_TX); + } +#endif + +#if STM32_SPI_USE_SPI5 + else if (&SPID5 == spip) { + msg = spi_lld_get_dma(spip, + STM32_SPI_SPI5_RX_DMA_STREAM, + STM32_SPI_SPI5_TX_DMA_STREAM, + STM32_SPI_SPI5_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI5(true); + rccResetSPI5(); + dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI5_RX); + dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI5_TX); + } +#endif + +#if STM32_SPI_USE_SPI6 + else if (&SPID6 == spip) { + rccEnableSPI6(true); + msg = spi_lld_get_bdma(spip, + STM32_SPI_SPI6_RX_BDMA_STREAM, + STM32_SPI_SPI6_TX_BDMA_STREAM, + STM32_SPI_SPI6_IRQ_PRIORITY); + if (msg != HAL_RET_SUCCESS) { + return msg; + } + rccEnableSPI6(true); + rccResetSPI6(); + bdmaSetRequestSource(spip->rx.bdma, STM32_DMAMUX2_SPI6_RX); + bdmaSetRequestSource(spip->tx.bdma, STM32_DMAMUX2_SPI6_TX); + } +#endif + + else { + osalDbgAssert(false, "invalid SPI instance"); + } + + /* DMA setup.*/ +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetPeripheral(spip->rx.bdma, &spip->spi->RXDR); + bdmaStreamSetPeripheral(spip->tx.bdma, &spip->spi->TXDR); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetPeripheral(spip->rx.dma, &spip->spi->RXDR); + dmaStreamSetPeripheral(spip->tx.dma, &spip->spi->TXDR); + } +#endif + } + + /* Configuration-specific DMA setup.*/ + dsize = (spip->config->cfg1 & SPI_CFG1_DSIZE_Msk) + 1U; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD; + spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) | + STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD; + } + if (spip->config->circular) { + spip->rxdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + spip->txdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + spip->txdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE); + } + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; + spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | + STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; + } + if (spip->config->circular) { + spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + else { + spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); + } + } +#endif + + /* SPI setup.*/ + spip->spi->CR1 = 0U; + spip->spi->CR2 = 0U; + spip->spi->CFG1 = (spip->config->cfg1 & ~SPI_CFG1_FTHLV_Msk) | + SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN; + spip->spi->CFG2 = (spip->config->cfg2 | SPI_CFG2_MASTER | SPI_CFG2_SSOE) & + ~SPI_CFG2_COMM_Msk; + spip->spi->IER = SPI_IER_OVRIE; + spip->spi->IFCR = 0xFFFFFFFFU; + + return HAL_RET_SUCCESS; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + /* If in ready state then disables the SPI clock.*/ + if (spip->state == SPI_READY) { + + /* SPI disable.*/ + spip->spi->CR1 &= ~SPI_CR1_SPE; + spip->spi->CR1 = 0U; + spip->spi->CR2 = 0U; + spip->spi->CFG1 = 0U; + spip->spi->CFG2 = 0U; + spip->spi->IER = 0U; +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamFreeI(spip->rx.bdma); + bdmaStreamFreeI(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamFreeI(spip->rx.dma); + dmaStreamFreeI(spip->tx.dma); + } +#endif + + /* Clock shutdown.*/ + if (false) { + } + +#if STM32_SPI_USE_SPI1 + else if (&SPID1 == spip) { + rccDisableSPI1(); + } +#endif + +#if STM32_SPI_USE_SPI2 + else if (&SPID2 == spip) { + rccDisableSPI2(); + } +#endif + +#if STM32_SPI_USE_SPI3 + else if (&SPID3 == spip) { + rccDisableSPI3(); + } +#endif + +#if STM32_SPI_USE_SPI4 + else if (&SPID4 == spip) { + rccDisableSPI4(); + } +#endif + +#if STM32_SPI_USE_SPI5 + else if (&SPID5 == spip) { + rccDisableSPI5(); + } +#endif + +#if STM32_SPI_USE_SPI6 + else if (&SPID6 == spip) { + rccDisableSPI6(); + } +#endif + + else { + osalDbgAssert(false, "invalid SPI instance"); + } + } +} + +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + /* No implementation on STM32.*/ +} +#endif + +/** + * @brief Ignores data on the SPI bus. + * @details This asynchronous function starts the transmission of a series of + * idle words on the SPI bus and ignores the received data. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_ignore(SPIDriver *spip, size_t n) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, &spip->rxsink); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode); + + bdmaStreamSetMemory(spip->tx.bdma, &spip->txsource); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, &spip->rxsink); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode); + + dmaStreamSetMemory0(spip->tx.dma, &spip->txsource); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spi_lld_start_master(spip); + + return HAL_RET_SUCCESS; +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamSetMemory(spip->tx.bdma, txbuf); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, rxbuf); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->tx.dma, txbuf); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spi_lld_start_master(spip); + + return HAL_RET_SUCCESS; +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, &spip->rxsink); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode); + + bdmaStreamSetMemory(spip->tx.bdma, txbuf); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, &spip->rxsink); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode); + + dmaStreamSetMemory0(spip->tx.dma, txbuf); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spi_lld_start_master(spip); + + return HAL_RET_SUCCESS; +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @note The buffers are organized as uint8_t arrays for data sizes below or + * equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + osalDbgAssert(n < 65536, "unsupported DMA transfer size"); + + spi_lld_wait_complete(spip); + +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + bdmaStreamSetMemory(spip->rx.bdma, rxbuf); + bdmaStreamSetTransactionSize(spip->rx.bdma, n); + bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC); + + bdmaStreamSetMemory(spip->tx.bdma, &spip->txsource); + bdmaStreamSetTransactionSize(spip->tx.bdma, n); + bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode); + + bdmaStreamEnable(spip->rx.bdma); + bdmaStreamEnable(spip->tx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + dmaStreamSetMemory0(spip->rx.dma, rxbuf); + dmaStreamSetTransactionSize(spip->rx.dma, n); + dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC); + + dmaStreamSetMemory0(spip->tx.dma, &spip->txsource); + dmaStreamSetTransactionSize(spip->tx.dma, n); + dmaStreamSetMode(spip->tx.dma, spip->txdmamode); + + dmaStreamEnable(spip->rx.dma); + dmaStreamEnable(spip->tx.dma); + } +#endif + + spi_lld_start_master(spip); + + return HAL_RET_SUCCESS; +} + +/** + * @brief Aborts the ongoing SPI operation, if any. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[out sizep pointer to the counter of frames not yet transferred + * or @p NULL + * @return The operation status. + * + * @notapi + */ +msg_t spi_lld_stop_transfer(SPIDriver *spip, size_t *sizep) { + msg_t msg; + + /* Stopping everything.*/ + msg = spi_lld_stop_nicely(spip); + + if (sizep != NULL) { +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + if (spip->is_bdma) +#endif +#if defined(STM32_SPI_BDMA_REQUIRED) + { + *sizep = bdmaStreamGetTransactionSize(spip->rx.bdma); + } +#endif +#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) + else +#endif +#if defined(STM32_SPI_DMA_REQUIRED) + { + *sizep = dmaStreamGetTransactionSize(spip->rx.dma); + } +#endif + } + + return msg; +} + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + * + * @notapi + */ +uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame) { + uint32_t dsize = (spip->spi->CFG1 & SPI_CFG1_DSIZE_Msk) + 1U; + uint32_t rxframe; + + spi_lld_wait_complete(spip); + + spip->spi->CR1 |= SPI_CR1_CSTART; + + /* wait for room in TX FIFO.*/ + while ((spip->spi->SR & SPI_SR_TXP) == 0U) + ; + + /* Data register must be accessed with the appropriate data size. + Byte size access (uint8_t *) for transactions that are <= 8-bit etc.*/ + if (dsize <= 8U) { + /* Frame width is between 4 and 8 bits.*/ + volatile uint8_t *txdrp8 = (volatile uint8_t *)&spip->spi->TXDR; + volatile uint8_t *rxdrp8 = (volatile uint8_t *)&spip->spi->RXDR; + *txdrp8 = (uint8_t)frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = (uint32_t)*rxdrp8; + } + else if (dsize <= 16U) { + /* Frame width is between 9 and 16 bits.*/ + volatile uint16_t *txdrp16 = (volatile uint16_t *)&spip->spi->TXDR; + volatile uint16_t *rxdrp16 = (volatile uint16_t *)&spip->spi->RXDR; + *txdrp16 = (uint16_t)frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = (uint32_t)*rxdrp16; + } + else { + /* Frame width is between 16 and 32 bits.*/ + spip->spi->TXDR = frame; + while ((spip->spi->SR & SPI_SR_RXP) == 0U) + ; + rxframe = spip->spi->RXDR; + } + + spip->spi->CR1 |= SPI_CR1_CSUSP; + + return rxframe; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.h b/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.h new file mode 100644 index 000000000..bf0efce57 --- /dev/null +++ b/os/hal/ports/STM32/LLD/SPIv3/hal_spi_v2_lld.h @@ -0,0 +1,605 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file SPIv3/hal_spi_v2_lld.h + * @brief STM32 SPI (v2) subsystem low level driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Circular mode support flag. + */ +#define SPI_SUPPORTS_CIRCULAR TRUE + +/** + * @brief Slave mode support flag. + */ +#define SPI_SUPPORTS_SLAVE_MODE FALSE + +/** + * @name Register helpers not found in ST headers + * @{ + */ +#define SPI_CFG1_MBR_VALUE(n) ((n) << SPI_CFG1_MBR_Pos) +#define SPI_CFG1_MBR_DIV2 SPI_CFG1_MBR_VALUE(0) +#define SPI_CFG1_MBR_DIV4 SPI_CFG1_MBR_VALUE(1) +#define SPI_CFG1_MBR_DIV8 SPI_CFG1_MBR_VALUE(2) +#define SPI_CFG1_MBR_DIV16 SPI_CFG1_MBR_VALUE(3) +#define SPI_CFG1_MBR_DIV32 SPI_CFG1_MBR_VALUE(4) +#define SPI_CFG1_MBR_DIV64 SPI_CFG1_MBR_VALUE(5) +#define SPI_CFG1_MBR_DIV128 SPI_CFG1_MBR_VALUE(6) +#define SPI_CFG1_MBR_DIV256 SPI_CFG1_MBR_VALUE(7) +#define SPI_CFG1_CRCSIZE_VALUE(n) ((n) << SPI_CFG1_CRCSIZE_Pos) +#define SPI_CFG1_UDRDET_VALUE(n) ((n) << SPI_CFG1_UDRDET_Pos) +#define SPI_CFG1_UDRCFG_VALUE(n) ((n) << SPI_CFG1_UDRCFG_Pos) +#define SPI_CFG1_FTHLV_VALUE(n) ((n) << SPI_CFG1_FTHLV_Pos) +#define SPI_CFG1_DSIZE_VALUE(n) ((n) << SPI_CFG1_DSIZE_Pos) + +#define SPI_CFG2_SP_VALUE(n) ((n) << SPI_CFG2_SP_Pos) +#define SPI_CFG2_COMM_VALUE(n) ((n) << SPI_CFG2_COMM_Pos) +#define SPI_CFG2_COMM_FULL_DUPLEX SPI_CFG2_COMM_VALUE(0) +#define SPI_CFG2_COMM_TRANSMITTER SPI_CFG2_COMM_VALUE(1) +#define SPI_CFG2_COMM_RECEIVER SPI_CFG2_COMM_VALUE(2) +#define SPI_CFG2_COMM_HALF_DUPLEX SPI_CFG2_COMM_VALUE(3) +#define SPI_CFG2_MIDI_VALUE(n) ((n) << SPI_CFG2_MIDI_Pos) +#define SPI_CFG2_MSSI_VALUE(n) ((n) << SPI_CFG2_MSSI_Pos) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for SPI1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI1 FALSE +#endif + +/** + * @brief SPI2 driver enable switch. + * @details If set to @p TRUE the support for SPI2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI2 FALSE +#endif + +/** + * @brief SPI3 driver enable switch. + * @details If set to @p TRUE the support for SPI3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI3 FALSE +#endif + +/** + * @brief SPI4 driver enable switch. + * @details If set to @p TRUE the support for SPI4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI4 FALSE +#endif + +/** + * @brief SPI5 driver enable switch. + * @details If set to @p TRUE the support for SPI5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI5 FALSE +#endif + +/** + * @brief SPI6 driver enable switch. + * @details If set to @p TRUE the support for SPI6 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__) +#define STM32_SPI_USE_SPI6 FALSE +#endif + +/** + * @brief Filler pattern used when there is nothing to transmit. + */ +#if !defined(STM32_SPI_FILLER_PATTERN) || defined(__DOXYGEN__) +#define STM32_SPI_FILLER_PATTERN 0xFFFFFFFFU +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI2 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI3 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI4 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI5 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI6 interrupt priority level setting. + */ +#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_IRQ_PRIORITY 10 +#endif + +/** + * @brief SPI1 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI2 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI3 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI4 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI4_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI5 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI5_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI6 DMA priority (0..3|lowest..highest). + * @note The priority level is used for both the TX and RX DMA streams but + * because of the streams ordering the RX stream has always priority + * over the TX stream. + */ +#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SPI_SPI6_DMA_PRIORITY 1 +#endif + +/** + * @brief SPI DMA error hook. + */ +#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1 +#error "SPI1 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2 +#error "SPI2 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3 +#error "SPI3 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4 +#error "SPI4 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5 +#error "SPI5 not present in the selected device" +#endif + +#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6 +#error "SPI6 not present in the selected device" +#endif + +#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \ + !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI6" +#endif + +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI1_TX_DMA_STREAM)) +#error "SPI1 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI2_TX_DMA_STREAM)) +#error "SPI2 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI3_TX_DMA_STREAM)) +#error "SPI3 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI4_TX_DMA_STREAM)) +#error "SPI4 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \ + !defined(STM32_SPI_SPI5_TX_DMA_STREAM)) +#error "SPI5 DMA streams not defined" +#endif + +#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_BDMA_STREAM) || \ + !defined(STM32_SPI_SPI6_TX_BDMA_STREAM)) +#error "SPI6 BDMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA streams.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI1 RX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM) +#error "Invalid DMA stream assigned to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_RX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_TX_BDMA_STREAM) +#error "Invalid BDMA stream assigned to SPI6 TX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI1" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI2" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI3" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI4" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI5" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SPI6" +#endif + +#if STM32_SPI_USE_SPI1 || STM32_SPI_USE_SPI2 || STM32_SPI_USE_SPI3 || \ + STM32_SPI_USE_SPI4 || STM32_SPI_USE_SPI5 +#define STM32_SPI_DMA_REQUIRED +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif +#endif + +#if STM32_SPI_USE_SPI6 +#define STM32_SPI_BDMA_REQUIRED +#if !defined(STM32_BDMA_REQUIRED) +#define STM32_BDMA_REQUIRED +#endif +#endif + +#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD +#error "SPI_SELECT_MODE_LLD not supported by this driver" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +#if (defined(STM32_SPI_DMA_REQUIRED) && \ + defined(STM32_SPI_BDMA_REQUIRED)) || defined(__DOXYGEN__) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** DMA type for this instance.*/ \ + bool is_bdma; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* Receive BDMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + /* Transmit DMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode; \ + /* Sink for discarded data.*/ \ + uint32_t rxsink; \ + /* Source for default TX pattern.*/ \ + uint32_t txsource +#endif + +#if defined(STM32_SPI_DMA_REQUIRED) && !defined(STM32_SPI_BDMA_REQUIRED) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_dma_stream_t *dma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode; \ + /* Sink for discarded data.*/ \ + uint32_t rxsink; \ + /* Source for default TX pattern.*/ \ + uint32_t txsource +#endif + +#if !defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED) +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + SPI_TypeDef *spi; \ + /** Union of the RX DMA streams.*/ \ + union { \ + /* Receive BDMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } rx; \ + /* Union of the TX DMA streams.*/ \ + union { \ + /* Transmit DMA stream.*/ \ + const stm32_bdma_stream_t *bdma; \ + } tx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode; \ + /* Sink for discarded data.*/ \ + uint32_t rxsink; \ + /* Source for default TX pattern.*/ \ + uint32_t txsource +#endif + +/** + * @brief Low level fields of the SPI configuration structure. + */ +#define spi_lld_config_fields \ + /* SPI CFG1 register initialization data.*/ \ + uint32_t cfg1; \ + /* SPI CFG2 register initialization data.*/ \ + uint32_t cfg2 + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__) +extern SPIDriver SPID3; +#endif + +#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__) +extern SPIDriver SPID4; +#endif + +#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__) +extern SPIDriver SPID5; +#endif + +#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__) +extern SPIDriver SPID6; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + msg_t spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); +#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__) + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); +#endif + msg_t spi_lld_ignore(SPIDriver *spip, size_t n); + msg_t spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + msg_t spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); + msg_t spi_lld_stop_transfer(SPIDriver *spip, size_t *sizep); + uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/STM32/STM32H7xx/hal_lld.h b/os/hal/ports/STM32/STM32H7xx/hal_lld.h index aec320a75..8fd193c66 100644 --- a/os/hal/ports/STM32/STM32H7xx/hal_lld.h +++ b/os/hal/ports/STM32/STM32H7xx/hal_lld.h @@ -43,6 +43,11 @@ /* Driver constants. */ /*===========================================================================*/ +/** + * @brief Requires use of SPIv2 driver model. + */ +#define HAL_LLD_SELECT_SPI_V2 TRUE + /** * @name Platform identification macros * @{ diff --git a/os/hal/ports/STM32/STM32H7xx/platform.mk b/os/hal/ports/STM32/STM32H7xx/platform.mk index 9f80dff35..3fc921dbe 100644 --- a/os/hal/ports/STM32/STM32H7xx/platform.mk +++ b/os/hal/ports/STM32/STM32H7xx/platform.mk @@ -39,7 +39,7 @@ include $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk -include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/driver_v2.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/SYSTICKv1/driver.mk diff --git a/testhal/STM32/multi/SPI/cfg/stm32h743_nucleo144/portab.c b/testhal/STM32/multi/SPI/cfg/stm32h743_nucleo144/portab.c index 86f9d0948..b01382d34 100644 --- a/testhal/STM32/multi/SPI/cfg/stm32h743_nucleo144/portab.c +++ b/testhal/STM32/multi/SPI/cfg/stm32h743_nucleo144/portab.c @@ -35,41 +35,45 @@ /*===========================================================================*/ void spi_circular_cb(SPIDriver *spip); +void spi_error_cb(SPIDriver *spip); /* * Circular SPI configuration (25MHz, CPHA=0, CPOL=0, MSb first). */ const SPIConfig c_spicfg = { - true, - spi_circular_cb, - GPIOD, - 14, - SPI_CFG1_MBR_DIV8 | SPI_CFG1_DSIZE_VALUE(7), - 0 + .circular = true, + .data_cb = spi_circular_cb, + .error_cb = spi_error_cb, + .ssport = GPIOD, + .sspad = 14U, + .cfg1 = SPI_CFG1_MBR_DIV8 | SPI_CFG1_DSIZE_VALUE(7), + .cfg2 = 0U }; /* * Maximum speed SPI configuration (25MHz, CPHA=0, CPOL=0, MSb first). */ const SPIConfig hs_spicfg = { - false, - NULL, - GPIOD, - 14, - SPI_CFG1_MBR_DIV8 | SPI_CFG1_DSIZE_VALUE(7), - 0 + .circular = false, + .data_cb = NULL, + .error_cb = spi_error_cb, + .ssport = GPIOD, + .sspad = 14U, + .cfg1 = SPI_CFG1_MBR_DIV8 | SPI_CFG1_DSIZE_VALUE(7), + .cfg2 = 0U }; /* * Low speed SPI configuration (1.5625MHz, CPHA=0, CPOL=0, MSb first). */ const SPIConfig ls_spicfg = { - false, - NULL, - GPIOD, - 14, - SPI_CFG1_MBR_DIV128 | SPI_CFG1_DSIZE_VALUE(7), - 0 + .circular = false, + .data_cb = NULL, + .error_cb = spi_error_cb, + .ssport = GPIOD, + .sspad = 14U, + .cfg1 = SPI_CFG1_MBR_DIV128 | SPI_CFG1_DSIZE_VALUE(7), + .cfg2 = 0U }; /*===========================================================================*/