STM32L4 DAC: report transfer as completed in DMA callback. Without this even O_NONBLOCK writes block the calling task if DAC was using DMA.

This commit is contained in:
Juha Niskanen 2017-08-25 07:05:11 -06:00 committed by Gregory Nutt
parent 874947d7e5
commit 1152e4868b
2 changed files with 73 additions and 43 deletions

View File

@ -3249,7 +3249,9 @@ config STM32L4_DAC1_TIMER
config STM32L4_DAC1_TIMER_FREQUENCY config STM32L4_DAC1_TIMER_FREQUENCY
int "DAC1 timer frequency" int "DAC1 timer frequency"
default 0 default 100
---help---
DAC1 output frequency. Default: 100Hz
endif endif
@ -3272,7 +3274,9 @@ config STM32L4_DAC2_TIMER
config STM32L4_DAC2_TIMER_FREQUENCY config STM32L4_DAC2_TIMER_FREQUENCY
int "DAC2 timer frequency" int "DAC2 timer frequency"
default 0 default 100
---help---
DAC2 output frequency. Default: 100Hz
endif endif

View File

@ -103,11 +103,12 @@
#ifdef CONFIG_STM32L4_DAC1_DMA #ifdef CONFIG_STM32L4_DAC1_DMA
# if !defined(CONFIG_STM32L4_DAC1_TIMER) # if !defined(CONFIG_STM32L4_DAC1_TIMER)
# warning "A timer number must be specificed in CONFIG_STM32L4_DAC1_TIMER" # warning "A timer number must be specified in CONFIG_STM32L4_DAC1_TIMER"
# undef CONFIG_STM32L4_DAC1_DMA # undef CONFIG_STM32L4_DAC1_DMA
# undef CONFIG_STM32L4_DAC1_TIMER_FREQUENCY # undef CONFIG_STM32L4_DAC1_TIMER_FREQUENCY
# elif !defined(CONFIG_STM32L4_DAC1_TIMER_FREQUENCY) # elif !defined(CONFIG_STM32L4_DAC1_TIMER_FREQUENCY) || \
# warning "A timer frequency must be specificed in CONFIG_STM32L4_DAC1_TIMER_FREQUENCY" (CONFIG_STM32L4_DAC1_TIMER_FREQUENCY < 1)
# warning "A timer frequency (>0) must be specified in CONFIG_STM32L4_DAC1_TIMER_FREQUENCY"
# undef CONFIG_STM32L4_DAC1_DMA # undef CONFIG_STM32L4_DAC1_DMA
# undef CONFIG_STM32L4_DAC1_TIMER # undef CONFIG_STM32L4_DAC1_TIMER
# endif # endif
@ -115,11 +116,12 @@
#ifdef CONFIG_STM32L4_DAC2_DMA #ifdef CONFIG_STM32L4_DAC2_DMA
# if !defined(CONFIG_STM32L4_DAC2_TIMER) # if !defined(CONFIG_STM32L4_DAC2_TIMER)
# warning "A timer number must be specificed in CONFIG_STM32L4_DAC2_TIMER" # warning "A timer number must be specified in CONFIG_STM32L4_DAC2_TIMER"
# undef CONFIG_STM32L4_DAC2_DMA # undef CONFIG_STM32L4_DAC2_DMA
# undef CONFIG_STM32L4_DAC2_TIMER_FREQUENCY # undef CONFIG_STM32L4_DAC2_TIMER_FREQUENCY
# elif !defined(CONFIG_STM32L4_DAC2_TIMER_FREQUENCY) # elif !defined(CONFIG_STM32L4_DAC2_TIMER_FREQUENCY) || \
# warning "A timer frequency must be specificed in CONFIG_STM32L4_DAC2_TIMER_FREQUENCY" (CONFIG_STM32L4_DAC2_TIMER_FREQUENCY < 1)
# warning "A timer frequency (>0) must be specified in CONFIG_STM32L4_DAC2_TIMER_FREQUENCY"
# undef CONFIG_STM32L4_DAC2_DMA # undef CONFIG_STM32L4_DAC2_DMA
# undef CONFIG_STM32L4_DAC2_TIMER # undef CONFIG_STM32L4_DAC2_TIMER
# endif # endif
@ -269,7 +271,7 @@
#endif #endif
/* Calculate timer divider values based upon DACn_TIMER_PCLK_FREQUENCY and /* Calculate timer divider values based upon DACn_TIMER_PCLK_FREQUENCY and
* CONFIG_STM32_DACn_TIMER_FREQUENCY. * CONFIG_STM32L4_DACn_TIMER_FREQUENCY.
*/ */
#warning "Missing Logic" #warning "Missing Logic"
@ -312,6 +314,7 @@ struct stm32_chan_s
DMA_HANDLE dma; /* Allocated DMA channel */ DMA_HANDLE dma; /* Allocated DMA channel */
uint32_t tbase; /* Timer base address */ uint32_t tbase; /* Timer base address */
uint32_t tfrequency; /* Timer frequency */ uint32_t tfrequency; /* Timer frequency */
int result; /* DMA result */
uint16_t dmabuffer[CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE]; /* DMA transfer buffer */ uint16_t dmabuffer[CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE]; /* DMA transfer buffer */
#endif #endif
}; };
@ -323,9 +326,10 @@ struct stm32_chan_s
/* DAC Register access */ /* DAC Register access */
#ifdef HAVE_DMA #ifdef HAVE_DMA
static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset); static inline void tim_putreg(FAR struct stm32_chan_s *chan, int offset,
static void tim_putreg(FAR struct stm32_chan_s *chan, int offset,
uint32_t value); uint32_t value);
static inline void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset,
uint32_t clearbits, uint32_t setbits);
#endif #endif
/* DAC methods */ /* DAC methods */
@ -457,7 +461,7 @@ static struct stm32_dac_s g_dacblock;
* Modify the contents of the DAC control register. * Modify the contents of the DAC control register.
* *
* Input Parameters: * Input Parameters:
* priv - Driver state instance * chan - A reference to the DAC channel state data
* clearbits - Bits in the control register to be cleared * clearbits - Bits in the control register to be cleared
* setbits - Bits in the control register to be set * setbits - Bits in the control register to be set
* *
@ -484,28 +488,6 @@ static inline void stm32l4_dac_modify_cr(FAR struct stm32_chan_s *chan,
modifyreg32(chan->cr, clearbits << shift, setbits << shift); modifyreg32(chan->cr, clearbits << shift, setbits << shift);
} }
/****************************************************************************
* Name: tim_getreg
*
* Description:
* Read the value of an DMA timer register.
*
* Input Parameters:
* chan - A reference to the DAC block status
* offset - The offset to the register to read
*
* Returned Value:
* The current contents of the specified register
*
****************************************************************************/
#ifdef HAVE_DMA
static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset)
{
return getreg32(chan->tbase + offset);
}
#endif
/**************************************************************************** /****************************************************************************
* Name: tim_putreg * Name: tim_putreg
* *
@ -513,7 +495,7 @@ static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset)
* Read the value of an DMA timer register. * Read the value of an DMA timer register.
* *
* Input Parameters: * Input Parameters:
* chan - A reference to the DAC block status * chan - A reference to the DAC channel state data
* offset - The offset to the register to read * offset - The offset to the register to read
* *
* Returned Value: * Returned Value:
@ -522,7 +504,7 @@ static uint32_t tim_getreg(FAR struct stm32_chan_s *chan, int offset)
****************************************************************************/ ****************************************************************************/
#ifdef HAVE_DMA #ifdef HAVE_DMA
static void tim_putreg(FAR struct stm32_chan_s *chan, int offset, static inline void tim_putreg(FAR struct stm32_chan_s *chan, int offset,
uint32_t value) uint32_t value)
{ {
putreg32(value, chan->tbase + offset); putreg32(value, chan->tbase + offset);
@ -536,7 +518,7 @@ static void tim_putreg(FAR struct stm32_chan_s *chan, int offset,
* Modify the value of an DMA timer register. * Modify the value of an DMA timer register.
* *
* Input Parameters: * Input Parameters:
* priv - Driver state instance * chan - A reference to the DAC channel state data
* offset - The timer register offset * offset - The timer register offset
* clearbits - Bits in the control register to be cleared * clearbits - Bits in the control register to be cleared
* setbits - Bits in the control register to be set * setbits - Bits in the control register to be set
@ -547,7 +529,7 @@ static void tim_putreg(FAR struct stm32_chan_s *chan, int offset,
****************************************************************************/ ****************************************************************************/
#ifdef HAVE_DMA #ifdef HAVE_DMA
static void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset, static inline void tim_modifyreg(FAR struct stm32_chan_s *chan, int offset,
uint32_t clearbits, uint32_t setbits) uint32_t clearbits, uint32_t setbits)
{ {
modifyreg32(chan->tbase + offset, clearbits, setbits); modifyreg32(chan->tbase + offset, clearbits, setbits);
@ -659,6 +641,48 @@ static void dac_txint(FAR struct dac_dev_s *dev, bool enable)
#ifdef HAVE_DMA #ifdef HAVE_DMA
static void dac_dmatxcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) static void dac_dmatxcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg)
{ {
struct stm32_chan_s *chan = (struct stm32_chan_s *)arg;
struct dac_dev_s *dev;
DEBUGASSERT(chan);
#ifdef CONFIG_STM32L4_DAC1
if (chan->intf == 0)
{
dev = &g_dac1dev;
}
#if STM32L4_NDAC > 1
else if (chan->intf == 1)
{
dev = &g_dac2dev;
}
#endif
else
#endif /* CONFIG_STM32L4_DAC1 */
#ifdef CONFIG_STM32L4_DAC2
if (chan->intf == 2)
{
dev = &g_dac3dev;
}
else
#endif
{
DEBUGPANIC();
}
DEBUGASSERT(dev->ad_priv == chan);
/* Report the result of the transfer only if the TX callback has not already
* reported an error.
*/
if (chan->result == -EBUSY)
{
/* Save the result of the transfer if no error was previously reported. */
chan->result = (isr & DMA_CHAN_TEIF_BIT) ? -EIO : OK;
dac_txdone(dev);
}
} }
#endif #endif
@ -705,8 +729,9 @@ static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg)
stm32l4_dmasetup(chan->dma, chan->dro, (uint32_t)chan->dmabuffer, stm32l4_dmasetup(chan->dma, chan->dro, (uint32_t)chan->dmabuffer,
CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE, DAC_DMA_CONTROL_WORD); CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE, DAC_DMA_CONTROL_WORD);
/* Enable DMA */ /* Start the DMA */
chan->result = -EBUSY;
stm32l4_dmastart(chan->dma, dac_dmatxcallback, chan, false); stm32l4_dmastart(chan->dma, dac_dmatxcallback, chan, false);
/* Enable DMA for DAC Channel */ /* Enable DMA for DAC Channel */
@ -777,7 +802,7 @@ static int dac_timinit(FAR struct stm32_chan_s *chan)
* counter mode (up). * counter mode (up).
*/ */
/* Enable the timer. At most, two of the following cases (pluse the /* Enable the timer. At most, two of the following cases (plus the
* default) will be enabled * default) will be enabled
*/ */
@ -1004,6 +1029,7 @@ static int dac_chaninit(FAR struct stm32_chan_s *chan)
if (ret < 0) if (ret < 0)
{ {
aerr("ERROR: Failed to initialize the DMA timer: %d\n", ret); aerr("ERROR: Failed to initialize the DMA timer: %d\n", ret);
stm32l4_dmafree(chan->dma);
return ret; return ret;
} }
} }