drivers/i2s_ll_stm32.c: (FIX) use dma_reload() to re-start the DMA

Fix issue #14618.
The I2S controller may generate an underrun/overrun error whenever
the current sample in the Data Register (DR) has not been read/written
yet when a new one needs to be sent/received. When the DMA operation
is completed there is no much time to re-enable it for a new
transfer. For example, in the case of a PDM microphone clocked at
2MHz we only have 8us to re-program the DMA to receive the new 16-bit
sample.

Doing a complete DMA configuration using the dma_config() API is an
operation that is consuming too much time and driver is close to the
limit. Instead, the dma_reload() routine only programs the minimum
needed information (src, dst, len) for the  new transfer in order
to restart the DMA.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2019-03-18 13:16:48 +01:00 committed by Kumar Gala
commit 455829248f

View file

@ -421,6 +421,23 @@ static const struct i2s_driver_api i2s_stm32_driver_api = {
static struct device *active_dma_rx_channel[STM32_DMA_NUM_CHANNELS];
static struct device *active_dma_tx_channel[STM32_DMA_NUM_CHANNELS];
static int reload_dma(struct device *dev_dma, u32_t channel,
struct dma_config *dcfg, void *src, void *dst,
u32_t blk_size)
{
int ret;
ret = dma_reload(dev_dma, channel, (u32_t)src, (u32_t)dst,
blk_size / sizeof(u16_t));
if (ret < 0) {
return ret;
}
ret = dma_start(dev_dma, channel);
return ret;
}
static int start_dma(struct device *dev_dma, u32_t channel,
struct dma_config *dcfg, void *src, void *dst,
u32_t blk_size)
@ -483,7 +500,7 @@ static void dma_rx_callback(void *arg, u32_t channel, int status)
goto rx_disable;
}
ret = start_dma(dev_data->dev_dma, stream->dma_channel,
ret = reload_dma(dev_data->dev_dma, stream->dma_channel,
&stream->dma_cfg,
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),
stream->mem_block,
@ -566,7 +583,7 @@ static void dma_tx_callback(void *arg, u32_t channel, int status)
/* Assure cache coherency before DMA read operation */
DCACHE_CLEAN(stream->mem_block, mem_block_size);
ret = start_dma(dev_data->dev_dma, stream->dma_channel,
ret = reload_dma(dev_data->dev_dma, stream->dma_channel,
&stream->dma_cfg,
stream->mem_block,
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),