The attached .patch implements DMA support for the stm32f4 I2C. Max and I have verified that it works on our systems.

This commit is contained in:
rg 2017-03-21 16:44:11 -06:00 committed by Gregory Nutt
parent 9919e33705
commit 82a5dfddb4
2 changed files with 332 additions and 25 deletions

View File

@ -6190,6 +6190,16 @@ config STM32_I2C_DUTY16_9
default n default n
depends on STM32_I2C depends on STM32_I2C
config STM32_I2C_DMA
bool "I2C DMA Support"
default n
depends on STM32_I2C && STM32_STM32F40XX && STM32_DMA1
---help---
This option enables the DMA for I2C transfers.
Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value for the
I2C dma streams, else the default priority level is set to medium.
Note: This option is compatible with CONFIG_I2C_POLLED.
endmenu endmenu
menu "SDIO Configuration" menu "SDIO Configuration"

View File

@ -63,7 +63,6 @@
* - 1 x 10 bit addresses + 1 x 7 bit address (?) * - 1 x 10 bit addresses + 1 x 7 bit address (?)
* - plus the broadcast address (general call) * - plus the broadcast address (general call)
* - Multi-master support * - Multi-master support
* - DMA (to get rid of too many CPU wake-ups and interventions)
* - Be ready for IPMI * - Be ready for IPMI
*/ */
@ -95,6 +94,7 @@
#include "stm32_rcc.h" #include "stm32_rcc.h"
#include "stm32_i2c.h" #include "stm32_i2c.h"
#include "stm32_waste.h" #include "stm32_waste.h"
#include "stm32_dma.h"
/* At least one I2C peripheral must be enabled */ /* At least one I2C peripheral must be enabled */
@ -162,6 +162,21 @@
#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) #define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT)
/* I2C DMA priority */
#ifdef CONFIG_STM32_I2C_DMA
# if defined(CONFIG_I2C_DMAPRIO)
# if (CONFIG_I2C_DMAPRIO & ~DMA_SCR_PL_MASK) != 0
# error "Illegal value for CONFIG_I2C_DMAPRIO"
# endif
# define I2C_DMA_PRIO CONFIG_I2C_DMAPRIO
# else
# define I2C_DMA_PRIO DMA_SCR_PRIMED
# endif
#endif
/* Debug ****************************************************************************/ /* Debug ****************************************************************************/
/* I2C event trace logic. NOTE: trace uses the internal, non-standard, low-level /* I2C event trace logic. NOTE: trace uses the internal, non-standard, low-level
@ -253,7 +268,7 @@ struct stm32_i2c_priv_s
struct i2c_msg_s *msgv; /* Message list */ struct i2c_msg_s *msgv; /* Message list */
uint8_t *ptr; /* Current message buffer */ uint8_t *ptr; /* Current message buffer */
uint32_t frequency; /* Current I2C frequency */ uint32_t frequency; /* Current I2C frequency */
int dcnt; /* Current message length */ volatile int dcnt; /* Current message length */
uint16_t flags; /* Current message flags */ uint16_t flags; /* Current message flags */
bool check_addr_ACK; /* Flag to signal if on next interrupt address has ACKed */ bool check_addr_ACK; /* Flag to signal if on next interrupt address has ACKed */
uint8_t total_msg_len; /* Flag to signal a short read sequence */ uint8_t total_msg_len; /* Flag to signal a short read sequence */
@ -270,6 +285,15 @@ struct stm32_i2c_priv_s
#endif #endif
uint32_t status; /* End of transfer SR2|SR1 status */ uint32_t status; /* End of transfer SR2|SR1 status */
/* I2C DMA support */
#ifdef CONFIG_STM32_I2C_DMA
DMA_HANDLE txdma; /* TX DMA handle */
DMA_HANDLE rxdma; /* RX DMA handle */
uint8_t txch; /* TX DMA channel */
uint8_t rxch; /* RX DMA channel */
#endif
}; };
/************************************************************************************ /************************************************************************************
@ -337,6 +361,13 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
static int stm32_i2c_reset(FAR struct i2c_master_s *dev); static int stm32_i2c_reset(FAR struct i2c_master_s *dev);
#endif #endif
/* DMA support */
#ifdef CONFIG_STM32_I2C_DMA
static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg);
static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg);
#endif
/************************************************************************************ /************************************************************************************
* Private Data * Private Data
************************************************************************************/ ************************************************************************************/
@ -398,7 +429,16 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv =
.ptr = NULL, .ptr = NULL,
.dcnt = 0, .dcnt = 0,
.flags = 0, .flags = 0,
.status = 0 .status = 0,
#ifdef CONFIG_STM32_I2C_DMA
# ifndef CONFIG_STM32_DMA1
# error "I2C1 enabled with DMA but corresponding DMA controller 1 is not enabled!"
# endif
/* TODO: ch for i2c 1 and 2 could be *X_2 based on stream priority */
.rxch = DMAMAP_I2C1_RX,
.txch = DMAMAP_I2C1_TX,
#endif
}; };
#endif #endif
@ -428,7 +468,14 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv =
.ptr = NULL, .ptr = NULL,
.dcnt = 0, .dcnt = 0,
.flags = 0, .flags = 0,
.status = 0 .status = 0,
#ifdef CONFIG_STM32_I2C_DMA
# ifndef CONFIG_STM32_DMA1
# error "I2C2 enabled with DMA but corresponding DMA controller 1 is not enabled!"
# endif
.rxch = DMAMAP_I2C2_RX,
.txch = DMAMAP_I2C2_TX,
#endif
}; };
#endif #endif
@ -458,7 +505,14 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv =
.ptr = NULL, .ptr = NULL,
.dcnt = 0, .dcnt = 0,
.flags = 0, .flags = 0,
.status = 0 .status = 0,
#ifdef CONFIG_STM32_I2C_DMA
# ifndef CONFIG_STM32_DMA1
# error "I2C3 enabled with DMA but corresponding DMA controller 1 is not enabled!"
# endif
.rxch = DMAMAP_I2C3_RX,
.txch = DMAMAP_I2C3_TX,
#endif
}; };
#endif #endif
@ -521,7 +575,7 @@ static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv)
{ {
while (sem_wait(&priv->sem_excl) != 0) while (sem_wait(&priv->sem_excl) != 0)
{ {
ASSERT(errno == EINTR); DEBUGASSERT(errno == EINTR);
} }
} }
@ -1185,6 +1239,12 @@ static inline void stm32_i2c_enablefsmc(uint32_t ahbenr)
static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv) static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
{ {
uint32_t status; uint32_t status;
#ifndef CONFIG_I2C_POLLED
uint32_t regval;
#endif
#ifdef CONFIG_STM32_I2C_DMA
uint16_t cr2;
#endif
i2cinfo("I2C ISR called\n"); i2cinfo("I2C ISR called\n");
@ -1228,6 +1288,23 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
* stm32_i2c_sem_waitdone() waiting process. * stm32_i2c_sem_waitdone() waiting process.
*/ */
#ifdef CONFIG_STM32_I2C_DMA
/* If ISR gets called (ex. polling mode) while DMA is still in
* progress, we should just return and let the DMA finish.
*/
cr2 = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
if ((cr2 & I2C_CR2_DMAEN) != 0)
{
#ifdef CONFIG_DEBUG_I2C_INFO
size_t left = stm32_dmaresidual(priv->rxdma);
i2cinfo("DMA in progress: %ld [bytes] remainining. Returning.\n", left);
#endif
return OK;
}
#endif
if (priv->dcnt == -1 && priv->msgc > 0) if (priv->dcnt == -1 && priv->msgc > 0)
{ {
i2cinfo("Switch to new message\n"); i2cinfo("Switch to new message\n");
@ -1484,6 +1561,46 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
/* Trace */ /* Trace */
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, 0); stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, 0);
#ifdef CONFIG_STM32_I2C_DMA
/* DMA only when not doing a short read */
i2cinfo("Starting dma transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data transfer.
* The DMAEN bit must be set in the I2C_CR2 register before the ADDR event.
*/
stm32_dmasetup(priv->rxdma, priv->config->base+STM32_I2C_DR_OFFSET,
(uint32_t) priv->ptr, priv->dcnt,
DMA_SCR_DIR_P2M |
DMA_SCR_MSIZE_8BITS |
DMA_SCR_PSIZE_8BITS |
DMA_SCR_MINC |
I2C_DMA_PRIO);
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
* used.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* The user can generate a Stop condition in the DMA Transfer Complete
* interrupt routine if enabled. This will be done in the dma rx callback
* Start DMA.
*/
stm32_dmastart(priv->rxdma, stm32_i2c_dmarxcallback, priv, false);
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
#endif
} }
} }
@ -1520,6 +1637,55 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
if (priv->dcnt >= 1) if (priv->dcnt >= 1)
{ {
#ifdef CONFIG_STM32_I2C_DMA
/* if DMA is enabled, only makes sense to make use of it for longer
than 1 B transfers.. */
if (priv->dcnt > 1)
{
i2cinfo("Starting dma transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data transfer.
* The DMAEN bit must be set in the I2C_CR2 register before the ADDR event.
*/
stm32_dmasetup(priv->txdma, priv->config->base+STM32_I2C_DR_OFFSET,
(uint32_t) priv->ptr, priv->dcnt,
DMA_SCR_DIR_M2P |
DMA_SCR_MSIZE_8BITS |
DMA_SCR_PSIZE_8BITS |
DMA_SCR_MINC |
I2C_DMA_PRIO );
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
* used.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* In the interrupt routine after the EOT interrupt, disable DMA
* requests then wait for a BTF event before programming the Stop
* condition. To do this, we'll just call the ISR again in
* dma tx callback, in which point we fall into the msgc==0 case
* which ultimately sends the stop..TODO: but we don't explicitly
* wait for BTF bit being set...
* Start DMA.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
stm32_dmastart(priv->txdma, stm32_i2c_dmatxcallback, priv, false);
}
else
#endif /* CONFIG_STM32_I2C_DMA */
{
/* Transmitting message. Send byte == write data into write register */ /* Transmitting message. Send byte == write data into write register */
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++); stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++);
@ -1528,11 +1694,10 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt); stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
priv->dcnt--; priv->dcnt--;
}
} }
else if (priv->dcnt == 0) else if (priv->dcnt == 0)
{ {
/* After last byte, check what to do based on next message flags */ /* After last byte, check what to do based on next message flags */
if (priv->msgc == 0) if (priv->msgc == 0)
@ -1678,6 +1843,7 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
stm32_i2c_traceevent(priv, I2CEVENT_READ_2, 0); stm32_i2c_traceevent(priv, I2CEVENT_READ_2, 0);
} }
#ifndef CONFIG_STM32_I2C_DMA
/* Case total message length >= 3 */ /* Case total message length >= 3 */
else if (priv->dcnt >= 4 && priv->total_msg_len >= 3) else if (priv->dcnt >= 4 && priv->total_msg_len >= 3)
@ -1757,6 +1923,7 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
priv->dcnt = -1; priv->dcnt = -1;
} }
#endif /* CONFIG_STM32_I2C_DMA */
/* Error handling for read mode */ /* Error handling for read mode */
@ -1765,7 +1932,8 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
i2cinfo("I2C read mode no correct state detected\n"); i2cinfo("I2C read mode no correct state detected\n");
i2cinfo(" state %i, dcnt=%i\n", status, priv->dcnt); i2cinfo(" state %i, dcnt=%i\n", status, priv->dcnt);
/* set condition to terminate ISR and wake waiting thread */ /* Set condition to terminate ISR and wake waiting thread */
priv->dcnt = -1; priv->dcnt = -1;
priv->msgc = 0; priv->msgc = 0;
stm32_i2c_traceevent(priv, I2CEVENT_READ_ERROR, 0); stm32_i2c_traceevent(priv, I2CEVENT_READ_ERROR, 0);
@ -1804,9 +1972,9 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
else else
{ {
#ifdef CONFIG_I2C_POLLED #ifdef CONFIG_I2C_POLLED
stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0); stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0);
#else #else
/* Read rest of the state */ /* Read rest of the state */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16); status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
@ -1814,12 +1982,12 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
i2cinfo(" No correct state detected(start bit, read or write) \n"); i2cinfo(" No correct state detected(start bit, read or write) \n");
i2cinfo(" state %i\n", status); i2cinfo(" state %i\n", status);
/* set condition to terminate ISR and wake waiting thread */ /* Set condition to terminate ISR and wake waiting thread */
priv->dcnt = -1; priv->dcnt = -1;
priv->msgc = 0; priv->msgc = 0;
stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0); stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0);
#endif #endif
} }
/* Messages handling(2/2) /* Messages handling(2/2)
@ -1842,9 +2010,9 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
priv->msgv = NULL; priv->msgv = NULL;
#ifdef CONFIG_I2C_POLLED #ifdef CONFIG_I2C_POLLED
priv->intstate = INTSTATE_DONE; priv->intstate = INTSTATE_DONE;
#else #else
/* Clear all interrupts */ /* Clear all interrupts */
uint32_t regval; uint32_t regval;
@ -1863,12 +2031,98 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
sem_post(&priv->sem_isr); sem_post(&priv->sem_isr);
priv->intstate = INTSTATE_DONE; priv->intstate = INTSTATE_DONE;
} }
#endif #endif
} }
return OK; return OK;
} }
/*****************************************************************************
* Name: stm32_i2c_dmarxcallback
*
* Description:
* Called when the RX DMA completes
*
*****************************************************************************/
#ifdef CONFIG_STM32_I2C_DMA
static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
{
#ifndef CONFIG_I2C_POLLED
uint32_t regval;
#endif
i2cinfo("DMA rx callback, status = %d \n", status);
FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)arg;
priv->dcnt = -1;
/* The user can generate a Stop condition in the DMA Transfer Complete
* interrupt routine if enabled.
*/
stm32_i2c_sendstop(priv);
/* Let the I2C periph know to stop DMA transfers, also is used by ISR to check
* if DMA is done.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Re-enable interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval |= (I2C_CR2_ITERREN | I2C_CR2_ITEVFEN);
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* let the ISR routine take care of shutting down or switching to next msg */
stm32_i2c_isr(priv);
}
#endif /* ifdef CONFIG_STM32_I2C_DMA */
/*****************************************************************************
* Name: stm32_i2c_dmarxcallback
*
* Description:
* Called when the RX DMA completes
*
*****************************************************************************/
#ifdef CONFIG_STM32_I2C_DMA
static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
{
#ifndef CONFIG_I2C_POLLED
uint32_t regval;
#endif
i2cinfo("DMA tx callback, status = %d \n", status);
FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)arg;
priv->dcnt = 0;
/* In the interrupt routine after the EOT interrupt, disable DMA requests */
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
#ifndef CONFIG_I2C_POLLED
/* re-enable interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval |= (I2C_CR2_ITERREN | I2C_CR2_ITEVFEN);
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* let the ISR routine take care of shutting down or switching to next msg */
stm32_i2c_isr(priv);
}
#endif /* ifdef CONFIG_STM32_I2C_DMA */
/************************************************************************************ /************************************************************************************
* Name: stm32_i2c1_isr * Name: stm32_i2c1_isr
* *
@ -1914,7 +2168,7 @@ static int stm32_i2c3_isr(int irq, void *context, FAR void *arg)
return stm32_i2c_isr(&stm32_i2c3_priv); return stm32_i2c_isr(&stm32_i2c3_priv);
} }
#endif #endif
#endif #endif /* CONFIG_I2C_POLLED */
/************************************************************************************ /************************************************************************************
* Private Initialization and Deinitialization * Private Initialization and Deinitialization
@ -1972,6 +2226,15 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
stm32_i2c_setclock(priv, 100000); stm32_i2c_setclock(priv, 100000);
#ifdef CONFIG_STM32_I2C_DMA
/* If, in the I2C_CR2 register, the LAST bit is set, I2C automatically
* sends a NACK after the next byte following EOT_1.
* Clear DMA en just in case.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, I2C_CR2_LAST);
#endif
/* Enable I2C */ /* Enable I2C */
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE); stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE);
@ -1991,6 +2254,7 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
/* Disable I2C */ /* Disable I2C */
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, 0); stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, 0);
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, 0);
/* Unconfigure GPIO pins */ /* Unconfigure GPIO pins */
@ -2006,6 +2270,13 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
irq_detach(priv->config->er_irq); irq_detach(priv->config->er_irq);
#endif #endif
#ifdef CONFIG_STM32_I2C_DMA
/* Disable DMA */
stm32_dmastop(priv->txdma);
stm32_dmastop(priv->rxdma);
#endif
/* Disable clocking */ /* Disable clocking */
modifyreg32(STM32_RCC_APB1ENR, priv->config->clk_bit, 0); modifyreg32(STM32_RCC_APB1ENR, priv->config->clk_bit, 0);
@ -2035,7 +2306,15 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
#endif #endif
int ret = 0; int ret = 0;
ASSERT(count); DEBUGASSERT(count);
#ifdef CONFIG_STM32_I2C_DMA
/* stop DMA just in case */
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
stm32_dmastop(priv->rxdma);
stm32_dmastop(priv->txdma);
#endif
#ifdef I2C1_FSMC_CONFLICT #ifdef I2C1_FSMC_CONFLICT
/* Disable FSMC that shares a pin with I2C1 (LBAR) */ /* Disable FSMC that shares a pin with I2C1 (LBAR) */
@ -2246,11 +2525,11 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev)
uint32_t frequency; uint32_t frequency;
int ret = ERROR; int ret = ERROR;
ASSERT(dev); DEBUGASSERT(dev);
/* Our caller must own a ref */ /* Our caller must own a ref */
ASSERT(priv->refs > 0); DEBUGASSERT(priv->refs > 0);
/* Lock out other clients */ /* Lock out other clients */
@ -2412,6 +2691,19 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port)
{ {
stm32_i2c_sem_init(priv); stm32_i2c_sem_init(priv);
stm32_i2c_init(priv); stm32_i2c_init(priv);
#ifdef CONFIG_STM32_I2C_DMA
/* Get DMA channels. NOTE: stm32_dmachannel() will always assign the DMA channel.
* if the channel is not available, then stm32_dmachannel() will block and wait
* until the channel becomes available. WARNING: If you have another device sharing
* a DMA channel with SPI and the code never releases that channel, then the call
* to stm32_dmachannel() will hang forever in this function! Don't let your
* design do that!
*/
priv->rxdma = stm32_dmachannel(priv->rxch);
priv->txdma = stm32_dmachannel(priv->txch);
DEBUGASSERT(priv->rxdma && priv->txdma);
#endif /* #ifdef CONFIG_STM32_I2C_DMA */
} }
leave_critical_section(flags); leave_critical_section(flags);
@ -2431,7 +2723,7 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev; FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev;
irqstate_t flags; irqstate_t flags;
ASSERT(dev); DEBUGASSERT(dev);
/* Decrement reference count and check for underflow */ /* Decrement reference count and check for underflow */
@ -2454,6 +2746,11 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
stm32_i2c_deinit(priv); stm32_i2c_deinit(priv);
#ifdef CONFIG_STM32_I2C_DMA
stm32_dmafree(priv->rxdma);
stm32_dmafree(priv->txdma);
#endif
/* Release unused resources */ /* Release unused resources */
stm32_i2c_sem_destroy(priv); stm32_i2c_sem_destroy(priv);