From 6483a05d1408d56b0d8a4c173c3d9967cfc03e74 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 14 May 2016 09:42:48 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9480 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/hal_qspi.h | 30 ++++++-- .../ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c | 68 ++++++++++++++---- .../ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h | 11 +++ os/hal/ports/STM32/STM32L4xx/stm32_registry.h | 3 +- os/hal/src/hal_qspi.c | 71 ++++++++++++++----- 5 files changed, 146 insertions(+), 37 deletions(-) diff --git a/os/hal/include/hal_qspi.h b/os/hal/include/hal_qspi.h index 498fedec7..0fe1e79fb 100644 --- a/os/hal/include/hal_qspi.h +++ b/os/hal/include/hal_qspi.h @@ -69,11 +69,6 @@ #define QSPI_CFG_DATA_MODE_ONE_LINE (1U << 24U) #define QSPI_CFG_DATA_MODE_TWO_LINES (2U << 24U) #define QSPI_CFG_DATA_MODE_FOUR_LINES (3U << 24U) -#define QSPI_CFG_F_MODE_MASK (3U << 26U) -#define QSPI_CFG_F_MODE_INDIRECT_WRITE (0U << 26U) -#define QSPI_CFG_F_MODE_INDIRECT_READ (1U << 26U) -#define QSPI_CFG_F_MODE_MEMORY_MAPPED (2U << 26U) -#define QSPI_CFG_F_MODE_FOUR_LINES (3U << 26U) #define QSPI_CFG_SIOO (1U << 28U) #define QSPI_CFG_DDRM (1U << 31U) /** @} */ @@ -141,6 +136,23 @@ typedef struct { * @name Macro Functions * @{ */ +/** + * @brief Sends a command without data phase. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * @param[in] cmd pointer to the command descriptor + * + * @iclass + */ +#define qspiCommandI(qspip, cmd) { \ + osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) == \ + QSPI_CFG_DATA_MODE_NONE, \ + "data mode specified"); \ + (qspip)->state = QSPI_ACTIVE; \ + qspi_lld_command(qspip, cmd, n, txbuf); \ +} + /** * @brief Sends data over the QSPI bus. * @details This asynchronous function starts a transmit operation. @@ -154,6 +166,9 @@ typedef struct { * @iclass */ #define qspiStartSendI(qspip, cmd, n, txbuf) { \ + osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) != \ + QSPI_CFG_DATA_MODE_NONE, \ + "data mode required"); \ (qspip)->state = QSPI_ACTIVE; \ qspi_lld_send(qspip, cmd, n, txbuf); \ } @@ -171,6 +186,9 @@ typedef struct { * @iclass */ #define qspiStartReceiveI(qspip, cmd, n, rxbuf) { \ + osalDbgAssert(((cmd)->cfg & QSPI_CFG_DATA_MODE_MASK) != \ + QSPI_CFG_DATA_MODE_NONE, \ + "data mode required"); \ (qspip)->state = QSPI_ACTIVE; \ qspi_lld_receive(qspip, cmd, n, rxbuf); \ } @@ -235,11 +253,13 @@ extern "C" { void qspiObjectInit(QSPIDriver *qspip); void qspiStart(QSPIDriver *qspip, const QSPIConfig *config); void qspiStop(QSPIDriver *qspip); + void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp); void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf); void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf); #if QSPI_USE_WAIT == TRUE + void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp); void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf); void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c index 4f4036a15..d395e0b43 100644 --- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c @@ -123,21 +123,29 @@ void qspi_lld_init(void) { */ void qspi_lld_start(QSPIDriver *qspip) { - /* If in stopped state then enables the QUADSPI and DMA clocks.*/ + /* If in stopped state then full initialization.*/ if (qspip->state == QSPI_STOP) { #if STM32_QSPI_USE_QUADSPI1 if (&QSPID1 == qspip) { - rccEnableQUADSPI1(FALSE); + bool b = dmaStreamAllocate(qspip->dma, + STM32_QSPI_QUADSPI1_IRQ_PRIORITY, + (stm32_dmaisr_t)qspi_lld_serve_dma_interrupt, + (void *)qspip); + osalDbgAssert(!b, "stream already allocated"); + rccEnableQUADSPI1(false); } #endif + + /* Common initializations.*/ + dmaStreamSetPeripheral(qspip->dma, &qspip->qspi->DR); } /* QSPI setup and enable.*/ -// spip->spi->CR1 = 0; -// spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR; -// spip->spi->CR2 = spip->config->cr2 | SPI_CR2_FRXTH | SPI_CR2_SSOE | -// SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN; -// spip->spi->CR1 |= SPI_CR1_SPE; + qspip->qspi->CR = ((STM32_QSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) | + QUADSPI_CR_TCIE | QUADSPI_CR_TEIE | QUADSPI_CR_DMAEN | + QUADSPI_CR_EN; + qspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF | + QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF; } /** @@ -153,10 +161,12 @@ void qspi_lld_stop(QSPIDriver *qspip) { if (qspip->state == QSPI_READY) { /* QSPI disable.*/ -// spip->spi->CR1 = 0; -// spip->spi->CR2 = 0; + qspip->qspi->CR = 0U; + + /* Releasing the DMA.*/ dmaStreamRelease(qspip->dma); + /* Stopping involved clocks.*/ #if STM32_QSPI_USE_QUADSPI1 if (&QSPID1 == qspip) { rccDisableQUADSPI1(FALSE); @@ -166,13 +176,32 @@ void qspi_lld_stop(QSPIDriver *qspip) { } /** - * @brief Sends data over the QSPI bus. - * @details This asynchronous function starts a transmit operation. + * @brief Sends a command without data phase. * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to send + * + * @notapi + */ +void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp) { + + qspip->qspi->CCR = cmdp->cfg; + if ((cmdp->cfg & QSPI_CFG_ALT_MODE_MASK) != QSPI_CFG_ALT_MODE_NONE) { + qspip->qspi->ABR = cmdp->alt; + } + if ((cmdp->cfg & QSPI_CFG_ADDR_MODE_MASK) != QSPI_CFG_ADDR_MODE_NONE) { + qspip->qspi->AR = cmdp->addr; + } +} + +/** + * @brief Sends a command with data over the QSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of bytes to send * @param[in] txbuf the pointer to the transmit buffer * * @notapi @@ -184,17 +213,21 @@ void qspi_lld_send(QSPIDriver *qspip, const qspi_command_t *cmdp, dmaStreamSetTransactionSize(qspip->dma, n); dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_M2P); + qspip->qspi->DLR = n - 1; + qspip->qspi->ABR = cmdp->alt; + qspip->qspi->CCR = cmdp->cfg; + qspip->qspi->AR = cmdp->addr; + dmaStreamEnable(qspip->dma); } /** - * @brief Receives data from the QSPI bus. - * @details This asynchronous function starts a receive operation. + * @brief Sends a command then receives data over the QSPI bus. * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to receive + * @param[in] n number of bytes to send * @param[out] rxbuf the pointer to the receive buffer * * @notapi @@ -206,6 +239,11 @@ void qspi_lld_receive(QSPIDriver *qspip, const qspi_command_t *cmdp, dmaStreamSetTransactionSize(qspip->dma, n); dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_P2M); + qspip->qspi->DLR = n - 1; + qspip->qspi->ABR = cmdp->alt; + qspip->qspi->CCR = cmdp->cfg | QUADSPI_CCR_FMODE_0; + qspip->qspi->AR = cmdp->addr; + dmaStreamEnable(qspip->dma); } diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h index 14dc01b2f..100572dfc 100644 --- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h @@ -48,6 +48,16 @@ #define STM32_QSPI_USE_QUADSPI1 FALSE #endif +/** + * @brief QUADSPI1 prescaler setting. + * @note This is the prescaler divider value 1..256. The maximum frequency + * varies depending on the STM32 model and operating conditions, + * find the details in the data sheet. + */ +#if !defined(STM32_QSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__) +#define STM32_QSPI_QUADSPI1_PRESCALER_VALUE 4 +#endif + /** * @brief QUADSPI1 interrupt priority level setting. */ @@ -199,6 +209,7 @@ extern "C" { void qspi_lld_init(void); void qspi_lld_start(QSPIDriver *qspip); void qspi_lld_stop(QSPIDriver *qspip); + void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp); void qspi_lld_send(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf); void qspi_lld_receive(QSPIDriver *qspip, const qspi_command_t *cmdp, diff --git a/os/hal/ports/STM32/STM32L4xx/stm32_registry.h b/os/hal/ports/STM32/STM32L4xx/stm32_registry.h index a1474a5c4..09de989ca 100644 --- a/os/hal/ports/STM32/STM32L4xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32L4xx/stm32_registry.h @@ -211,7 +211,8 @@ /* QUADSPI attributes.*/ #define STM32_HAS_QUADSPI1 TRUE -#define STM32_QUADSPI1_DMA_MSK (STM32_DMA_STREAM_ID_MSK(2, 7)) +#define STM32_QUADSPI1_DMA_MSK (STM32_DMA_STREAM_ID_MSK(1, 5) |\ + STM32_DMA_STREAM_ID_MSK(2, 7)) #define STM32_QUADSPI1_DMA_CHN 0x03000000 /* RTC attributes.*/ diff --git a/os/hal/src/hal_qspi.c b/os/hal/src/hal_qspi.c index 3070eeb66..6fdb0c3a0 100644 --- a/os/hal/src/hal_qspi.c +++ b/os/hal/src/hal_qspi.c @@ -123,13 +123,31 @@ void qspiStop(QSPIDriver *qspip) { } /** - * @brief Sends data over the QSPI bus. - * @details This asynchronous function starts a transmit operation. + * @brief Sends a command without data phase. * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to send or zero if no data phase + * + * @api + */ +void qspiStartCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) { + + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + + osalSysLock(); + osalDbgAssert(qspip->state == QSPI_READY, "not ready"); + qspiStartCommandI(qspip, cmd); + osalSysUnlock(); +} + +/** + * @brief Sends a command with data over the QSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of bytes to send * @param[in] txbuf the pointer to the transmit buffer * * @api @@ -138,7 +156,7 @@ void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); - osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL))); + osalDbgCheck((n > 0U) && (txbuf != NULL)); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); @@ -147,13 +165,12 @@ void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp, } /** - * @brief Receives data from the QSPI bus. - * @details This asynchronous function starts a receive operation. + * @brief Sends a command then receives data over the QSPI bus. * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to receive or zero if no data phase + * @param[in] n number of bytes to send * @param[out] rxbuf the pointer to the receive buffer * * @api @@ -162,7 +179,7 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); - osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL))); + osalDbgCheck((n > 0U) && (rxbuf != NULL)); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); @@ -172,8 +189,7 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, #if (QSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__) /** - * @brief Sends data over the QSPI bus. - * @details This synchronous function performs a transmit operation. + * @brief Sends a command without data phase. * @pre In order to use this function the option @p QSPI_USE_WAIT must be * enabled. * @pre In order to use this function the driver must have been configured @@ -181,7 +197,31 @@ void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to send or zero if no data phase + * + * @api + */ +void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) { + + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + + osalSysLock(); + osalDbgAssert(qspip->state == QSPI_READY, "not ready"); + osalDbgAssert(qspip->config->end_cb == NULL, "has callback"); + qspiStartCommandI(qspip, cmd, n, txbuf); + (void) osalThreadSuspendS(&qspip->thread); + osalSysUnlock(); +} + +/** + * @brief Sends a command with data over the QSPI bus. + * @pre In order to use this function the option @p QSPI_USE_WAIT must be + * enabled. + * @pre In order to use this function the driver must have been configured + * without callbacks (@p end_cb = @p NULL). + * + * @param[in] qspip pointer to the @p QSPIDriver object + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of bytes to send * @param[in] txbuf the pointer to the transmit buffer * * @api @@ -190,7 +230,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); - osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL))); + osalDbgCheck((n > 0U) && (txbuf != NULL)); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); @@ -201,8 +241,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, } /** - * @brief Receives data from the QSPI bus. - * @details This synchronous function performs a receive operation. + * @brief Sends a command then receives data over the QSPI bus. * @pre In order to use this function the option @p QSPI_USE_WAIT must be * enabled. * @pre In order to use this function the driver must have been configured @@ -210,7 +249,7 @@ void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, * * @param[in] qspip pointer to the @p QSPIDriver object * @param[in] cmd pointer to the command descriptor - * @param[in] n number of words to receive or zero if no data phase + * @param[in] n number of bytes to send * @param[out] rxbuf the pointer to the receive buffer * * @api @@ -219,7 +258,7 @@ void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf) { osalDbgCheck((qspip != NULL) && (cmdp != NULL)); - osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL))); + osalDbgCheck((n > 0U) && (rxbuf != NULL)); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready");