stm32h7:Fix DMA Overrun error

This commit is contained in:
David Sidrane 2020-04-02 12:06:58 -07:00 committed by patacongo
parent c191787ba4
commit fc3ab3e085

View File

@ -1451,16 +1451,6 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits); spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
#ifdef CONFIG_STM32H7_SPI_DMA
/* Enabling SPI causes a spurious received character indication
* which confuse the DMA controller so we disable DMA during that
* enabling; and flush the SPI RX FIFO before re-enabling DMA.
*/
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_RXDMAEN |
SPI_CFG1_TXDMAEN, 0);
#endif
/* Re-enable SPI */ /* Re-enable SPI */
spi_enable(priv, true); spi_enable(priv, true);
@ -1469,19 +1459,9 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
{ {
/* Flush SPI read FIFO */ /* Flush SPI read FIFO */
spi_getreg(priv, STM32_SPI_TXDR_OFFSET); spi_getreg(priv, STM32_SPI_RXDR_OFFSET);
} }
#ifdef CONFIG_STM32H7_SPI_DMA
/* Re-enable DMA (with SPI disabled) */
spi_enable(priv, false);
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_RXDMAEN |
SPI_CFG1_TXDMAEN);
spi_enable(priv, true);
#endif
/* Save the mode so that subsequent re-configurations will be faster */ /* Save the mode so that subsequent re-configurations will be faster */
priv->mode = mode; priv->mode = mode;
@ -1913,6 +1893,22 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
static uint8_t rxdummy[4] __attribute__((aligned(4))); static uint8_t rxdummy[4] __attribute__((aligned(4)));
static const uint16_t txdummy = 0xffff; static const uint16_t txdummy = 0xffff;
/* When starting communication using DMA, to prevent DMA channel
* management raising error events, these steps must be followed in
* order:
* 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CFG1 register,
* if DMA Rx is used.
* 2. Enable DMA requests for Tx and Rx in DMA registers, if the DMA is
* used.
* 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CFG1 register,
* if DMA Tx is used.
* 4. Enable the SPI by setting the SPE bit.
*/
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", spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
txbuffer, rxbuffer, nwords); txbuffer, rxbuffer, nwords);
DEBUGASSERT(priv->spibase != 0); DEBUGASSERT(priv->spibase != 0);
@ -1920,6 +1916,9 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
spi_dmarxsetup(priv, rxbuffer, (uint16_t *)rxdummy, nbytes); spi_dmarxsetup(priv, rxbuffer, (uint16_t *)rxdummy, nbytes);
spi_dmatxsetup(priv, txbuffer, &txdummy, nbytes); spi_dmatxsetup(priv, txbuffer, &txdummy, nbytes);
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN |
SPI_CFG1_RXDMAEN);
/* Flush cache to physical memory */ /* Flush cache to physical memory */
if (txbuffer) if (txbuffer)
@ -1927,19 +1926,17 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
up_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + nbytes); up_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + nbytes);
} }
/* REVISIT: Master transfer start */
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
#ifdef CONFIG_SPI_TRIGGER #ifdef CONFIG_SPI_TRIGGER
/* Is deferred triggering in effect? */ /* Is deferred triggering in effect? */
if (!priv->defertrig) if (!priv->defertrig)
{ {
/* No.. Start the DMAs */ /* No.. Start the DMAs then the SPI */
spi_dmarxstart(priv); spi_dmarxstart(priv);
spi_dmatxstart(priv); spi_dmatxstart(priv);
spi_enable(priv, true);
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
} }
else else
{ {
@ -1948,20 +1945,32 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
priv->trigarmed = true; priv->trigarmed = true;
} }
#else #else
/* Start the DMAs */ /* Start the DMAs then the SPI */
spi_dmarxstart(priv); spi_dmarxstart(priv);
spi_dmatxstart(priv); spi_dmatxstart(priv);
spi_enable(priv, true);
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
#endif #endif
/* Then wait for each to complete */ /* Then wait for each to complete */
ret = spi_dmarxwait(priv); spi_dmarxwait(priv);
if (ret >= 0) spi_dmatxwait(priv);
{
ret = spi_dmatxwait(priv); /* To close communication it is mandatory to follow these steps in
UNUSED(ret); * order:
} * 1. Disable DMA request for Tx and Rx in the DMA registers, if the
* DMA issued.
* 2. Disable the SPI by following the SPI disable procedure.
* 3. Disable DMA Tx and Rx buffers by clearing the TXDMAEN and RXDMAEN
* bits in the SPI_CFG1 register, if DMA Tx and/or DMA Rx are used.
*/
spi_enable(priv, false);
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN |
SPI_CFG1_RXDMAEN, 0);
spi_enable(priv, true);
#ifdef CONFIG_SPI_TRIGGER #ifdef CONFIG_SPI_TRIGGER
priv->trigarmed = false; priv->trigarmed = false;
@ -2012,7 +2021,8 @@ static int spi_trigger(FAR struct spi_dev_s *dev)
spi_dmarxstart(priv); spi_dmarxstart(priv);
spi_dmatxstart(priv); spi_dmatxstart(priv);
spi_enable(priv, true);
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
return OK; return OK;
#else #else
return -ENOSYS; return -ENOSYS;