diff --git a/arch/arm/src/stm32/chip/stm32_dac.h b/arch/arm/src/stm32/chip/stm32_dac.h index cd4e3ff90b7..640837404e6 100644 --- a/arch/arm/src/stm32/chip/stm32_dac.h +++ b/arch/arm/src/stm32/chip/stm32_dac.h @@ -157,7 +157,7 @@ # define DAC_CR_WAVE_TRIANGLE (2 << DAC_CR_WAVE_SHIFT) /* Triangle wave generation enabled */ #define DAC_CR_MAMP_SHIFT (8) /* Bits 8-11: DAC channel mask/amplitude selector */ #define DAC_CR_MAMP_MASK (15 << DAC_CR_MAMP_SHIFT) -# define DAC_CR_MAMP_AMP1 (0 << DAC_CR_MAMP1_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */ +# define DAC_CR_MAMP_AMP1 (0 << DAC_CR_MAMP_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */ # define DAC_CR_MAMP_AMP3 (1 << DAC_CR_MAMP_SHIFT) /* Unmask bits[1:0] of LFSR/triangle amplitude=3 */ # define DAC_CR_MAMP_AMP7 (2 << DAC_CR_MAMP_SHIFT) /* Unmask bits[2:0] of LFSR/triangle amplitude=7 */ # define DAC_CR_MAMP_AMP15 (3 << DAC_CR_MAMP_SHIFT) /* Unmask bits[3:0] of LFSR/triangle amplitude=15 */ diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 93f874342bf..f9930161486 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -3271,6 +3271,13 @@ config STM32L4_DAC1_TIMER_FREQUENCY endif +config STM32L4_DAC1_OUTPUT_ADC + bool "DAC1 output to ADC" + depends on STM32L4_DAC1 + default n + ---help--- + Route DAC1 output to ADC input instead of external pin. + config STM32L4_DAC2_DMA bool "DAC2 DMA" depends on STM32L4_DAC2 @@ -3296,8 +3303,16 @@ config STM32L4_DAC2_TIMER_FREQUENCY endif +config STM32L4_DAC2_OUTPUT_ADC + bool "DAC2 output to ADC" + depends on STM32L4_DAC2 + default n + ---help--- + Route DAC2 output to ADC input instead of external pin. + config STM32L4_DAC_DMA_BUFFER_SIZE int "DAC DMA buffer size" + depends on STM32L4_DAC1_DMA || STM32L4_DAC2_DMA default 256 endmenu diff --git a/arch/arm/src/stm32l4/chip/stm32l4_dac.h b/arch/arm/src/stm32l4/chip/stm32l4_dac.h index 3326538c6db..234bdfd2722 100644 --- a/arch/arm/src/stm32l4/chip/stm32l4_dac.h +++ b/arch/arm/src/stm32l4/chip/stm32l4_dac.h @@ -120,7 +120,7 @@ # define DAC_CR_WAVE_TRIANGLE (2 << DAC_CR_WAVE_SHIFT) /* Triangle wave generation enabled */ #define DAC_CR_MAMP_SHIFT (8) /* Bits 8-11: DAC channel mask/amplitude selector */ #define DAC_CR_MAMP_MASK (15 << DAC_CR_MAMP_SHIFT) -# define DAC_CR_MAMP_AMP1 (0 << DAC_CR_MAMP1_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */ +# define DAC_CR_MAMP_AMP1 (0 << DAC_CR_MAMP_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */ # define DAC_CR_MAMP_AMP3 (1 << DAC_CR_MAMP_SHIFT) /* Unmask bits[1:0] of LFSR/triangle amplitude=3 */ # define DAC_CR_MAMP_AMP7 (2 << DAC_CR_MAMP_SHIFT) /* Unmask bits[2:0] of LFSR/triangle amplitude=7 */ # define DAC_CR_MAMP_AMP15 (3 << DAC_CR_MAMP_SHIFT) /* Unmask bits[3:0] of LFSR/triangle amplitude=15 */ @@ -291,6 +291,16 @@ #define DAC_MCR_MODE_SHIFT(n) (((n)-1) << 4) #define DAC_MCR_MODE_MASK(n) (0x7 << DAC_MCR_MODE_SHIFT(n)) + /* DAC channel in normal mode: */ +# define DAC_MCR_MODE_EXTBUF (0) /* DAC channel connected to external pin, Buffer enabled */ +# define DAC_MCR_MODE_EXTINBUF (1) /* DAC channel connected to external pin, on-chip peripherals, Buffer enabled */ +# define DAC_MCR_MODE_EXT (2) /* DAC channel connected to external pin, Buffer disabled */ +# define DAC_MCR_MODE_IN (3) /* DAC channel connected to on-chip peripherals, Buffer disabled */ + /* DAC channel in Sample and Hold mode: */ +# define DAC_MCR_MODE_SHEXTBUF (4) /* DAC channel connected to external pin, Buffer enabled */ +# define DAC_MCR_MODE_SHEXTINBUF (5) /* DAC channel connected to external pin, on-chip peripherals, Buffer enabled */ +# define DAC_MCR_MODE_SHEXTIN (6) /* DAC channel connected to external pin, on-chip peripherals, Buffer disabled */ +# define DAC_MCR_MODE_SHIN (7) /* DAC channel connected to on-chip peripherals, Buffer disabled */ #define DAC_MCR_MODE1_SHIFT (0) /* Bits 0-2: DAC channel 1 mode */ #define DAC_MCR_MODE1_MASK (0x7 << DAC_MCR_MODE1_SHIFT) diff --git a/arch/arm/src/stm32l4/stm32l4_adc.c b/arch/arm/src/stm32l4/stm32l4_adc.c index 619e0b17c63..7abf3f41048 100644 --- a/arch/arm/src/stm32l4/stm32l4_adc.c +++ b/arch/arm/src/stm32l4/stm32l4_adc.c @@ -1253,8 +1253,9 @@ static int adc_setup(FAR struct adc_dev_s *dev) ADC_CCR_TSEN | ADC_CCR_VBATEN; setbits = ADC_CCR_PRESC_NOT_DIV; - /* REVISIT: there is no way to select DAC1 or DAC2 output here on - * STM32L4X3 devices where they are multiplexed with ADC1 TSEN and VBAT. + /* On STM32L4X3 devices DAC1 and DAC2 outputs are multiplexed with ADC1 TS and VBAT. + * adc_internal() knows about this and does not set TSEN or VBATEN bits if configuration + * has requested DAC output to be connected to ADC. */ adc_internal(priv, &setbits); @@ -1434,11 +1435,14 @@ static bool adc_internal(FAR struct stm32_dev_s * priv, uint32_t *adc_ccr) break; case 17: +#if !(defined(CONFIG_STM32L4_STM32L4X3) && defined(CONFIG_STM32L4_DAC1_OUTPUT_ADC)) *adc_ccr |= ADC_CCR_TSEN; +#endif break; - case 18: +#if !(defined(CONFIG_STM32L4_STM32L4X3) && defined(CONFIG_STM32L4_DAC2_OUTPUT_ADC)) *adc_ccr |= ADC_CCR_VBATEN; +#endif break; } } diff --git a/arch/arm/src/stm32l4/stm32l4_dac.c b/arch/arm/src/stm32l4/stm32l4_dac.c index 90971aa042b..8f15f93caa4 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.c +++ b/arch/arm/src/stm32l4/stm32l4_dac.c @@ -266,7 +266,7 @@ # define DAC2_TSEL_VALUE DAC_CR_TSEL_SW #endif -#ifndef CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE +#if !defined(CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE) || CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE < 1 # define CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE 256 #endif @@ -315,6 +315,7 @@ struct stm32_chan_s uint32_t tbase; /* Timer base address */ uint32_t tfrequency; /* Timer frequency */ int result; /* DMA result */ + uint16_t dmapos; /* Position in dmabuffer where to write new value */ uint16_t dmabuffer[CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE]; /* DMA transfer buffer */ #endif }; @@ -488,6 +489,38 @@ static inline void stm32l4_dac_modify_cr(FAR struct stm32_chan_s *chan, modifyreg32(chan->cr, clearbits << shift, setbits << shift); } +/**************************************************************************** + * Name: stm32l4_dac_modify_mcr + * + * Description: + * Modify the contents of the DAC mode register. + * + * Input Parameters: + * chan - A reference to the DAC channel state data + * clearbits - Bits in the control register to be cleared + * setbits - Bits in the control register to be set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void stm32l4_dac_modify_mcr(FAR struct stm32_chan_s *chan, + uint32_t clearbits, uint32_t setbits) +{ + unsigned int shift; + + /* DAC1 channels 1 and 2 share the STM32L4_DAC_MCR control register. + * Bit 0 of the interface number provides the correct shift. + * + * Bit 0 = 0: Shift = 0 + * Bit 0 = 1: Shift = 16 + */ + + shift = (chan->intf & 1) << 4; + modifyreg32(STM32L4_DAC_MCR, clearbits << shift, setbits << shift); +} + /**************************************************************************** * Name: tim_putreg * @@ -710,6 +743,18 @@ static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) #ifdef HAVE_DMA if (chan->hasdma) { + /* Copy the value to circular buffer. Since dmabuffer is initialized to zero, + * writing e.g. monotonously increasing values creates a continuosly repeating + * ramp-effect, alternating with periods of zero output. + * + * In real use it would be better to initialize dmabuffer with desired pattern + * beforehand. If want to write just one value at a time with DMA, set + * CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE to 1. + */ + + chan->dmabuffer[chan->dmapos] = (uint16_t)msg->am_data; + chan->dmapos = (chan->dmapos + 1) % CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE; + /* Configure the DMA stream/channel. * * - Channel number @@ -1001,7 +1046,28 @@ static int dac_chaninit(FAR struct stm32_chan_s *chan) DAC_CR_WAVE_DISABLED; /* Set no noise */ stm32l4_dac_modify_cr(chan, clearbits, setbits); - /* TODO: Enable output buffer? */ + /* Enable output buffer or route DAC output to on-chip peripherals (ADC) */ + + clearbits = DAC_MCR_MODE1_MASK; +#if defined(CONFIG_STM32L4_DAC1_OUTPUT_ADC) + if (chan->intf == 0) + { + setbits = DAC_MCR_MODE_IN; + } + else +#endif +#if defined(CONFIG_STM32L4_DAC2_OUTPUT_ADC) + if (chan->intf == 1) + { + setbits = DAC_MCR_MODE_IN; + } + else +#endif + { + setbits = DAC_MCR_MODE_EXTBUF; + } + + stm32l4_dac_modify_mcr(chan, clearbits, setbits); #ifdef HAVE_DMA /* Determine if DMA is supported by this channel */