You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/07/25 15:46:43 UTC
[incubator-nuttx] 04/04: stm32f0l0g0/stm32_spi.c: fix receiving data for half duplex mode
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 <ra...@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;
}