mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
drivers/spi/Kconfig and include/nuttx/spi/spi.h: Extend the HW features supported by SPI. It now supports a deffered DMA trigger hardware configuration. arch/arm/src/stm32/stm32_spi.c: Implements the new deferred DMA trigger feature.
This commit is contained in:
committed by
Gregory Nutt
parent
d2b98cc150
commit
8328539534
@@ -173,6 +173,10 @@ struct stm32_spidev_s
|
|||||||
#ifdef CONFIG_STM32_SPI_DMA
|
#ifdef CONFIG_STM32_SPI_DMA
|
||||||
volatile uint8_t rxresult; /* Result of the RX DMA */
|
volatile uint8_t rxresult; /* Result of the RX DMA */
|
||||||
volatile uint8_t txresult; /* Result of the RX DMA */
|
volatile uint8_t txresult; /* Result of the RX DMA */
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
bool defertrig; /* Flag indicating that trigger should be deferred */
|
||||||
|
bool trigarmed; /* Flag indicating that the trigger is armed */
|
||||||
|
#endif
|
||||||
uint8_t rxch; /* The RX DMA channel number */
|
uint8_t rxch; /* The RX DMA channel number */
|
||||||
uint8_t txch; /* The TX DMA channel number */
|
uint8_t txch; /* The TX DMA channel number */
|
||||||
DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */
|
DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */
|
||||||
@@ -277,6 +281,9 @@ static const struct spi_ops_s g_sp1iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi1register, /* Provided externally */
|
.registercallback = stm32_spi1register, /* Provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -326,6 +333,9 @@ static const struct spi_ops_s g_sp2iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi2register, /* provided externally */
|
.registercallback = stm32_spi2register, /* provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -375,6 +385,9 @@ static const struct spi_ops_s g_sp3iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi3register, /* provided externally */
|
.registercallback = stm32_spi3register, /* provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -424,6 +437,9 @@ static const struct spi_ops_s g_sp4iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi4register, /* provided externally */
|
.registercallback = stm32_spi4register, /* provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -473,6 +489,9 @@ static const struct spi_ops_s g_sp5iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi5register, /* provided externally */
|
.registercallback = stm32_spi5register, /* provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -522,6 +541,9 @@ static const struct spi_ops_s g_sp6iops =
|
|||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
.trigger = spi_trigger,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SPI_CALLBACK
|
#ifdef CONFIG_SPI_CALLBACK
|
||||||
.registercallback = stm32_spi6register, /* provided externally */
|
.registercallback = stm32_spi6register, /* provided externally */
|
||||||
#else
|
#else
|
||||||
@@ -1428,12 +1450,23 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
|
|||||||
spi_modifycr1(priv, setbits, clrbits);
|
spi_modifycr1(priv, setbits, clrbits);
|
||||||
spi_modifycr1(priv, SPI_CR1_SPE, 0);
|
spi_modifycr1(priv, SPI_CR1_SPE, 0);
|
||||||
|
|
||||||
|
features &= ~HWFEAT_LSBFIRST;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
/* Turn deferred trigger mode on or off. Only applicable for DMA mode. If a
|
||||||
|
* transfer is deferred then the DMA will not actually be triggered until a
|
||||||
|
* subsequent call to SPI_TRIGGER to set it off. The thread will be waiting
|
||||||
|
* on the transfer completing as normal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
priv->defertrig = ((features & HWFEAT_TRIGGER) != 0);
|
||||||
|
features &= ~HWFEAT_TRIGGER;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Other H/W features are not supported */
|
/* Other H/W features are not supported */
|
||||||
|
|
||||||
return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS;
|
return (features == 0) ? OK : -ENOSYS;
|
||||||
#else
|
|
||||||
return -ENOSYS;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1634,19 +1667,78 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
|||||||
spi_dmarxsetup(priv, rxbuffer, &rxdummy, nwords);
|
spi_dmarxsetup(priv, rxbuffer, &rxdummy, nwords);
|
||||||
spi_dmatxsetup(priv, txbuffer, &txdummy, nwords);
|
spi_dmatxsetup(priv, txbuffer, &txdummy, nwords);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
/* Is deferred triggering in effect? */
|
||||||
|
|
||||||
|
if (!priv->defertrig)
|
||||||
|
{
|
||||||
|
/* No.. Start the DMAs */
|
||||||
|
|
||||||
|
spi_dmarxstart(priv);
|
||||||
|
spi_dmatxstart(priv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Yes.. indicated that we are ready to be started */
|
||||||
|
|
||||||
|
priv->trigarmed = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
/* Start the DMAs */
|
/* Start the DMAs */
|
||||||
|
|
||||||
spi_dmarxstart(priv);
|
spi_dmarxstart(priv);
|
||||||
spi_dmatxstart(priv);
|
spi_dmatxstart(priv);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Then wait for each to complete */
|
/* Then wait for each to complete */
|
||||||
|
|
||||||
spi_dmarxwait(priv);
|
spi_dmarxwait(priv);
|
||||||
spi_dmatxwait(priv);
|
spi_dmatxwait(priv);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
priv->trigarmed = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_STM32_SPI_DMA */
|
#endif /* CONFIG_STM32_SPI_DMA */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: spi_trigger
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Trigger a previously configured DMA transfer.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - Device-specific state data
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK - Trigger was fired
|
||||||
|
* ENOTSUP - Trigger not fired due to lack of DMA support
|
||||||
|
* EIO - Trigger not fired because not previously primed
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
static int spi_trigger(FAR struct spi_dev_s *dev)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_STM32_SPI_DMA
|
||||||
|
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
|
||||||
|
|
||||||
|
if (!priv->trigarmed)
|
||||||
|
{
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_dmarxstart(priv);
|
||||||
|
spi_dmatxstart(priv);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
#else
|
||||||
|
return -ENOSYS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: spi_sndblock
|
* Name: spi_sndblock
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -114,6 +114,17 @@ config SPI_CS_DELAY_CONTROL
|
|||||||
|
|
||||||
This option enables the setdelay() interface method.
|
This option enables the setdelay() interface method.
|
||||||
|
|
||||||
|
config SPI_TRIGGER
|
||||||
|
bool "SPI DMA trigger"
|
||||||
|
default n
|
||||||
|
select SPI_HWFEATURES
|
||||||
|
depends on SPI_EXCHANGE
|
||||||
|
---help---
|
||||||
|
Some architectures benefit from delaying the start of DMA from the
|
||||||
|
DMA setup. If this option is selected, then an SPI_TRIGGER() method
|
||||||
|
is supported: The DMA is setup with in in SPI_EXCHANGE() but does
|
||||||
|
not actually begin until SPI_TRIGGER() is called.
|
||||||
|
|
||||||
config SPI_DRIVER
|
config SPI_DRIVER
|
||||||
bool "SPI character driver"
|
bool "SPI character driver"
|
||||||
default n
|
default n
|
||||||
|
|||||||
@@ -225,6 +225,10 @@
|
|||||||
* condition. (see spi_exchange)
|
* condition. (see spi_exchange)
|
||||||
* Bit 4: HWFEAT_LSBFIRST
|
* Bit 4: HWFEAT_LSBFIRST
|
||||||
* Data transferred LSB first (default is MSB first)
|
* Data transferred LSB first (default is MSB first)
|
||||||
|
* Bit 5: Turn deferred trigger mode on or off. Primarily used for DMA
|
||||||
|
* mode. If a transfer is deferred then the DMA will not actually
|
||||||
|
* be triggered until a subsequent call to SPI_TRIGGER to set it
|
||||||
|
* off.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# ifdef CONFIG_SPI_CRCGENERATION
|
# ifdef CONFIG_SPI_CRCGENERATION
|
||||||
@@ -243,6 +247,10 @@
|
|||||||
# define HWFEAT_LSBFIRST (1 << 4)
|
# define HWFEAT_LSBFIRST (1 << 4)
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifdef CONFIG_SPI_TRIGGER
|
||||||
|
# define HWFEAT_TRIGGER (1 << 5)
|
||||||
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Any attempt to select hardware features with CONFIG_SPI_HWFEATURES
|
/* Any attempt to select hardware features with CONFIG_SPI_HWFEATURES
|
||||||
* deselected will return an -ENOSYS error.
|
* deselected will return an -ENOSYS error.
|
||||||
@@ -420,6 +428,25 @@
|
|||||||
#define SPI_REGISTERCALLBACK(d,c,a) \
|
#define SPI_REGISTERCALLBACK(d,c,a) \
|
||||||
((d)->ops->registercallback ? (d)->ops->registercallback(d,c,a) : -ENOSYS)
|
((d)->ops->registercallback ? (d)->ops->registercallback(d,c,a) : -ENOSYS)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: SPI_TRIGGER
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Trigger a previously configured DMA transfer.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - Device-specific state data
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK - Trigger was fired
|
||||||
|
* -ENOSYS - Trigger not fired due to lack of DMA or low level support
|
||||||
|
* -EIO - Trigger not fired because not previously primed
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
# define SPI_TRIGGER(d) \
|
||||||
|
(((d)->ops->trigger) ? ((d)->ops->trigger(d)) : -ENOSYS)
|
||||||
|
|
||||||
/* SPI Device Macros ********************************************************/
|
/* SPI Device Macros ********************************************************/
|
||||||
|
|
||||||
/* This builds a SPI devid from its type and index */
|
/* This builds a SPI devid from its type and index */
|
||||||
@@ -549,6 +576,9 @@ struct spi_ops_s
|
|||||||
FAR const void *buffer, size_t nwords);
|
FAR const void *buffer, size_t nwords);
|
||||||
CODE void (*recvblock)(FAR struct spi_dev_s *dev, FAR void *buffer,
|
CODE void (*recvblock)(FAR struct spi_dev_s *dev, FAR void *buffer,
|
||||||
size_t nwords);
|
size_t nwords);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_TRIGGER
|
||||||
|
CODE int (*trigger)(FAR struct spi_dev_s *dev);
|
||||||
#endif
|
#endif
|
||||||
CODE int (*registercallback)(FAR struct spi_dev_s *dev,
|
CODE int (*registercallback)(FAR struct spi_dev_s *dev,
|
||||||
spi_mediachange_t callback, void *arg);
|
spi_mediachange_t callback, void *arg);
|
||||||
|
|||||||
Reference in New Issue
Block a user