This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 8eae3bb5ff1270bd1d092baccf8236e63e4c651e Author: raiden00pl <raide...@railab.me> AuthorDate: Fri Jul 22 10:32:10 2022 +0200 stm32f0l0g0/stm32_spi.c: fix receiving data for half duplex mode --- arch/arm/src/stm32f0l0g0/stm32_spi.c | 119 +++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 13 deletions(-) diff --git a/arch/arm/src/stm32f0l0g0/stm32_spi.c b/arch/arm/src/stm32f0l0g0/stm32_spi.c index 10fa825275..eab982771d 100644 --- a/arch/arm/src/stm32f0l0g0/stm32_spi.c +++ b/arch/arm/src/stm32f0l0g0/stm32_spi.c @@ -184,6 +184,8 @@ struct stm32_spidev_s struct pm_callback_s pm_cb; /* PM callbacks */ #endif enum spi_config_e config; /* full/half duplex, simplex transmit/read only */ + bool rx_now; /* Half duplex only: receiving data now */ + bool rx_mode; /* Half duplex only: SPI_CR1_BIDIOE bit status */ }; /**************************************************************************** @@ -196,6 +198,7 @@ static inline uint16_t spi_getreg(struct stm32_spidev_s *priv, uint8_t offset); static inline void spi_putreg(struct stm32_spidev_s *priv, uint8_t offset, uint16_t value); +static inline void spi_rx_mode(struct stm32_spidev_s *priv, bool enable); static inline uint16_t spi_readword(struct stm32_spidev_s *priv); static inline void spi_writeword(struct stm32_spidev_s *priv, uint16_t byte); @@ -430,6 +433,62 @@ static inline void spi_putreg(struct stm32_spidev_s *priv, putreg16(value, priv->spibase + offset); } +/**************************************************************************** + * Name: spi_rx_mode + * + * Description: + * Activate SPI RX or SPI TX for the half-duplex mode + * + ****************************************************************************/ + +static inline void spi_rx_mode(struct stm32_spidev_s *priv, bool enable) +{ + if (enable) + { + /* Enable RX */ + + if (!priv->rx_mode) + { + /* Disable SPI */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_SPE); + + /* Disable output for half-duplex mode - SPI starts to + * automatically output clocks. + */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_BIDIOE); + + /* Enable SPI */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, SPI_CR1_SPE, 0); + + priv->rx_mode = true; + } + } + else + { + /* Enable TX */ + + if (priv->rx_mode) + { + /* Disable SPI */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_SPE); + + /* Enable TX output */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, SPI_CR1_BIDIOE, 0); + + /* Enable SPI */ + + spi_modifycr(STM32_SPI_CR1_OFFSET, priv, SPI_CR1_SPE, 0); + + priv->rx_mode = false; + } + } +} + /**************************************************************************** * Name: spi_getreg8 * @@ -495,15 +554,18 @@ static inline uint16_t spi_readword(struct stm32_spidev_s *priv) if (priv->config == HALF_DUPLEX) { - /* Disable output for half-duplex mode */ - - spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_BIDIOE); + spi_rx_mode(priv, true); } /* Wait until the receive buffer is not empty */ while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXNE) == 0); + if (priv->config == HALF_DUPLEX) + { + spi_rx_mode(priv, false); + } + /* Then return the received byte */ return spi_getreg(priv, STM32_SPI_DR_OFFSET); @@ -536,9 +598,7 @@ static inline void spi_writeword(struct stm32_spidev_s *priv, if (priv->config == HALF_DUPLEX) { - /* Enable output for half-duplex mode */ - - spi_modifycr(STM32_SPI_CR1_OFFSET, priv, SPI_CR1_BIDIOE, 0); + spi_rx_mode(priv, false); } /* Wait until the transmit buffer is empty */ @@ -576,6 +636,13 @@ static inline void spi_writeword(struct stm32_spidev_s *priv, { spi_putreg(priv, STM32_SPI_DR_OFFSET, word); } + + if (priv->config == HALF_DUPLEX) + { + /* Wait for data transfer to be completed */ + + while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_BSY) != 0); + } } /**************************************************************************** @@ -1289,12 +1356,32 @@ static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd) { struct stm32_spidev_s *priv = (struct stm32_spidev_s *)dev; uint32_t regval; - uint32_t ret; + uint32_t ret = 0; DEBUGASSERT(priv && priv->spibase); - spi_writeword(priv, (uint16_t)(wd & 0xffff)); - ret = (uint32_t)spi_readword(priv); + if (priv->config != HALF_DUPLEX) + { + spi_writeword(priv, (uint16_t)(wd & 0xffff)); + ret = (uint32_t)spi_readword(priv); + } + else + { + /* In half duplex we must send data and receive data in separate + * spi_send() calls. + */ + + if (!priv->rx_now) + { + spi_writeword(priv, (uint16_t)(wd & 0xffff)); + } + else + { + ret = (uint32_t)spi_readword(priv); + + priv->rx_now = false; + } + } /* Check and clear any error flags (Reading from the SR clears the error * flags) @@ -1361,10 +1448,12 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, if (src) { word = *src++; + priv->rx_now = false; } else { word = 0xffff; + priv->rx_now = true; } /* Exchange one word */ @@ -1394,10 +1483,12 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, if (src) { word = *src++; + priv->rx_now = false; } else { word = 0xff; + priv->rx_now = true; } /* Exchange one word */ @@ -1746,8 +1837,9 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv) setbits |= SPI_CR1_RXONLY; break; case HALF_DUPLEX: - clrbits |= SPI_CR1_BIDIOE | SPI_CR1_RXONLY; - setbits |= SPI_CR1_BIDIMODE; + clrbits |= SPI_CR1_RXONLY; + setbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE; /* TX mode */ + priv->rx_mode = false; break; } @@ -1787,8 +1879,9 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv) setbits |= SPI_CR1_RXONLY; break; case HALF_DUPLEX: - clrbits |= SPI_CR1_BIDIOE | SPI_CR1_RXONLY; - setbits |= SPI_CR1_BIDIMODE; + clrbits |= SPI_CR1_RXONLY; + setbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE; /* TX mode */ + priv->rx_mode = false; break; }