From fdcdb6e91669287bc043b117c357175b3fbaf048 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 13 May 2016 10:29:23 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9472 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/hal.mk | 4 + os/hal/include/hal.h | 78 ++++ os/hal/include/hal_qspi.h | 61 +-- os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c | 212 ++++++++++ os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h | 541 ++++++++++++++++++++++++ os/hal/src/hal_qspi.c | 48 ++- 6 files changed, 899 insertions(+), 45 deletions(-) create mode 100644 os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c create mode 100644 os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h (limited to 'os/hal') diff --git a/os/hal/hal.mk b/os/hal/hal.mk index 01e21c97e..a456cdd1d 100644 --- a/os/hal/hal.mk +++ b/os/hal/hal.mk @@ -44,6 +44,9 @@ endif ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) HALSRC += $(CHIBIOS)/os/hal/src/hal_pwm.c endif +ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) +HALSRC += $(CHIBIOS)/os/hal/src/hal_qspi.c +endif ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) HALSRC += $(CHIBIOS)/os/hal/src/hal_rtc.c endif @@ -85,6 +88,7 @@ HALSRC = $(CHIBIOS)/os/hal/src/hal.c \ $(CHIBIOS)/os/hal/src/hal_mmc_spi.c \ $(CHIBIOS)/os/hal/src/hal_pal.c \ $(CHIBIOS)/os/hal/src/hal_pwm.c \ + $(CHIBIOS)/os/hal/src/hal_qspi.c \ $(CHIBIOS)/os/hal/src/hal_rtc.c \ $(CHIBIOS)/os/hal/src/hal_sdc.c \ $(CHIBIOS)/os/hal/src/hal_serial.c \ diff --git a/os/hal/include/hal.h b/os/hal/include/hal.h index 876bd2b8a..e08aa707d 100644 --- a/os/hal/include/hal.h +++ b/os/hal/include/hal.h @@ -29,6 +29,83 @@ #include "board.h" #include "halconf.h" +/* Error checks on the configuration header file.*/ +#if !defined(HAL_USE_PAL) +#define HAL_USE_PAL FALSE +#endif + +#if !defined(HAL_USE_ADC) +#define HAL_USE_ADC FALSE +#endif + +#if !defined(HAL_USE_CAN) +#define HAL_USE_CAN FALSE +#endif + +#if !defined(HAL_USE_DAC) +#define HAL_USE_DAC FALSE +#endif + +#if !defined(HAL_USE_EXT) +#define HAL_USE_ETX FALSE +#endif + +#if !defined(HAL_USE_GPT) +#define HAL_USE_GPT FALSE +#endif + +#if !defined(HAL_USE_I2C) +#define HAL_USE_I2C FALSE +#endif + +#if !defined(HAL_USE_I2S) +#define HAL_USE_I2S FALSE +#endif + +#if !defined(HAL_USE_ICU) +#define HAL_USE_ICU FALSE +#endif + +#if !defined(HAL_USE_MAC) +#define HAL_USE_MAC FALSE +#endif + +#if !defined(HAL_USE_PWM) +#define HAL_USE_PWM FALSE +#endif + +#if !defined(HAL_USE_QSPI) +#define HAL_USE_QSPI FALSE +#endif + +#if !defined(HAL_USE_RTC) +#define HAL_USE_RTC FALSE +#endif + +#if !defined(HAL_USE_SERIAL) +#define HAL_USE_SERIAL FALSE +#endif + +#if !defined(HAL_USE_SDC) +#define HAL_USE_SDC FALSE +#endif + +#if !defined(HAL_USE_SPI) +#define HAL_USE_SPI FALSE +#endif + +#if !defined(HAL_USE_UART) +#define HAL_USE_UART FALSE +#endif + +#if !defined(HAL_USE_USB) +#define HAL_USE_USB FALSE +#endif + +#if !defined(HAL_USE_WDG) +#define HAL_USE_WDG FALSE +#endif + #include "hal_lld.h" /* Abstract interfaces.*/ @@ -54,6 +131,7 @@ #include "hal_icu.h" #include "hal_mac.h" #include "hal_pwm.h" +#include "hal_qspi.h" #include "hal_rtc.h" #include "hal_serial.h" #include "hal_sdc.h" diff --git a/os/hal/include/hal_qspi.h b/os/hal/include/hal_qspi.h index 391af6666..498fedec7 100644 --- a/os/hal/include/hal_qspi.h +++ b/os/hal/include/hal_qspi.h @@ -31,6 +31,10 @@ /* Driver constants. */ /*===========================================================================*/ +/** + * @name Transfer options + * @{ + */ #define QSPI_CFG_CMD_MASK (0xFFU << 0U) #define QSPI_CFG_CMD(n) ((n) << 0U) #define QSPI_CFG_CMD_MODE_MASK (3U << 8U) @@ -48,16 +52,16 @@ #define QSPI_CFG_ADDR_SIZE_16 (1U << 12U) #define QSPI_CFG_ADDR_SIZE_24 (2U << 12U) #define QSPI_CFG_ADDR_SIZE_32 (3U << 12U) -#define QSPI_CFG_AB_MODE_MASK (3U << 14U) -#define QSPI_CFG_AB_MODE_NONE (0U << 14U) -#define QSPI_CFG_AB_MODE_ONE_LINE (1U << 14U) -#define QSPI_CFG_AB_MODE_TWO_LINES (2U << 14U) -#define QSPI_CFG_AB_MODE_FOUR_LINES (3U << 14U) -#define QSPI_CFG_AB_SIZE_MASK (3U << 16U) -#define QSPI_CFG_AB_SIZE_8 (0U << 16U) -#define QSPI_CFG_AB_SIZE_16 (1U << 16U) -#define QSPI_CFG_AB_SIZE_24 (2U << 16U) -#define QSPI_CFG_AB_SIZE_32 (3U << 16U) +#define QSPI_CFG_ALT_MODE_MASK (3U << 14U) +#define QSPI_CFG_ALT_MODE_NONE (0U << 14U) +#define QSPI_CFG_ALT_MODE_ONE_LINE (1U << 14U) +#define QSPI_CFG_ALT_MODE_TWO_LINES (2U << 14U) +#define QSPI_CFG_ALT_MODE_FOUR_LINES (3U << 14U) +#define QSPI_CFG_ALT_SIZE_MASK (3U << 16U) +#define QSPI_CFG_ALT_SIZE_8 (0U << 16U) +#define QSPI_CFG_ALT_SIZE_16 (1U << 16U) +#define QSPI_CFG_ALT_SIZE_24 (2U << 16U) +#define QSPI_CFG_ALT_SIZE_32 (3U << 16U) #define QSPI_CFG_DUMMY_CYCLES_MASK (0x1FU << 18U) #define QSPI_CFG_DUMMY_CYCLES(n) ((n) << 18U) #define QSPI_CFG_DATA_MODE_MASK (3U << 24U) @@ -72,6 +76,7 @@ #define QSPI_CFG_F_MODE_FOUR_LINES (3U << 26U) #define QSPI_CFG_SIOO (1U << 28U) #define QSPI_CFG_DDRM (1U << 31U) +/** @} */ /*===========================================================================*/ /* Driver pre-compile time settings. */ @@ -118,15 +123,15 @@ typedef enum { } qspistate_t; /** - * @brief Type of a QSPI transaction descriptor. + * @brief Type of a QSPI command descriptor. */ typedef struct { uint32_t cfg; - uint32_t address; - uint32_t alternate; -} qspitransaction_t; + uint32_t addr; + uint32_t alt; +} qspi_command_t; -#include "hal_spi_lld.h" +#include "hal_qspi_lld.h" /*===========================================================================*/ /* Driver macros. */ @@ -142,14 +147,15 @@ typedef struct { * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object - * @param[in] n number of bytes to send + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of bytes to send or zero if no data phase * @param[in] txbuf the pointer to the transmit buffer * * @iclass */ -#define qspiStartSendI(qspip, n, txbuf) { \ +#define qspiStartSendI(qspip, cmd, n, txbuf) { \ (qspip)->state = QSPI_ACTIVE; \ - qspi_lld_send(qspip, n, txbuf); \ + qspi_lld_send(qspip, cmd, n, txbuf); \ } /** @@ -158,14 +164,15 @@ typedef struct { * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object - * @param[in] n number of bytes to receive + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of bytes to receive or zero if no data phase * @param[out] rxbuf the pointer to the receive buffer * * @iclass */ -#define qspiStartReceiveI(qspip, n, rxbuf) { \ +#define qspiStartReceiveI(qspip, cmd, n, rxbuf) { \ (qspip)->state = QSPI_ACTIVE; \ - qspi_lld_receive(qspip, n, rxbuf); \ + qspi_lld_receive(qspip, cmd, n, rxbuf); \ } /** @} */ @@ -228,11 +235,15 @@ extern "C" { void qspiObjectInit(QSPIDriver *qspip); void qspiStart(QSPIDriver *qspip, const QSPIConfig *config); void qspiStop(QSPIDriver *qspip); - void qspiStartSend(QSPIDriver *qspip, size_t n, const void *txbuf); - void qspiStartReceive(QSPIDriver *qspip, size_t n, void *rxbuf); + 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 qspiSend(QSPIDriver *qspip, size_t n, const void *txbuf); - void qspiReceive(QSPIDriver *qspip, size_t n, void *rxbuf); + 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, + size_t n, uint8_t *rxbuf); #endif #if QSPI_USE_MUTUAL_EXCLUSION == TRUE void qspiAcquireBus(QSPIDriver *qspip); diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c new file mode 100644 index 000000000..1b7eb5491 --- /dev/null +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c @@ -0,0 +1,212 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 QUADSPIv1/hal_qspi_lld.c + * @brief STM32 QSPI subsystem low level driver source. + * + * @addtogroup QSPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_QSPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define SPI1_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_QSPI_QUADSPI1_DMA_STREAM, \ + STM32_QUADSPI1_RX_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SPI1 driver identifier.*/ +#if STM32_QSPI_USE_QUADSPI1 || defined(__DOXYGEN__) +SPIDriver QSPID1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared service routine. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void qspi_lld_serve_dma_interrupt(QSPIDriver *qspip, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_QSPI_DMA_ERROR_HOOK) + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { + STM32_QSPI_DMA_ERROR_HOOK(qspip); + } +#else + (void)flags; +#endif +} + +/** + * @brief Shared service routine. + * + * @param[in] qspip pointer to the @p QSPIDriver object + */ +static void qspi_lld_serve_interrupt(QSPIDriver *qspip) { + + /* Stop everything.*/ + dmaStreamDisable(qspip->dma); + + /* Portable QSPI ISR code defined in the high level driver, note, it is + a macro.*/ + _qspi_isr_code(qspip); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void qspi_lld_init(void) { + +#if STM32_QSPI_USE_QUADSPI1 + qspiObjectInit(&QSPID1); + QSPID1.spi = SPI1; + QSPID1.dma = STM32_DMA_STREAM(STM32_QSPI_QUADSPI1_DMA_STREAM); + QSPID1.dmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_QSPI_QUADSPI1_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_BYTE | + STM32_DMA_CR_MSIZE_BYTE | + STM32_DMA_CR_MINC | + STM32_DMA_CR_DMEIE | + STM32_DMA_CR_TEIE; +#endif +} + +/** + * @brief Configures and activates the QSPI peripheral. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * + * @notapi + */ +void qspi_lld_start(QSPIDriver *qspip) { + uint32_t ds; + + /* If in stopped state then enables the SPI and DMA clocks.*/ + if (qspip->state == QSPI_STOP) { +#if STM32_SPI_USE_SPI1 + if (&SPID1 == qspip) { + rccEnableQUADSPI1(FALSE); + } +#endif + + /* 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; +} + +/** + * @brief Deactivates the QSPI peripheral. + * + * @param[in] qspip pointer to the @p QSPIDriver object + * + * @notapi + */ +void qspi_lld_stop(QSPIDriver *qspip) { + + /* If in ready state then disables the SPI clock.*/ + if (qspip->state == QSPI_READY) { + + /* QSPI disable.*/ +// spip->spi->CR1 = 0; +// spip->spi->CR2 = 0; + dmaStreamRelease(qspip->dma); + +#if STM32_QSPI_USE_QUADSPI1 + if (&QSPID1 == qspip) + rccDisableQUADSPI1(FALSE); +#endif + } +} + +/** + * @brief Sends data over the QSPI bus. + * @details This asynchronous function starts a transmit operation. + * @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 + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void qspi_lld_send(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + + dmaStreamSetMemory0(qspip->dma, txbuf); + dmaStreamSetTransactionSize(qspip->dma, n); + dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_M2P); + + dmaStreamEnable(qspip->dma); +} + +/** + * @brief Receives data from the QSPI bus. + * @details This asynchronous function starts a receive operation. + * @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[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void qspi_lld_receive(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + + dmaStreamSetMemory0(qspip->dma, rxbuf); + dmaStreamSetTransactionSize(qspip->dma, n); + dmaStreamSetMode(qspip->dma, qspip->dmamode | STM32_DMA_CR_DIR_P2M); + + dmaStreamEnable(qspip->dmarx); +} + +#endif /* HAL_USE_QSPI */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h new file mode 100644 index 000000000..c3129a42f --- /dev/null +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h @@ -0,0 +1,541 @@ +/* + ChibiOS - Copyright (C) 2006..2016 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 QUADSPIv1/hal_qspi_lld.h + * @brief STM32 QSPI subsystem low level driver header. + * + * @addtogroup QSPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_QSPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* 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 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 + +#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 + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* 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_DMA_STREAM) || \ + !defined(STM32_SPI_SPI6_TX_DMA_STREAM)) +#error "SPI6 DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 RX" +#endif + +#if STM32_SPI_USE_SPI1 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI1 TX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 RX" +#endif + +#if STM32_SPI_USE_SPI2 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI2 TX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 RX" +#endif + +#if STM32_SPI_USE_SPI3 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI3 TX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_RX_DMA_STREAM, STM32_SPI4_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 RX" +#endif + +#if STM32_SPI_USE_SPI4 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_TX_DMA_STREAM, STM32_SPI4_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI4 TX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_RX_DMA_STREAM, STM32_SPI5_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 RX" +#endif + +#if STM32_SPI_USE_SPI5 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_TX_DMA_STREAM, STM32_SPI5_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI5 TX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_RX_DMA_STREAM, STM32_SPI6_RX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 RX" +#endif + +#if STM32_SPI_USE_SPI6 && \ + !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_TX_DMA_STREAM, STM32_SPI6_TX_DMA_MSK) +#error "invalid DMA stream associated to SPI6 TX" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an SPI driver. + */ +typedef struct SPIDriver SPIDriver; + +/** + * @brief SPI notification callback type. + * + * @param[in] spip pointer to the @p SPIDriver object triggering the + * callback + */ +typedef void (*spicallback_t)(SPIDriver *spip); + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Operation complete callback or @p NULL. + */ + spicallback_t end_cb; + /* End of the mandatory fields.*/ + /** + * @brief The chip select line port. + */ + ioportid_t ssport; + /** + * @brief The chip select line pad number. + */ + uint16_t sspad; + /** + * @brief SPI CR1 register initialization data. + */ + uint16_t cr1; + /** + * @brief SPI CR2 register initialization data. + */ + uint16_t cr2; +} SPIConfig; + +/** + * @brief Structure representing an SPI driver. + */ +struct SPIDriver { + /** + * @brief Driver state. + */ + spistate_t state; + /** + * @brief Current configuration data. + */ + const SPIConfig *config; +#if SPI_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif /* SPI_USE_WAIT */ +#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* SPI_USE_MUTUAL_EXCLUSION */ +#if defined(SPI_DRIVER_EXT_FIELDS) + SPI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the SPIx registers block. + */ + SPI_TypeDef *spi; + /** + * @brief Receive DMA stream. + */ + const stm32_dma_stream_t *dmarx; + /** + * @brief Transmit DMA stream. + */ + const stm32_dma_stream_t *dmatx; + /** + * @brief RX DMA mode bit mask. + */ + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* 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 qspi_lld_init(void); + void qspi_lld_start(SPIDriver *spip); + void qspi_lld_stop(SPIDriver *spip); + void qspi_lld_send(SPIDriver *spip, size_t n, const uint8_t *txbuf); + void qspi_lld_receive(SPIDriver *spip, size_t n, uint8_t *rxbuf); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_QSPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ diff --git a/os/hal/src/hal_qspi.c b/os/hal/src/hal_qspi.c index e57694925..3070eeb66 100644 --- a/os/hal/src/hal_qspi.c +++ b/os/hal/src/hal_qspi.c @@ -128,18 +128,21 @@ void qspiStop(QSPIDriver *qspip) { * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object - * @param[in] n number of words to send + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of words to send or zero if no data phase * @param[in] txbuf the pointer to the transmit buffer * * @api */ -void qspiStartSend(QSPIDriver *qspip, size_t n, const void *txbuf) { +void qspiStartSend(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { - osalDbgCheck((qspip != NULL) && (n > 0U) && (txbuf != NULL)); + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL))); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); - qspiStartSendI(qspip, n, txbuf); + qspiStartSendI(qspip, cmd, n, txbuf); osalSysUnlock(); } @@ -149,18 +152,21 @@ void qspiStartSend(QSPIDriver *qspip, size_t n, const void *txbuf) { * @post At the end of the operation the configured callback is invoked. * * @param[in] qspip pointer to the @p QSPIDriver object - * @param[in] n number of words to receive + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of words to receive or zero if no data phase * @param[out] rxbuf the pointer to the receive buffer * * @api */ -void qspiStartReceive(QSPIDriver *qspip, size_t n, void *rxbuf) { +void qspiStartReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { - osalDbgCheck((qspip != NULL) && (n > 0U) && (rxbuf != NULL)); + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL))); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); - qspiStartReceiveI(qspip, n, rxbuf); + qspiStartReceiveI(qspip, cmd, n, rxbuf); osalSysUnlock(); } @@ -172,23 +178,24 @@ void qspiStartReceive(QSPIDriver *qspip, size_t n, void *rxbuf) { * enabled. * @pre In order to use this function the driver must have been configured * without callbacks (@p end_cb = @p NULL). - * @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] qspip pointer to the @p QSPIDriver object - * @param[in] n number of words to send + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of words to send or zero if no data phase * @param[in] txbuf the pointer to the transmit buffer * * @api */ -void qspiSend(QSPIDriver *qspip, size_t n, const void *txbuf) { +void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { - osalDbgCheck((qspip != NULL) && (n > 0U) && (txbuf != NULL)); + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n == 0U) || ((n > 0U) && (txbuf != NULL))); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); osalDbgAssert(qspip->config->end_cb == NULL, "has callback"); - qspiStartSendI(qspip, n, txbuf); + qspiStartSendI(qspip, cmd, n, txbuf); (void) osalThreadSuspendS(&qspip->thread); osalSysUnlock(); } @@ -200,23 +207,24 @@ void qspiSend(QSPIDriver *qspip, size_t n, const void *txbuf) { * enabled. * @pre In order to use this function the driver must have been configured * without callbacks (@p end_cb = @p NULL). - * @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] qspip pointer to the @p QSPIDriver object - * @param[in] n number of words to receive + * @param[in] cmd pointer to the command descriptor + * @param[in] n number of words to receive or zero if no data phase * @param[out] rxbuf the pointer to the receive buffer * * @api */ -void qspiReceive(QSPIDriver *qspip, size_t n, void *rxbuf) { +void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { - osalDbgCheck((qspip != NULL) && (n > 0U) && (rxbuf != NULL)); + osalDbgCheck((qspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n == 0U) || ((n > 0U) && (rxbuf != NULL))); osalSysLock(); osalDbgAssert(qspip->state == QSPI_READY, "not ready"); osalDbgAssert(qspip->config->end_cb == NULL, "has callback"); - qspiStartReceiveI(qspip, n, rxbuf); + qspiStartReceiveI(qspip, cmd, n, rxbuf); (void) osalThreadSuspendS(&qspip->thread); osalSysUnlock(); } -- cgit v1.2.3