stm32f0l0g0/SPI: add support for half duplex, simplex rx and simplex tx modes

This commit is contained in:
raiden00pl 2022-07-15 12:39:23 +02:00 • committed by Xiang Xiao
parent d69d9eb0c9
commit 3c0a3dabfc
2 changed files with 143 additions and 14 deletions

View file

@ -1286,6 +1286,22 @@ config STM32F0L0G0_SPI2_DMA
---help---
Use DMA to improve SPI2 transfer performance.
config STM32F0L0G0_SPI1_COMMTYPE
int "SPI1 Operation mode"
default 0
range 0 3
depends on STM32F0L0G0_SPI1
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32F0L0G0_SPI2_COMMTYPE
int "SPI2 Operation mode"
default 0
range 0 3
depends on STM32F0L0G0_SPI2
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32F0L0G0_SYSCFG
bool "SYSCFG"
default y

View file

@ -142,6 +142,14 @@
* Private Types
****************************************************************************/
enum spi_config_e
{
FULL_DUPLEX = 0,
SIMPLEX_TX,
SIMPLEX_RX,
HALF_DUPLEX
};
struct stm32_spidev_s
{
struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
@ -175,6 +183,7 @@ struct stm32_spidev_s
#ifdef CONFIG_PM
struct pm_callback_s pm_cb; /* PM callbacks */
#endif
enum spi_config_e config; /* full/half duplex, simplex transmit/read only */
};
/****************************************************************************
@ -192,6 +201,9 @@ static inline void spi_writeword(struct stm32_spidev_s *priv,
uint16_t byte);
static inline bool spi_16bitmode(struct stm32_spidev_s *priv);
static void spi_modifycr(uint32_t addr, struct stm32_spidev_s *priv,
uint16_t setbits, uint16_t clrbits);
/* DMA support */
#ifdef CONFIG_STM32F0L0G0_SPI_DMA
@ -472,6 +484,20 @@ static inline void spi_putreg8(struct stm32_spidev_s *priv,
static inline uint16_t spi_readword(struct stm32_spidev_s *priv)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return 0;
}
if (priv->config == HALF_DUPLEX)
{
/* Disable output for half-duplex mode */
spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_BIDIOE);
}
/* Wait until the receive buffer is not empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXNE) == 0);
@ -497,6 +523,20 @@ static inline uint16_t spi_readword(struct stm32_spidev_s *priv)
static inline uint8_t spi_readbyte(struct stm32_spidev_s *priv)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return 0;
}
if (priv->config == HALF_DUPLEX)
{
/* Disable output for half-duplex mode */
spi_modifycr(STM32_SPI_CR1_OFFSET, priv, 0, SPI_CR1_BIDIOE);
}
/* Wait until the receive buffer is not empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXNE) == 0);
@ -524,6 +564,20 @@ static inline uint8_t spi_readbyte(struct stm32_spidev_s *priv)
static inline void spi_writeword(struct stm32_spidev_s *priv,
uint16_t word)
{
/* Can't transmit in rx only mode */
if (priv->config == SIMPLEX_RX)
{
return;
}
if (priv->config == HALF_DUPLEX)
{
/* Enable output for half-duplex mode */
spi_modifycr(STM32_SPI_CR1_OFFSET, priv, SPI_CR1_BIDIOE, 0);
}
/* Wait until the transmit buffer is empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXE) == 0)
@ -1710,9 +1764,30 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv)
*/
clrbits = SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_BR_MASK |
SPI_CR1_LSBFIRST | SPI_CR1_RXONLY | SPI_CR1_BIDIOE |
SPI_CR1_BIDIMODE;
SPI_CR1_LSBFIRST;
setbits = SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM;
switch (priv->config)
{
default:
case FULL_DUPLEX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE | SPI_CR1_RXONLY;
setbits |= 0;
break;
case SIMPLEX_TX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE | SPI_CR1_RXONLY;
setbits |= 0;
break;
case SIMPLEX_RX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE;
setbits |= SPI_CR1_RXONLY;
break;
case HALF_DUPLEX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_RXONLY;
setbits |= SPI_CR1_BIDIMODE;
break;
}
spi_modifycr(STM32_SPI_CR1_OFFSET, priv, setbits, clrbits);
clrbits = SPI_CR2_DS_MASK;
@ -1730,9 +1805,30 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv)
*/
clrbits = SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_BR_MASK |
SPI_CR1_LSBFIRST | SPI_CR1_RXONLY | SPI_CR1_DFF |
SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE;
SPI_CR1_LSBFIRST | SPI_CR1_DFF;
setbits = SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM;
switch (priv->config)
{
default:
case FULL_DUPLEX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE | SPI_CR1_RXONLY;
setbits |= 0;
break;
case SIMPLEX_TX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE | SPI_CR1_RXONLY;
setbits |= 0;
break;
case SIMPLEX_RX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_BIDIMODE;
setbits |= SPI_CR1_RXONLY;
break;
case HALF_DUPLEX:
clrbits |= SPI_CR1_BIDIOE | SPI_CR1_RXONLY;
setbits |= SPI_CR1_BIDIMODE;
break;
}
spi_modifycr(STM32_SPI_CR1_OFFSET, priv, setbits, clrbits);
#endif
@ -1843,13 +1939,12 @@ struct spi_dev_s *stm32_spibus_initialize(int bus)
/* Configure SPI1 pins: SCK, MISO, and MOSI */
stm32_configgpio(GPIO_SPI1_SCK);
stm32_configgpio(GPIO_SPI1_MISO);
stm32_configgpio(GPIO_SPI1_MOSI);
/* Set up default configuration: Master, 8-bit, etc. */
spi_bus_initialize(priv);
priv->initialized = true;
if (priv->config == FULL_DUPLEX || priv->config == SIMPLEX_RX)
{
stm32_configgpio(GPIO_SPI1_MISO);
}
}
}
else
@ -1868,21 +1963,39 @@ struct spi_dev_s *stm32_spibus_initialize(int bus)
/* Configure SPI2 pins: SCK, MISO, and MOSI */
stm32_configgpio(GPIO_SPI2_SCK);
stm32_configgpio(GPIO_SPI2_MISO);
stm32_configgpio(GPIO_SPI2_MOSI);
/* Set up default configuration: Master, 8-bit, etc. */
spi_bus_initialize(priv);
priv->initialized = true;
if (priv->config == FULL_DUPLEX || priv->config == SIMPLEX_RX)
{
stm32_configgpio(GPIO_SPI2_MISO);
}
}
}
else
#endif
{
spierr("ERROR: Unsupported SPI bus: %d\n", bus);
priv = NULL;
goto errout;
}
#ifdef CONFIG_STM32L4_SPI_DMA
/* SPI DMA supported only for full-duplex mode */
if (priv->rxch && priv->txch && priv->config != FULL_DUPLEX)
{
priv = NULL;
spierr("ERROR: SPI DMA supported only for full duplex mode\n");
goto errout;
}
#endif
/* Set up default configuration: Master, 8-bit, etc. */
spi_bus_initialize(priv);
priv->initialized = true;
errout:
leave_critical_section(flags);
return (struct spi_dev_s *)priv;
}