diff --git a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_spi.h b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_spi.h index 74025c762b..9d93e32129 100644 --- a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_spi.h +++ b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_spi.h @@ -397,6 +397,22 @@ #define SPI_SR_CTSIZE_SHIFT (16) /* Bits 16-31: number of data frames remaining in current TSIZE session */ #define SPI_SR_CTSIZE_MASK (1 << SPI_SR_CTSIZE_SHIFT) +/* SPI/I2S interrupt/status flags interrupt enable register */ + +#define SPI_IER_RXPIE (1 << 0) /* Bit 0: RXP Interrupt enable */ +#define SPI_IER_TXPIE (1 << 1) /* Bit 1: TXP interrupt enable */ +#define SPI_IER_DXPIE (1 << 2) /* Bit 2: DXP interrupt enable */ +#define SPI_IER_EOTIE (1 << 3) /* Bit 3: EOT, SUSP and TXC interrupt enable */ +#define SPI_IER_TXTFIE (1 << 4) /* Bit 4: TXTFIE interrupt enable */ +#define SPI_IER_UDRIE (1 << 5) /* Bit 5: UDR interrupt enable */ +#define SPI_IER_OVRIE (1 << 6) /* Bit 6: OVR interrupt enable */ +#define SPI_IER_CRCEIE (1 << 7) /* Bit 7: CRC error interrupt enable */ +#define SPI_IER_TIFREIE (1 << 8) /* Bit 8: TIFRE interrupt enable */ +#define SPI_IER_MODFIE (1 << 9) /* Bit 9: mode fault interrupt enable */ +#define SPI_IER_TSERFIE (1 << 10) /* Bit 10: additional number of transactions + * reload interrupt enable + */ + /* SPI/I2S interrupt/status flags clear register */ /* Bits 0-2: Reserved */ diff --git a/arch/arm/src/stm32h7/stm32_spi.c b/arch/arm/src/stm32h7/stm32_spi.c index 895868f1d3..b7ae80a6b3 100644 --- a/arch/arm/src/stm32h7/stm32_spi.c +++ b/arch/arm/src/stm32h7/stm32_spi.c @@ -234,9 +234,7 @@ struct stm32_spidev_s struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ uint32_t spibase; /* SPIn base address */ uint32_t spiclock; /* Clocking for the SPI module */ -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS uint8_t spiirq; /* SPI IRQ number */ -#endif #ifdef CONFIG_STM32H7_SPI_DMA volatile uint8_t rxresult; /* Result of the RX DMA */ volatile uint8_t txresult; /* Result of the RX DMA */ @@ -291,11 +289,8 @@ static inline void spi_dumpregs(FAR struct stm32_spidev_s *priv); static int spi_dmarxwait(FAR struct stm32_spidev_s *priv); static int spi_dmatxwait(FAR struct stm32_spidev_s *priv); static inline void spi_dmarxwakeup(FAR struct stm32_spidev_s *priv); -static inline void spi_dmatxwakeup(FAR struct stm32_spidev_s *priv); static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg); -static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, - void *arg); static void spi_dmarxsetup(FAR struct stm32_spidev_s *priv, FAR void *rxbuffer, FAR void *rxdummy, @@ -396,9 +391,7 @@ static struct stm32_spidev_s g_spi1dev = }, .spibase = STM32_SPI1_BASE, .spiclock = SPI123_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI1, -#endif #ifdef CONFIG_STM32H7_SPI1_DMA .rxch = DMAMAP_SPI1_RX, .txch = DMAMAP_SPI1_TX, @@ -464,9 +457,7 @@ static struct stm32_spidev_s g_spi2dev = }, .spibase = STM32_SPI2_BASE, .spiclock = SPI123_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI2, -#endif #ifdef CONFIG_STM32H7_SPI2_DMA .rxch = DMAMAP_SPI2_RX, .txch = DMAMAP_SPI2_TX, @@ -532,9 +523,7 @@ static struct stm32_spidev_s g_spi3dev = }, .spibase = STM32_SPI3_BASE, .spiclock = SPI123_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI3, -#endif #ifdef CONFIG_STM32H7_SPI3_DMA .rxch = DMAMAP_SPI3_RX, .txch = DMAMAP_SPI3_TX, @@ -600,9 +589,7 @@ static struct stm32_spidev_s g_spi4dev = }, .spibase = STM32_SPI4_BASE, .spiclock = SPI45_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI4, -#endif #ifdef CONFIG_STM32H7_SPI4_DMA .rxch = DMAMAP_SPI4_RX, .txch = DMAMAP_SPI4_TX, @@ -668,9 +655,7 @@ static struct stm32_spidev_s g_spi5dev = }, .spibase = STM32_SPI5_BASE, .spiclock = SPI45_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI5, -#endif #ifdef CONFIG_STM32H7_SPI5_DMA .rxch = DMAMAP_SPI5_RX, .txch = DMAMAP_SPI5_TX, @@ -736,9 +721,7 @@ static struct stm32_spidev_s g_spi6dev = }, .spibase = STM32_SPI6_BASE, .spiclock = SPI6_KERNEL_CLOCK_FREQ, -#ifdef CONFIG_STM32H7_SPI_INTERRUPTS .spiirq = STM32_IRQ_SPI6, -#endif #ifdef CONFIG_STM32H7_SPI6_DMA .rxch = DMAMAP_SPI6_RX, .txch = DMAMAP_SPI6_TX, @@ -846,6 +829,22 @@ static inline void spi_putreg(FAR struct stm32_spidev_s *priv, putreg32(value, priv->spibase + offset); } +/**************************************************************************** + * Name: spi_modifyreg + * + * Description: + * Modify an SPI register + * + ****************************************************************************/ + +static void spi_modifyreg(FAR struct stm32_spidev_s *priv, uint32_t offset, + uint32_t clrbits, uint32_t setbits) +{ + /* Only 32-bit registers */ + + modifyreg32(priv->spibase + offset, clrbits, setbits); +} + /**************************************************************************** * Name: spi_readword * @@ -996,6 +995,39 @@ static void spi_dumpregs(FAR struct stm32_spidev_s *priv) } #endif +/**************************************************************************** + * Name: spi_interrupt + * + * Description: + * In DMA transfer mode, handle the transmission complete interrupt + * + ****************************************************************************/ + +static int spi_interrupt(int irq, void *context, void *arg) +{ + FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg; + uint32_t sr = spi_getreg(priv, STM32_SPI_SR_OFFSET); + + if (sr & SPI_SR_TXC) + { + /* Disable interrupt. This needs to be done + * before disabling SPI to avoid spurious TXC interrupt + * (ERRATA: Q2.14.4 TXP interrupt occurring while SPI/I2Sdisabled") + * There is no need to clear the interrupt since it is disabled and + * SPI will be disabled after transmit as well. + */ + + spi_modifyreg(priv, STM32_SPI_IER_OFFSET, SPI_IER_EOTIE, 0); + + /* Set result and release wait semaphore */ + + priv->txresult = 0x80; + nxsem_post(&priv->txsem); + } + + return 0; +} + /**************************************************************************** * Name: spi_dmarxwait * @@ -1056,6 +1088,15 @@ static int spi_dmatxwait(FAR struct stm32_spidev_s *priv) return OK; } + /* Enable TXC interrupt. This needs to be done after starting TX-dma AND + * when spi is enabled to avoid spurious TXC interrupt (ERRATA: + * "2.14.4 TXP interrupt occurring while SPI/I2Sdisabled") + * It is fine to enable this interrupt even if the transfer already did + * complete; in this case the irq will just fire right away + */ + + spi_modifyreg(priv, STM32_SPI_IER_OFFSET, 0, SPI_IER_EOTIE); + /* Take the semaphore (perhaps waiting). If the result is zero, then the * DMA must not really have completed??? */ @@ -1091,21 +1132,6 @@ static inline void spi_dmarxwakeup(FAR struct stm32_spidev_s *priv) } #endif -/**************************************************************************** - * Name: spi_dmatxwakeup - * - * Description: - * Signal that DMA is complete - * - ****************************************************************************/ - -#ifdef CONFIG_STM32H7_SPI_DMA -static inline void spi_dmatxwakeup(FAR struct stm32_spidev_s *priv) -{ - nxsem_post(&priv->txsem); -} -#endif - /**************************************************************************** * Name: spi_dmarxcallback * @@ -1126,26 +1152,6 @@ static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg) } #endif -/**************************************************************************** - * Name: spi_dmatxcallback - * - * Description: - * Called when the RX DMA completes - * - ****************************************************************************/ - -#ifdef CONFIG_STM32H7_SPI_DMA -static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg) -{ - FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg; - - /* Wake-up the SPI driver */ - - priv->txresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */ - spi_dmatxwakeup(priv); -} -#endif - /**************************************************************************** * Name: spi_dmarxsetup * @@ -1287,6 +1293,7 @@ static void spi_dmarxstart(FAR struct stm32_spidev_s *priv) } priv->rxresult = 0; + spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_RXDMAEN); stm32_dmastart(priv->rxdma, spi_dmarxcallback, priv, false); } #endif @@ -1310,18 +1317,11 @@ static void spi_dmatxstart(FAR struct stm32_spidev_s *priv) } priv->txresult = 0; - stm32_dmastart(priv->txdma, spi_dmatxcallback, priv, false); + stm32_dmastart(priv->txdma, NULL, priv, false); + spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN); } #endif -static void spi_modifyreg(FAR struct stm32_spidev_s *priv, uint32_t offset, - uint32_t clrbits, uint32_t setbits) -{ - /* Only 32-bit registers */ - - modifyreg32(priv->spibase + offset, clrbits, setbits); -} - /**************************************************************************** * Name: spi_lock * @@ -2051,8 +2051,6 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, */ spi_enable(priv, false); - spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN, - SPI_CFG1_RXDMAEN); spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords); @@ -2070,9 +2068,6 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, stm32_dmasetup(priv->txdma, &txdmacfg); } - spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN | - SPI_CFG1_RXDMAEN); - #ifdef CONFIG_SPI_TRIGGER /* Is deferred triggering in effect? */ @@ -2114,6 +2109,11 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, * bits in the SPI_CFG1 register, if DMA Tx and/or DMA Rx are used. */ + /* TX transmission must be completed before shutting down the SPI */ + + DEBUGASSERT(priv->config != SIMPLEX_RX ? + (spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXC) : 1); + spi_enable(priv, false); spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN, 0); @@ -2360,7 +2360,7 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv) clrbits = SPI_CFG2_CPHA | SPI_CFG2_CPOL | SPI_CFG2_LSBFRST | SPI_CFG2_COMM_MASK; - setbits = SPI_CFG2_MASTER | SPI_CFG2_SSM; + setbits = SPI_CFG2_AFCNTR | SPI_CFG2_MASTER | SPI_CFG2_SSM; switch (priv->config) { @@ -2434,6 +2434,20 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv) } #endif + /* Attach the IRQ to the driver */ + + if (irq_attach(priv->spiirq, spi_interrupt, priv)) + { + /* We could not attach the ISR to the interrupt */ + + spierr("ERROR: Can't initialize spi irq\n"); + return; + } + + /* Enable SPI interrupts */ + + up_enable_irq(priv->spiirq); + /* Enable SPI */ spi_enable(priv, true);