git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16413 27425a3e-05d8-49a3-a47f-9c15f0e5edd8

This commit is contained in:
Giovanni Di Sirio 2023-11-17 13:54:10 +00:00
parent 33f53bc0dd
commit b6455931cb
5 changed files with 131 additions and 189 deletions

View File

@ -81,5 +81,22 @@ REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* RAM region to be used for GPDMA link structures.*/
REGION_ALIAS("GPDMA_RAM", ram0);
SECTIONS
{
/* Special section for GPDMA links, it must not exceed 64kB in size.*/
.gpdma (NOLOAD) : ALIGN(16)
{
__gpdma_base__ = .;
*(.gpdma)
*(.gpdma.*)
*(.bss.__gpdma_*)
. = ALIGN(4);
__gpdma_end__ = .;
} > GPDMA_RAM
}
/* Generic rules inclusion.*/
INCLUDE rules.ld

View File

@ -572,10 +572,6 @@ void gpdmaChannelFree(const stm32_gpdma_channel_t *dmachp) {
* @details The function disables the specified channel and then clears any
* pending interrupt.
* @note This function can be invoked in both ISR or thread context.
* @note Interrupts enabling flags are set to zero after this call, see
* bug 3607518.
* @pre The channel must have been allocated using @p dmaChannelAlloc().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
*

View File

@ -380,173 +380,6 @@ typedef struct {
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Associates a peripheral data register to a GPDMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @param[in] addr value to be written in the CPAR register
*
* @special
*/
#define gpdmaStreamSetPeripheral(dmachp, addr) { \
(dmachp)->channel->CPAR = (uint32_t)(addr); \
}
/**
* @brief Associates a memory destination to a GPDMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @param[in] addr value to be written in the CMAR register
*
* @special
*/
#define gpdmaStreamSetMemory0(dmachp, addr) { \
(dmachp)->channel->CMAR = (uint32_t)(addr); \
}
/**
* @brief Sets the number of transfers to be performed.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @param[in] size value to be written in the CNDTR register
*
* @special
*/
#define gpdmaStreamSetTransactionSize(dmachp, size) { \
(dmachp)->channel->CNDTR = (uint32_t)(size); \
}
/**
* @brief Returns the number of transfers to be performed.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @return The number of transfers to be performed.
*
* @special
*/
#define gpdmaStreamGetTransactionSize(dmachp) ((size_t)((dmachp)->channel->CNDTR))
/**
* @brief Programs the channel mode settings.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @param[in] mode value to be written in the CCR register
*
* @special
*/
#define gpdmaStreamSetMode(dmachp, mode) { \
(dmachp)->channel->CCR = (uint32_t)(mode); \
}
/**
* @brief GPDMA channel enable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
*
* @special
*/
#define gpdmaStreamEnable(dmachp) { \
(dmachp)->channel->CCR |= STM32_GPDMA_CR_EN; \
}
/**
* @brief GPDMA channel disable.
* @details The function disables the specified channel and then clears any
* pending interrupt.
* @note This function can be invoked in both ISR or thread context.
* @note Interrupts enabling flags are set to zero after this call, see
* bug 3607518.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
*
* @special
*/
#define ______gpdmaStreamDisable(dmachp) { \
(dmachp)->channel->CCR &= ~(STM32_GPDMA_CR_TCIE | STM32_GPDMA_CR_HTIE | \
STM32_GPDMA_CR_TEIE | STM32_GPDMA_CR_EN); \
dmaStreamClearInterrupt(dmachp); \
}
/**
* @brief GPDMA channel interrupt sources clear.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
*
* @special
*/
#define gpdmaStreamClearInterrupt(dmachp) { \
(dmachp)->dma->IFCR = STM32_GPDMA_ISR_MASK << (dmachp)->shift; \
}
/**
* @brief Starts a memory to memory operation using the specified channel.
* @note The default transfer data mode is "byte to byte" but it can be
* changed by specifying extra options in the @p mode parameter.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
* @param[in] mode value to be written in the CCR register, this value
* is implicitly ORed with:
* - @p STM32_GPDMA_CR_MINC
* - @p STM32_GPDMA_CR_PINC
* - @p STM32_GPDMA_CR_DIR_M2M
* - @p STM32_GPDMA_CR_EN
* .
* @param[in] src source address
* @param[in] dst destination address
* @param[in] n number of data units to copy
*/
#define gpdmaStartMemCopy(dmachp, mode, src, dst, n) { \
dmaStreamSetPeripheral(dmachp, src); \
dmaStreamSetMemory0(dmachp, dst); \
dmaStreamSetTransactionSize(dmachp, n); \
dmaStreamSetMode(dmachp, (mode) | \
STM32_GPDMA_CR_MINC | STM32_GPDMA_CR_PINC | \
STM32_GPDMA_CR_DIR_M2M | STM32_GPDMA_CR_EN); \
}
/**
* @brief Polled wait for GPDMA transfer end.
* @pre The channel must have been allocated using @p dmaStreamAlloc().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmachp pointer to a @p stm32_gpdma_channel_t structure
*/
#define gpdmaWaitCompletion(dmachp) { \
while ((dmachp)->channel->CNDTR > 0U) \
; \
dmaStreamDisable(dmachp); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@ -555,6 +388,13 @@ typedef struct {
extern const stm32_gpdma_channel_t __stm32_gpdma_channels[STM32_GPDMA_NUM_CHANNELS];
#endif
/* The linker needs to export this symbol if the link mode of GPDMA is required,
the symbol needs to be aligned to a 64k boundary and marks the base of an
area where all symbols with names starting with __gpdma_ are collected.
On devices with data cache this area shall be placed at beginning of a
non-cachable area.*/
extern uint32_t __gpdma_base__;
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -68,6 +68,30 @@ SPIDriver SPID6;
/* Driver local variables and types. */
/*===========================================================================*/
#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi1;
#endif
#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi2;
#endif
#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi3;
#endif
#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi4;
#endif
#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi5;
#endif
#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
static spi_dmabuf_t __gpdma_spi6;
#endif
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
@ -455,6 +479,7 @@ void spi_lld_init(void) {
SPID1.dreqrx = STM32_GPDMA_REQ_SPI1_RX;
SPID1.dreqtx = STM32_GPDMA_REQ_SPI1_TX;
SPID1.dprio = STM32_SPI_SPI1_DMA_PRIORITY;
SPID1.dbuf = &__gpdma_spi1;
#if !defined(STM32_SPI1_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI1_NUMBER, STM32_SPI_SPI1_IRQ_PRIORITY);
#endif
@ -468,6 +493,7 @@ void spi_lld_init(void) {
SPID2.dreqrx = STM32_GPDMA_REQ_SPI2_RX;
SPID2.dreqtx = STM32_GPDMA_REQ_SPI2_TX;
SPID2.dprio = STM32_SPI_SPI2_DMA_PRIORITY;
SPID2.dbuf = &__gpdma_spi2;
#if !defined(STM32_SPI2_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI2_NUMBER, STM32_SPI_SPI2_IRQ_PRIORITY);
#endif
@ -481,6 +507,7 @@ void spi_lld_init(void) {
SPID3.dreqrx = STM32_GPDMA_REQ_SPI3_RX;
SPID3.dreqtx = STM32_GPDMA_REQ_SPI3_TX;
SPID3.dprio = STM32_SPI_SPI3_DMA_PRIORITY;
SPID3.dbuf = &__gpdma_spi3;
#if !defined(STM32_SPI3_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI3_NUMBER, STM32_SPI_SPI3_IRQ_PRIORITY);
#endif
@ -494,6 +521,7 @@ void spi_lld_init(void) {
SPID4.dreqrx = STM32_GPDMA_REQ_SPI4_RX;
SPID4.dreqtx = STM32_GPDMA_REQ_SPI4_TX;
SPID4.dprio = STM32_SPI_SPI4_DMA_PRIORITY;
SPID4.dbuf = &__gpdma_spi4;
#if !defined(STM32_SPI4_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI4_NUMBER, STM32_SPI_SPI4_IRQ_PRIORITY);
#endif
@ -507,6 +535,7 @@ void spi_lld_init(void) {
SPID5.dreqrx = STM32_GPDMA_REQ_SPI5_RX;
SPID5.dreqtx = STM32_GPDMA_REQ_SPI5_TX;
SPID5.dprio = STM32_SPI_SPI5_DMA_PRIORITY;
SPID5.dbuf = &__gpdma_spi5;
#if !defined(STM32_SPI5_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI5_NUMBER, STM32_SPI_SPI5_IRQ_PRIORITY);
#endif
@ -520,6 +549,7 @@ void spi_lld_init(void) {
SPID6.dreqrx = STM32_GPDMA_REQ_SPI6_RX;
SPID6.dreqtx = STM32_GPDMA_REQ_SPI6_TX;
SPID6.dprio = STM32_SPI_SPI6_DMA_PRIORITY;
SPID6.dbuf = &__gpdma_spi6;
#if !defined(STM32_SPI6_SUPPRESS_ISR)
nvicEnableVector(STM32_SPI6_NUMBER, STM32_SPI_SPI6_IRQ_PRIORITY);
#endif
@ -538,8 +568,9 @@ msg_t spi_lld_start(SPIDriver *spip) {
uint32_t dsize, dmaccr, dmalbar;
msg_t msg;
/* Resetting TX pattern source.*/
spip->txsource = (uint32_t)STM32_SPI_FILLER_PATTERN;
/* Resetting TX pattern source, clearing RX sink.*/
spip->dbuf->rxsink = 0U;
spip->dbuf->txsource = (uint32_t)STM32_SPI_FILLER_PATTERN;
/* If in stopped state then enables the SPI and GPDMA clocks.*/
if (spip->state == SPI_STOP) {
@ -642,16 +673,23 @@ msg_t spi_lld_start(SPIDriver *spip) {
}
/* Configuration-specific GPDMA setup.*/
dmalbar = 0U;
dmaccr = STM32_GPDMA_CCR_PRIO((uint32_t)spip->dprio) |
STM32_GPDMA_CCR_TOIE |
STM32_GPDMA_CCR_USEIE |
STM32_GPDMA_CCR_ULEIE |
STM32_GPDMA_CCR_DTEIE |
STM32_GPDMA_CCR_TCIE;
// if (spip->config->circular) {
// dmaccr |= STM32_GPDMA_CCR_HTIE;
// }
#if SPI_SUPPORTS_CIRCULAR
dmalbar = (uint32_t)&__gpdma_base__;
osalDbgAssert((dmalbar &0xFFFFU) == 0U, "unaligned LBAR");
if (spip->config->circular) {
dmaccr |= STM32_GPDMA_CCR_HTIE;
}
#else
dmalbar = 0U;
#endif
gpdmaChannelInit(spip->dmarx, dmalbar, dmaccr);
gpdmaChannelSetSource(spip->dmarx, &spip->spi->RXDR);
gpdmaChannelInit(spip->dmatx, dmalbar, dmaccr);
@ -809,7 +847,7 @@ msg_t spi_lld_ignore(SPIDriver *spip, size_t n) {
osalDbgAssert(n <= STM32_GPDMA_MAX_TRANSFER, "unsupported GPDMA transfer size");
/* Setting up RX DMA channel.*/
gpdmaChannelSetDestination(spip->dmarx, &spip->rxsink);
gpdmaChannelSetDestination(spip->dmarx, &spip->dbuf->rxsink);
gpdmaChannelTransactionSize(spip->dmarx, n);
gpdmaChannelSetMode(spip->dmarx,
(spip->config->dtr1rx |
@ -820,7 +858,7 @@ msg_t spi_lld_ignore(SPIDriver *spip, size_t n) {
gpdmaChannelEnable(spip->dmarx);
/* Setting up TX DMA channel.*/
gpdmaChannelSetSource(spip->dmatx, &spip->txsource);
gpdmaChannelSetSource(spip->dmatx, &spip->dbuf->txsource);
gpdmaChannelTransactionSize(spip->dmatx, n);
gpdmaChannelSetMode(spip->dmatx,
(spip->config->dtr1tx |
@ -854,11 +892,33 @@ msg_t spi_lld_ignore(SPIDriver *spip, size_t n) {
*/
msg_t spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
uint32_t llrrx, llrtx;
osalDbgAssert(n <= STM32_GPDMA_CCR_PRIO_POS, "unsupported GPDMA transfer size");
/* Setting up RX DMA channel.*/
#if SPI_SUPPORTS_CIRCULAR
if (spip->config->circular) {
/* It is a circular operation, using the linking mechanism to reload
source/destination pointers.*/
llrrx = STM32_GPDMA_CLLR_UDA | (((uint32_t)&spip->dbuf->rxdar) & 0xFFFFU);
spip->dbuf->rxdar = (uint32_t)rxbuf;
llrtx = STM32_GPDMA_CLLR_USA | (((uint32_t)&spip->dbuf->txsar) & 0xFFFFU);
spip->dbuf->txsar = (uint32_t)txbuf;
}
else {
llrrx = 0U;
llrtx = 0U;
gpdmaChannelSetDestination(spip->dmarx, rxbuf);
gpdmaChannelSetSource(spip->dmatx, txbuf);
}
#else
llrrx = 0U;
llrtx = 0U;
gpdmaChannelSetDestination(spip->dmarx, rxbuf);
gpdmaChannelSetSource(spip->dmatx, txbuf);
#endif
/* Setting up RX DMA channel.*/
gpdmaChannelTransactionSize(spip->dmarx, n);
gpdmaChannelSetMode(spip->dmarx,
(spip->config->dtr1rx |
@ -866,11 +926,10 @@ msg_t spi_lld_exchange(SPIDriver *spip, size_t n,
STM32_GPDMA_CTR1_DINC),
(spip->config->dtr2rx |
STM32_GPDMA_CTR2_REQSEL(spip->dreqrx)),
0U);
llrrx);
gpdmaChannelEnable(spip->dmarx);
/* Setting up TX DMA channel.*/
gpdmaChannelSetSource(spip->dmatx, txbuf);
gpdmaChannelTransactionSize(spip->dmatx, n);
gpdmaChannelSetMode(spip->dmatx,
(spip->config->dtr1tx |
@ -879,7 +938,7 @@ msg_t spi_lld_exchange(SPIDriver *spip, size_t n,
(spip->config->dtr2tx |
STM32_GPDMA_CTR2_REQSEL(spip->dreqtx) |
STM32_GPDMA_CTR2_DREQ),
0U);
llrtx);
gpdmaChannelEnable(spip->dmatx);
spi_lld_resume(spip);
@ -906,7 +965,7 @@ msg_t spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
osalDbgAssert(n <= STM32_GPDMA_CCR_PRIO_POS, "unsupported GPDMA transfer size");
/* Setting up RX DMA channel.*/
gpdmaChannelSetDestination(spip->dmarx, &spip->rxsink);
gpdmaChannelSetDestination(spip->dmarx, &spip->dbuf->rxsink);
gpdmaChannelTransactionSize(spip->dmarx, n);
gpdmaChannelSetMode(spip->dmarx,
(spip->config->dtr1rx |
@ -966,7 +1025,7 @@ msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
gpdmaChannelEnable(spip->dmarx);
/* Setting up TX DMA channel.*/
gpdmaChannelSetSource(spip->dmatx, &spip->txsource);
gpdmaChannelSetSource(spip->dmatx, &spip->dbuf->txsource);
gpdmaChannelTransactionSize(spip->dmatx, n);
gpdmaChannelSetMode(spip->dmatx,
(spip->config->dtr1tx |

View File

@ -31,15 +31,23 @@
/* Driver constants. */
/*===========================================================================*/
#if !defined(__SPI_DISABLE_CIRCULAR)
/**
* @brief Circular mode support flag.
*/
#define SPI_SUPPORTS_CIRCULAR TRUE
#else
#define SPI_SUPPORTS_CIRCULAR FALSE
#endif
#if !defined(__SPI_DISABLE_SLAVE)
/**
* @brief Slave mode support flag.
*/
#define SPI_SUPPORTS_SLAVE_MODE TRUE
#else
#define SPI_SUPPORTS_SLAVE_MODE FALSE
#endif
/**
* @name Register helpers not found in ST headers
@ -449,6 +457,30 @@
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure containin DMA-accessible driver fields.
*/
typedef struct spi_dmabuf {
/**
* @brief Sink for discarded data.
*/
uint32_t rxsink;
/**
* @brief Source for default TX pattern.
*/
uint32_t txsource;
#if SPI_SUPPORTS_CIRCULAR || defined(__DOXYGEN__)
/**
* @brief GPDMA link structure for circular mode RX channel.
*/
uint32_t rxdar;
/**
* @brief GPDMA link structure for circular mode TX channel.
*/
uint32_t txsar;
#endif
} spi_dmabuf_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
@ -470,10 +502,8 @@
uint32_t dtr1rx; \
/* DMA TX settings.*/ \
uint32_t dtr1tx; \
/* Sink for discarded data.*/ \
uint32_t rxsink; \
/* Source for default TX pattern.*/ \
uint32_t txsource
/* DMA buffers.*/ \
spi_dmabuf_t *dbuf
/**
* @brief Low level fields of the SPI configuration structure.