diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 334498b0731..7c0de629a32 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -5473,6 +5473,12 @@ config STM32L4_DAC2_OUTPUT_ADC ---help--- Route DAC2 output to ADC input instead of external pin. +config STM32L4_DAC_LL_OPS + bool "DAC low-level operations" + default n + ---help--- + Enable low-level DAC ops. + endmenu menu "DFSDM Configuration" diff --git a/arch/arm/src/stm32l4/stm32l4_dac.c b/arch/arm/src/stm32l4/stm32l4_dac.c index b58db4ac9dd..088bda79c1c 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.c +++ b/arch/arm/src/stm32l4/stm32l4_dac.c @@ -305,6 +305,9 @@ struct stm32_dac_s struct stm32_chan_s { +#ifdef CONFIG_STM32L4_DAC_LL_OPS + const struct stm32_dac_ops_s *llops; /* Low-level DAC ops */ +#endif uint8_t inuse : 1; /* True, the driver is in use and not available */ #ifdef HAVE_DMA uint8_t hasdma : 1; /* True, this channel supports DMA */ @@ -333,6 +336,9 @@ struct stm32_chan_s /* DAC Register access */ +static uint32_t dac_getreg(struct stm32_chan_s *priv, int offset); +static void dac_dumpregs(struct stm32_chan_s *priv); + #ifdef HAVE_DMA static inline void tim_putreg(struct stm32_chan_s *chan, int offset, uint32_t value); @@ -357,6 +363,16 @@ static int dac_timinit(struct stm32_chan_s *chan); static int dac_chaninit(struct stm32_chan_s *chan); static void dac_blockinit(void); +#ifdef CONFIG_STM32L4_DAC_LL_OPS +static void dac_llops_enable(struct stm32_dac_dev_s *dev, bool enabled); +static void dac_llops_writedro(struct stm32_dac_dev_s *dev, uint16_t data); +#ifdef HAVE_DMA +static void dac_llops_startdma(struct stm32_dac_dev_s *dev); +static void dac_llops_stopdma(struct stm32_dac_dev_s *dev); +#endif +static void dac_llops_dumpregs(struct stm32_dac_dev_s *dev); +#endif /* CONFIG_STM32L4_DAC_LL_OPS */ + /**************************************************************************** * Private Data ****************************************************************************/ @@ -371,6 +387,21 @@ static const struct dac_ops_s g_dacops = .ao_ioctl = dac_ioctl, }; +/* Publicly visible DAC lower-half operations */ + +#ifdef CONFIG_STM32L4_DAC_LL_OPS +static const struct stm32_dac_ops_s g_dac_llops = +{ + .enable = dac_llops_enable, + .write_dro = dac_llops_writedro, +#ifdef HAVE_DMA + .start_dma = dac_llops_startdma, + .stop_dma = dac_llops_stopdma, +#endif + .dump_regs = dac_llops_dumpregs +}; +#endif /* CONFIG_STM32L4_DAC_LL_OPS */ + #ifdef CONFIG_STM32L4_DAC1 /* Channel 1 */ @@ -380,6 +411,9 @@ uint16_t stm32l4_dac1_dmabuffer[CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE]; static struct stm32_chan_s g_dac1priv = { +#ifdef CONFIG_STM32L4_DAC_LL_OPS + .llops = &g_dac_llops, +#endif .intf = 0, #ifdef CONFIG_STM32L4_DAC1_OUTPUT_ADC .pin = 0xffffffffu, @@ -417,6 +451,9 @@ uint16_t stm32l4_dac2_dmabuffer[CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE]; static struct stm32_chan_s g_dac2priv = { +#ifdef CONFIG_STM32L4_DAC_LL_OPS + .llops = &g_dac_llops, +#endif .intf = 1, #ifdef CONFIG_STM32L4_DAC2_OUTPUT_ADC .pin = 0xffffffffu, @@ -451,6 +488,26 @@ static struct stm32_dac_s g_dacblock; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: dac_getreg + * + * Description: + * Read the value of an DAC register. + * + * Input Parameters: + * priv - A reference to the DAC block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint32_t dac_getreg(struct stm32_chan_s *priv, int offset) +{ + return getreg32(STM32L4_DAC_BASE + offset); +} + /**************************************************************************** * Name: stm32l4_dac_modify_cr * @@ -519,6 +576,22 @@ static inline void stm32l4_dac_modify_mcr(struct stm32_chan_s *chan, modifyreg32(STM32L4_DAC_MCR, clearbits << shift, setbits << shift); } +/**************************************************************************** + * Name: dac_dumpregs + ****************************************************************************/ + +static void dac_dumpregs(struct stm32_chan_s *priv) +{ + UNUSED(priv); + + ainfo("CR: 0x%08" PRIx32 " SWTRGR: 0x%08" PRIx32 + "SR: 0x%08" PRIx32 " MCR: 0x%08" PRIx32 "\n", + dac_getreg(priv, STM32L4_DAC_CR_OFFSET), + dac_getreg(priv, STM32L4_DAC_SWTRIGR_OFFSET), + dac_getreg(priv, STM32L4_DAC_SR_OFFSET), + dac_getreg(priv, STM32L4_DAC_MCR_OFFSET)); +} + /**************************************************************************** * Name: tim_putreg * @@ -1140,6 +1213,112 @@ static void dac_blockinit(void) g_dacblock.init = 1; } +#ifdef CONFIG_STM32L4_DAC_LL_OPS + +/**************************************************************************** + * Name: dac_llops_enable + ****************************************************************************/ + +static void dac_llops_enable(struct stm32_dac_dev_s *dev, bool enabled) +{ + struct stm32_chan_s *priv = (struct stm32_chan_s *)dev; + + /* Enable/disable DAC Channel */ + + if (enabled) + { + stm32l4_dac_modify_cr(priv, 0, DAC_CR_EN); + } + else + { + stm32l4_dac_modify_cr(priv, DAC_CR_EN, 0); + } +} + +/**************************************************************************** + * Name: dac_llops_writedro + ****************************************************************************/ + +static void dac_llops_writedro(struct stm32_dac_dev_s *dev, uint16_t data) +{ + struct stm32_chan_s *priv = (struct stm32_chan_s *)dev; + + putreg16(data, priv->dro); +} + +/**************************************************************************** + * Name: dac_llops_startdma + ****************************************************************************/ +#ifdef HAVE_DMA +static void dac_llops_startdma(struct stm32_dac_dev_s *dev) +{ + struct stm32_chan_s *priv = (struct stm32_chan_s *)dev; + + /* Configure the DMA stream/channel. + * + * - Channel number + * - Peripheral address + * - Direction: Memory to peripheral + * - Disable peripheral address increment + * - Enable memory address increment + * - Peripheral data size: half word + * - Mode: circular??? + * - Priority: ? + * - FIFO mode: disable + * - FIFO threshold: half full + * - Memory Burst: single + * - Peripheral Burst: single + */ + + stm32l4_dmasetup(priv->dma, priv->dro, (uint32_t)priv->dmabuffer, + priv->buffer_len, DAC_DMA_CONTROL_WORD); + + /* Start the DMA */ + + priv->result = -EBUSY; + stm32l4_dmastart(priv->dma, dac_dmatxcallback, priv, false); + + /* Enable DMA for DAC Channel */ + + stm32l4_dac_modify_cr(priv, 0, DAC_CR_DMAEN); + + /* Reset counters (generate an update) */ + + tim_modifyreg(priv, STM32L4_GTIM_EGR_OFFSET, 0, GTIM_EGR_UG); +} + +/**************************************************************************** + * Name: dac_llops_stopdma + ****************************************************************************/ + +static void dac_llops_stopdma(struct stm32_dac_dev_s *dev) +{ + struct stm32_chan_s *priv = (struct stm32_chan_s *)dev; + + /* Stop the DMA */ + + priv->result = -EBUSY; + stm32l4_dmastop(priv->dma); + + /* Enable DMA for DAC Channel */ + + stm32l4_dac_modify_cr(priv, 0, DAC_CR_DMAEN); +} +#endif + +/**************************************************************************** + * Name: adc_llops_dumpregs + ****************************************************************************/ + +static void dac_llops_dumpregs(struct stm32_dac_dev_s *dev) +{ + struct stm32_chan_s *priv = (struct stm32_chan_s *)dev; + + dac_dumpregs(priv); +} + +#endif /* CONFIG_STM32L4_DAC_LL_OPS */ + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/arch/arm/src/stm32l4/stm32l4_dac.h b/arch/arm/src/stm32l4/stm32l4_dac.h index 1f81fdc97b7..f8421d4d6ea 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.h +++ b/arch/arm/src/stm32l4/stm32l4_dac.h @@ -78,6 +78,65 @@ # undef CONFIG_STM32L4_TIM17_DAC #endif +/* Low-level ops helpers ****************************************************/ + +#define DAC_ENABLE(dac,d) \ + (dac)->llops->enable(dac,d) +#define DAC_WRITE_DRO(dac,d) \ + (dac)->llops->write_dro(dac,d) +#define DAC_START_DMA(dac) \ + (dac)->llops->start_dma(dac) +#define DAC_STOP_DMA(dac) \ + (dac)->llops->stop_dma(dac) +#define DAC_DUMP_REGS(dac) \ + (dac)->llops->dump_regs(dac) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_STM32L4_DAC_LL_OPS + +/* This structure provides the publicly visible representation of the + * "lower-half" DAC driver structure. + */ + +struct stm32_dac_dev_s +{ + /* Publicly visible portion of the "lower-half" ADC driver structure */ + + const struct stm32_dac_ops_s *llops; + + /* Require cast-compatibility with private "lower-half" ADC structure */ +}; + +/* Low-level operations for DAC */ + +struct stm32_dac_ops_s +{ + /* Enable / Disable DAC */ + + void (*enable)(struct stm32_dac_dev_s *dev, bool enabled); + + /* Write DRO */ + + void (*write_dro)(struct stm32_dac_dev_s *dev, uint16_t data); + + /* Start DMA */ + + void (*start_dma)(struct stm32_dac_dev_s *dev); + + /* Stop DMA */ + + void (*stop_dma)(struct stm32_dac_dev_s *dev); + + /* Dump DAC regs */ + + void (*dump_regs)(struct stm32_dac_dev_s *dev); +}; + +#endif /* CONFIG_STM32L4_DAC_LL_OPS */ + /**************************************************************************** * Public Data ****************************************************************************/