From 402520577291c2525fbb41774ca8b4ff103e3b2a Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Tue, 29 Aug 2017 17:53:49 +0300 Subject: [PATCH 1/4] STM32L4 DAC: add option for routing DAC output to ADC Actually write something to the DAC DMA buffer. Change-Id: I1b2516ac26fb17f5242611b56be8926c5f40c2c7 Signed-off-by: Juha Niskanen --- arch/arm/src/stm32/chip/stm32_dac.h | 2 +- arch/arm/src/stm32l4/Kconfig | 15 ++++++ arch/arm/src/stm32l4/chip/stm32l4_dac.h | 12 ++++- arch/arm/src/stm32l4/stm32l4_adc.c | 10 ++-- arch/arm/src/stm32l4/stm32l4_dac.c | 70 ++++++++++++++++++++++++- 5 files changed, 102 insertions(+), 7 deletions(-) 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 */ From 0003ad171ddce1c2f7026ce4122c678ff56081f1 Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Tue, 29 Aug 2017 18:36:08 +0300 Subject: [PATCH 2/4] STM32L4 DAC: separate DMA buffer configuration for channels Change-Id: Ibc6dc90b39b784b5534b8908eaf615bf1ddcb7ed Signed-off-by: Juha Niskanen --- arch/arm/src/stm32l4/Kconfig | 17 ++++++++----- arch/arm/src/stm32l4/stm32l4_dac.c | 41 ++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index f9930161486..09a1afd6bf3 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -3254,7 +3254,7 @@ config STM32L4_DAC1_DMA ---help--- If DMA is selected, then a timer and output frequency must also be provided to support the DMA transfer. The DMA transfer could be - supported by and EXTI trigger, but this feature is not currently + supported by an EXTI trigger, but this feature is not currently supported by the driver. if STM32L4_DAC1_DMA @@ -3269,6 +3269,10 @@ config STM32L4_DAC1_TIMER_FREQUENCY ---help--- DAC1 output frequency. Default: 100Hz +config STM32L4_DAC1_DMA_BUFFER_SIZE + int "DAC1 DMA buffer size" + default 1 + endif config STM32L4_DAC1_OUTPUT_ADC @@ -3285,7 +3289,7 @@ config STM32L4_DAC2_DMA ---help--- If DMA is selected, then a timer and output frequency must also be provided to support the DMA transfer. The DMA transfer could be - supported by and EXTI trigger, but this feature is not currently + supported by an EXTI trigger, but this feature is not currently supported by the driver. if STM32L4_DAC2_DMA @@ -3301,6 +3305,10 @@ config STM32L4_DAC2_TIMER_FREQUENCY ---help--- DAC2 output frequency. Default: 100Hz +config STM32L4_DAC2_DMA_BUFFER_SIZE + int "DAC2 DMA buffer size" + default 1 + endif config STM32L4_DAC2_OUTPUT_ADC @@ -3310,11 +3318,6 @@ config STM32L4_DAC2_OUTPUT_ADC ---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 config STM32L4_HAVE_USART1 diff --git a/arch/arm/src/stm32l4/stm32l4_dac.c b/arch/arm/src/stm32l4/stm32l4_dac.c index 8f15f93caa4..90b87e7949a 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.c +++ b/arch/arm/src/stm32l4/stm32l4_dac.c @@ -95,13 +95,16 @@ # endif #endif -/* If DMA is selected, then a timer and output frequency must also be - * provided to support the DMA transfer. The DMA transfer could be - * supported by and EXTI trigger, but this feature is not currently +/* If DMA is selected, then a buffer, a timer and output frequency must + * also be provided to support the DMA transfer. The DMA transfer could be + * supported by an EXTI trigger, but this feature is not currently * supported by the driver. */ #ifdef CONFIG_STM32L4_DAC1_DMA +# if !defined(CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE) || CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE < 1 +# define CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE 1 +# endif # if !defined(CONFIG_STM32L4_DAC1_TIMER) # warning "A timer number must be specified in CONFIG_STM32L4_DAC1_TIMER" # undef CONFIG_STM32L4_DAC1_DMA @@ -115,6 +118,9 @@ #endif #ifdef CONFIG_STM32L4_DAC2_DMA +# if !defined(CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE) || CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE < 1 +# define CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE 1 +# endif # if !defined(CONFIG_STM32L4_DAC2_TIMER) # warning "A timer number must be specified in CONFIG_STM32L4_DAC2_TIMER" # undef CONFIG_STM32L4_DAC2_DMA @@ -266,10 +272,6 @@ # define DAC2_TSEL_VALUE DAC_CR_TSEL_SW #endif -#if !defined(CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE) || CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE < 1 -# define CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE 256 -#endif - /* Calculate timer divider values based upon DACn_TIMER_PCLK_FREQUENCY and * CONFIG_STM32L4_DACn_TIMER_FREQUENCY. */ @@ -311,12 +313,13 @@ struct stm32_chan_s uint32_t tsel; /* CR trigger select value */ #ifdef HAVE_DMA uint16_t dmachan; /* DMA channel needed by this DAC */ + uint16_t buffer_len; /* DMA buffer length */ DMA_HANDLE dma; /* Allocated DMA channel */ 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 */ + uint16_t buffer_pos; /* Position in dmabuffer where to write new value */ + uint16_t *dmabuffer; /* DMA transfer buffer */ #endif }; @@ -367,6 +370,10 @@ static const struct dac_ops_s g_dacops = #ifdef CONFIG_STM32L4_DAC1 /* Channel 1 */ +#ifdef CONFIG_STM32L4_DAC1_DMA +static uint16_t dac1_dmabuffer[CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE]; +#endif + static struct stm32_chan_s g_dac1priv = { .intf = 0, @@ -382,6 +389,8 @@ static struct stm32_chan_s g_dac1priv = #ifdef CONFIG_STM32L4_DAC1_DMA .hasdma = 1, .dmachan = DAC1_DMA_CHAN, + .buffer_len = CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE, + .dmabuffer = dac1_dmabuffer, .timer = CONFIG_STM32L4_DAC1_TIMER, .tsel = DAC1_TSEL_VALUE, .tbase = DAC1_TIMER_BASE, @@ -400,6 +409,10 @@ static struct dac_dev_s g_dac1dev = * the DAC1 second output channel. */ +#ifdef CONFIG_STM32L4_DAC2_DMA +static uint16_t dac2_dmabuffer[CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE]; +#endif + static struct stm32_chan_s g_dac2priv = { .intf = 1, @@ -415,6 +428,8 @@ static struct stm32_chan_s g_dac2priv = #ifdef CONFIG_STM32L4_DAC2_DMA .hasdma = 1, .dmachan = DAC2_DMA_CHAN, + .buffer_len = CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE, + .dmabuffer = dac2_dmabuffer, .timer = CONFIG_STM32L4_DAC2_TIMER, .tsel = DAC2_TSEL_VALUE, .tbase = DAC2_TIMER_BASE, @@ -749,11 +764,11 @@ static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) * * 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. + * the buffer size to 1. */ - chan->dmabuffer[chan->dmapos] = (uint16_t)msg->am_data; - chan->dmapos = (chan->dmapos + 1) % CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE; + chan->dmabuffer[chan->buffer_pos] = (uint16_t)msg->am_data; + chan->buffer_pos = (chan->buffer_pos + 1) % chan->buffer_len; /* Configure the DMA stream/channel. * @@ -772,7 +787,7 @@ 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, - CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE, DAC_DMA_CONTROL_WORD); + chan->buffer_len, DAC_DMA_CONTROL_WORD); /* Start the DMA */ From 258fa08e699d2e80cf510230b17c5e431cc45f46 Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Fri, 1 Sep 2017 09:03:11 +0300 Subject: [PATCH 3/4] STM32L4 DAC: Fix naming so that DAC1 and DAC2 always refer to channels 1 and 2 User should not be bothered by details like how many IP blocks there are. As no current STM32L4 has second DAC block (channel 3), remove support for such hypothetical hardware. DMA channels corrected. Change-Id: I2cba7e55803871f1ff945538113f12cf5088f68d Signed-off-by: Juha Niskanen --- arch/arm/src/stm32l4/Kconfig | 7 +- arch/arm/src/stm32l4/chip/stm32l4x3xx_dma.h | 6 +- arch/arm/src/stm32l4/chip/stm32l4x5xx_dma.h | 2 +- arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h | 6 +- arch/arm/src/stm32l4/stm32l4_dac.c | 207 +++++++------------- arch/arm/src/stm32l4/stm32l4_dac.h | 11 ++ 6 files changed, 96 insertions(+), 143 deletions(-) diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 09a1afd6bf3..a323f7d0bec 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -420,6 +420,7 @@ config STM32L4_STM32L431XX bool default n select STM32L4_STM32L4X1 + select STM32L4_HAVE_DAC2 select STM32L4_HAVE_TIM7 select STM32L4_HAVE_SDMMC1 if (STM32L4_IO_CONFIG_V || STM32L4_IO_CONFIG_R) @@ -427,18 +428,21 @@ config STM32L4_STM32L432XX bool default n select STM32L4_STM32L4X2 + select STM32L4_HAVE_DAC2 select STM32L4_HAVE_TIM7 config STM32L4_STM32L433XX bool default n select STM32L4_STM32L4X3 + select STM32L4_HAVE_DAC2 select STM32L4_HAVE_TIM7 config STM32L4_STM32L442XX bool default n select STM32L4_STM32L4X2 + select STM32L4_HAVE_DAC2 select STM32L4_HAVE_TIM7 select STM32L4_HAVE_AES @@ -446,6 +450,7 @@ config STM32L4_STM32L443XX bool default n select STM32L4_STM32L4X3 + select STM32L4_HAVE_DAC2 select STM32L4_HAVE_TIM7 select STM32L4_HAVE_SDMMC1 select STM32L4_HAVE_AES @@ -3245,7 +3250,7 @@ config STM32L4_ADC3_DMA endmenu menu "DAC Configuration" - depends on STM32L4_DAC1 || STM32L4_DAC2 + depends on STM32L4_DAC config STM32L4_DAC1_DMA bool "DAC1 DMA" diff --git a/arch/arm/src/stm32l4/chip/stm32l4x3xx_dma.h b/arch/arm/src/stm32l4/chip/stm32l4x3xx_dma.h index e312e0f9e8a..8723fc1c0aa 100644 --- a/arch/arm/src/stm32l4/chip/stm32l4x3xx_dma.h +++ b/arch/arm/src/stm32l4/chip/stm32l4x3xx_dma.h @@ -332,8 +332,10 @@ /* DAC */ #define DMACHAN_DAC1_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN3, 6) -#define DMACHAN_DAC1_2 DMACHAN_SETTING(STM32L4_DMA1_CHAN4, 5) -#define DMACHAN_DAC1_3 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) +#define DMACHAN_DAC1_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) + +#define DMACHAN_DAC2_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN4, 5) +#define DMACHAN_DAC2_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN5, 3) /* DCMI */ diff --git a/arch/arm/src/stm32l4/chip/stm32l4x5xx_dma.h b/arch/arm/src/stm32l4/chip/stm32l4x5xx_dma.h index 2b44d7f839c..2eceae8292e 100644 --- a/arch/arm/src/stm32l4/chip/stm32l4x5xx_dma.h +++ b/arch/arm/src/stm32l4/chip/stm32l4x5xx_dma.h @@ -331,7 +331,7 @@ /* DAC */ #define DMACHAN_DAC1_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN3, 6) -#define DMACHAN_DAC1_3 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) +#define DMACHAN_DAC1_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) #define DMACHAN_DAC2_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN4, 5) #define DMACHAN_DAC2_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN5, 3) diff --git a/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h b/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h index 8ff0edfca21..cf90c3e18dc 100644 --- a/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h +++ b/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h @@ -338,10 +338,10 @@ /* DAC */ #define DMACHAN_DAC1_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN3, 6) -#define DMACHAN_DAC1_2 DMACHAN_SETTING(STM32L4_DMA1_CHAN4, 5) -#define DMACHAN_DAC1_3 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) +#define DMACHAN_DAC1_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN4, 3) -#define DMACHAN_DAC2 DMACHAN_SETTING(STM32L4_DMA2_CHAN5, 3) +#define DMACHAN_DAC2_1 DMACHAN_SETTING(STM32L4_DMA1_CHAN4, 5) +#define DMACHAN_DAC2_2 DMACHAN_SETTING(STM32L4_DMA2_CHAN5, 3) /* DCMI */ diff --git a/arch/arm/src/stm32l4/stm32l4_dac.c b/arch/arm/src/stm32l4/stm32l4_dac.c index 90b87e7949a..36cf044a6b0 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.c +++ b/arch/arm/src/stm32l4/stm32l4_dac.c @@ -67,7 +67,11 @@ * Pre-processor Definitions ****************************************************************************/ /* Configuration ************************************************************/ -/* Up to 2 DAC interfaces for up to 3 channels are supported */ +/* Up to 1 DAC interface for up to 2 channels are supported */ + +#if STM32L4_NDAC > 2 +# warning "Extra DAC channels. Only DAC1 and DAC2 are supported" +#endif #if STM32L4_NDAC < 2 # undef CONFIG_STM32L4_DAC2 @@ -87,14 +91,6 @@ /* DMA configuration. */ -#if defined(CONFIG_STM32L4_DAC1_DMA) || defined(CONFIG_STM32L4_DAC2_DMA) -# if !defined(CONFIG_STM32L4_DMA1) -# warning "STM32L4 DAC DMA support requires CONFIG_STM32L4_DMA1" -# undef CONFIG_STM32L4_DAC1_DMA -# undef CONFIG_STM32L4_DAC2_DMA -# endif -#endif - /* If DMA is selected, then a buffer, a timer and output frequency must * also be provided to support the DMA transfer. The DMA transfer could be * supported by an EXTI trigger, but this feature is not currently @@ -133,15 +129,28 @@ # endif #endif -/* DMA *********************************************************************/ +/* Select DMA channels, favor DMA1 if configured. */ #undef HAVE_DMA -#if defined(CONFIG_STM32L4_DAC1_DMA) || defined(CONFIG_STM32L4_DAC2_DMA) -# define HAVE_DMA 1 -# define DAC_DMA 1 -# define DAC1_DMA_CHAN DMACHAN_DAC1_1 -# define DAC2_DMA_CHAN DMACHAN_DAC1_2 +#ifdef CONFIG_STM32L4_DAC1_DMA +# if defined(CONFIG_STM32L4_DMA1) +# define DAC1_DMA_CHAN DMACHAN_DAC1_1 +# elif defined(CONFIG_STM32L4_DMA2) +# define DAC1_DMA_CHAN DMACHAN_DAC1_2 +# else +# error "No DMA channel for DAC1" +# endif #endif +#ifdef CONFIG_STM32L4_DAC2_DMA +# if defined(CONFIG_STM32L4_DMA1) +# define DAC2_DMA_CHAN DMACHAN_DAC2_1 +# elif defined(CONFIG_STM32L4_DMA2) +# define DAC2_DMA_CHAN DMACHAN_DAC2_2 +# else +# error "No DMA channel for DAC2" +# endif +#endif +#define HAVE_DMA /* Timer configuration. The STM32L4 supports 8 different trigger for DAC * output: @@ -351,7 +360,7 @@ static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg); static int dac_timinit(FAR struct stm32_chan_s *chan); #endif static int dac_chaninit(FAR struct stm32_chan_s *chan); -static int dac_blockinit(void); +static void dac_blockinit(void); /**************************************************************************** * Private Data @@ -371,26 +380,20 @@ static const struct dac_ops_s g_dacops = /* Channel 1 */ #ifdef CONFIG_STM32L4_DAC1_DMA -static uint16_t dac1_dmabuffer[CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE]; +uint16_t stm32l4_dac1_dmabuffer[CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE]; #endif static struct stm32_chan_s g_dac1priv = { .intf = 0, -#if STM32L4_NDAC < 3 .pin = GPIO_DAC1_OUT, .dro = STM32L4_DAC_DHR12R1, .cr = STM32L4_DAC_CR, -#else - .pin = GPIO_DAC1_OUT1, - .dro = STM32L4_DAC1_DHR12R1, - .cr = STM32L4_DAC1_CR, -#endif #ifdef CONFIG_STM32L4_DAC1_DMA .hasdma = 1, .dmachan = DAC1_DMA_CHAN, .buffer_len = CONFIG_STM32L4_DAC1_DMA_BUFFER_SIZE, - .dmabuffer = dac1_dmabuffer, + .dmabuffer = stm32l4_dac1_dmabuffer, .timer = CONFIG_STM32L4_DAC1_TIMER, .tsel = DAC1_TSEL_VALUE, .tbase = DAC1_TIMER_BASE, @@ -404,32 +407,26 @@ static struct dac_dev_s g_dac1dev = .ad_priv = &g_dac1priv, }; -#if STM32L4_NDAC > 1 -/* Channel 2: Note that some STM32L4 chips don't have - * the DAC1 second output channel. - */ +#endif /* CONFIG_STM32L4_DAC1 */ + +#ifdef CONFIG_STM32L4_DAC2 +/* Channel 2 */ #ifdef CONFIG_STM32L4_DAC2_DMA -static uint16_t dac2_dmabuffer[CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE]; +uint16_t stm32l4_dac2_dmabuffer[CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE]; #endif static struct stm32_chan_s g_dac2priv = { .intf = 1, -#if STM32L4_NDAC < 3 .pin = GPIO_DAC2_OUT, .dro = STM32L4_DAC_DHR12R2, .cr = STM32L4_DAC_CR, -#else - .pin = GPIO_DAC1_OUT2, - .dro = STM32L4_DAC1_DHR12R2, - .cr = STM32L4_DAC1_CR, -#endif #ifdef CONFIG_STM32L4_DAC2_DMA .hasdma = 1, .dmachan = DAC2_DMA_CHAN, .buffer_len = CONFIG_STM32L4_DAC2_DMA_BUFFER_SIZE, - .dmabuffer = dac2_dmabuffer, + .dmabuffer = stm32l4_dac2_dmabuffer, .timer = CONFIG_STM32L4_DAC2_TIMER, .tsel = DAC2_TSEL_VALUE, .tbase = DAC2_TIMER_BASE, @@ -442,27 +439,8 @@ static struct dac_dev_s g_dac2dev = .ad_ops = &g_dacops, .ad_priv = &g_dac2priv, }; -#endif -#endif /* CONFIG_STM32L4_DAC1 */ - -#ifdef CONFIG_STM32L4_DAC2 -/* Channel 3: Does not actually exit in any current STM32L4 */ - -static struct stm32_chan_s g_dac3priv = -{ - .intf = 2, - .pin = GPIO_DAC2_OUT1, - .dro = STM32L4_DAC2_DHR12R1, - .cr = STM32L4_DAC2_CR, -}; - -static struct dac_dev_s g_dac3dev = -{ - .ad_ops = &g_dacops, - .ad_priv = &g_dac3priv, -}; -#endif +#endif /* CONFIG_STM32L4_DAC2 */ static struct stm32_dac_s g_dacblock; @@ -491,10 +469,10 @@ static inline void stm32l4_dac_modify_cr(FAR struct stm32_chan_s *chan, { unsigned int shift; - /* DAC1 channels 1 and 2 share the STM32L4_DAC[1]_CR control register. DAC2 - * channel 1 (and perhaps channel 2) uses the STM32L4_DAC2_CR control - * register. In either case, bit 0 of the interface number provides the - * correct shift. + /* DAC channels 1 and 2 share the STM32L4_DAC[1]_CR control register. If + * future chips have DAC channel 3 (and perhaps channel 4) they likely have + * their own register like in STM32. In either case, bit 0 of the interface + * number provides the correct shift. * * Bit 0 = 0: Shift = 0 * Bit 0 = 1: Shift = 16 @@ -525,7 +503,7 @@ static inline void stm32l4_dac_modify_mcr(FAR struct stm32_chan_s *chan, { unsigned int shift; - /* DAC1 channels 1 and 2 share the STM32L4_DAC_MCR control register. + /* DAC 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 @@ -694,28 +672,21 @@ static void dac_dmatxcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) DEBUGASSERT(chan); + switch (chan->intf) + { #ifdef CONFIG_STM32L4_DAC1 - if (chan->intf == 0) - { - dev = &g_dac1dev; - } -#if STM32L4_NDAC > 1 - else if (chan->intf == 1) - { - dev = &g_dac2dev; - } + case 0: + dev = &g_dac1dev; + break; #endif - else -#endif /* CONFIG_STM32L4_DAC1 */ #ifdef CONFIG_STM32L4_DAC2 - if (chan->intf == 2) - { - dev = &g_dac3dev; - } - else + case 1: + dev = &g_dac2dev; + break; #endif - { - DEBUGPANIC(); + default: + DEBUGPANIC(); + break; } DEBUGASSERT(dev->ad_priv == chan); @@ -762,9 +733,10 @@ static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) * 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 - * the buffer size to 1. + * In real use it the dmabuffer should be initialized with a desired pattern + * beforehand, followed by a single dummy write to initiate circular DMA. If want + * to write just one value at a time with DMA, set the buffer size to 1 (mostly + * useful for just testing the functionality). */ chan->dmabuffer[chan->buffer_pos] = (uint16_t)msg->am_data; @@ -1131,11 +1103,10 @@ static int dac_chaninit(FAR struct stm32_chan_s *chan) * Input Parameters: * * Returned Value: - * Zero on success; a negated errno value on failure. * ****************************************************************************/ -static int dac_blockinit(void) +static void dac_blockinit(void) { irqstate_t flags; uint32_t regval; @@ -1144,46 +1115,25 @@ static int dac_blockinit(void) if (g_dacblock.init) { - /* Yes.. then return success We only have to do this once */ - - return OK; + return; } /* Put the entire DAC block in reset state */ flags = enter_critical_section(); regval = getreg32(STM32L4_RCC_APB1RSTR1); -#if STM32L4_NDAC < 2 regval |= RCC_APB1RSTR1_DAC1RST; -#else -#ifdef CONFIG_STM32L4_DAC1 - regval |= RCC_APB1RSTR1_DAC1RST; -#endif -#ifdef CONFIG_STM32L4_DAC2 - regval |= RCC_APB1RSTR1_DAC2RST; -#endif -#endif putreg32(regval, STM32L4_RCC_APB1RSTR1); /* Take the DAC out of reset state */ -#if STM32L4_NDAC < 2 regval &= ~RCC_APB1RSTR1_DAC1RST; -#else -#ifdef CONFIG_STM32L4_DAC1 - regval &= ~RCC_APB1RSTR1_DAC1RST; -#endif -#ifdef CONFIG_STM32L4_DAC2 - regval &= ~RCC_APB1RSTR1_DAC2RST; -#endif -#endif putreg32(regval, STM32L4_RCC_APB1RSTR1); leave_critical_section(flags); /* Mark the DAC block as initialized */ g_dacblock.init = 1; - return OK; } /**************************************************************************** @@ -1214,44 +1164,29 @@ FAR struct dac_dev_s *stm32l4_dacinitialize(int intf) FAR struct stm32_chan_s *chan; int ret; + switch (intf) + { #ifdef CONFIG_STM32L4_DAC1 - if (intf == 0) - { - ainfo("DAC1-1 Selected\n"); - dev = &g_dac1dev; - } -#if STM32L4_NDAC > 1 - else if (intf == 1) - { - ainfo("DAC1-2 Selected\n"); - dev = &g_dac2dev; - } + case 0: + ainfo("DAC1-1 Selected\n"); + dev = &g_dac1dev; + break; #endif - else -#endif /* CONFIG_STM32L4_DAC1 */ #ifdef CONFIG_STM32L4_DAC2 - if (intf == 2) - { - ainfo("DAC2-1 Selected\n"); - dev = &g_dac3dev; - } - else + case 1: + ainfo("DAC1-2 Selected\n"); + dev = &g_dac2dev; + break; #endif - { - aerr("ERROR: No such DAC interface: %d\n", intf); - errno = ENODEV; - return NULL; + default: + aerr("ERROR: No such DAC interface: %d\n", intf); + errno = ENODEV; + return NULL; } /* Make sure that the DAC block has been initialized */ - ret = dac_blockinit(); - if (ret < 0) - { - aerr("ERROR: Failed to initialize the DAC block: %d\n", ret); - errno = -ret; - return NULL; - } + dac_blockinit(); /* Configure the selected DAC channel */ diff --git a/arch/arm/src/stm32l4/stm32l4_dac.h b/arch/arm/src/stm32l4/stm32l4_dac.h index 19c8ad65c3a..b6e370f0e02 100644 --- a/arch/arm/src/stm32l4/stm32l4_dac.h +++ b/arch/arm/src/stm32l4/stm32l4_dac.h @@ -92,6 +92,17 @@ # undef CONFIG_STM32L4_TIM17_DAC #endif +/************************************************************************************ + * Public Data + ************************************************************************************/ + +#ifdef CONFIG_STM32L4_DAC1_DMA +extern uint16_t stm32l4_dac1_dmabuffer[]; +#endif +#ifdef CONFIG_STM32L4_DAC2_DMA +extern uint16_t stm32l4_dac2_dmabuffer[]; +#endif + /************************************************************************************ * Public Function Prototypes ************************************************************************************/ From 06ebe57a63584d28a5c839449d88a2a7c23cfb41 Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Fri, 1 Sep 2017 10:08:09 +0300 Subject: [PATCH 4/4] configs/nucleo-l496zg: add DAC and missing TIM frequencies Signed-off-by: Juha Niskanen --- configs/nucleo-l496zg/include/board.h | 19 +++ configs/nucleo-l496zg/src/Makefile | 4 + configs/nucleo-l496zg/src/nucleo-144.h | 12 ++ .../nucleo-l496zg/src/stm32_appinitialize.c | 10 ++ configs/nucleo-l496zg/src/stm32_dac.c | 117 ++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 configs/nucleo-l496zg/src/stm32_dac.c diff --git a/configs/nucleo-l496zg/include/board.h b/configs/nucleo-l496zg/include/board.h index 7cfbf844f6c..e85d94a17f2 100644 --- a/configs/nucleo-l496zg/include/board.h +++ b/configs/nucleo-l496zg/include/board.h @@ -194,6 +194,25 @@ #endif +/* Timer Frequencies, if APBx is set to 1, frequency is same to APBx + * otherwise frequency is 2xAPBx. + * Note: TIM1,8,15,16,17 are on APB2, others on APB1 + */ + +#define BOARD_TIM1_FREQUENCY STM32L4_HCLK_FREQUENCY +#define BOARD_TIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM3_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM4_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM5_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM6_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM7_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_TIM8_FREQUENCY STM32L4_HCLK_FREQUENCY +#define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY +#define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY +#define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY +#define BOARD_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) +#define BOARD_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) + /* SDMMC dividers. Note that slower clocking is required when DMA is disabled * in order to avoid RX overrun/TX underrun errors due to delayed responses * to service FIFOs in interrupt driven mode. These values have not been diff --git a/configs/nucleo-l496zg/src/Makefile b/configs/nucleo-l496zg/src/Makefile index d30f3bc75e0..1ae9cc1d70c 100644 --- a/configs/nucleo-l496zg/src/Makefile +++ b/configs/nucleo-l496zg/src/Makefile @@ -61,6 +61,10 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif +ifeq ($(CONFIG_DAC),y) +CSRCS += stm32_dac.c +endif + ifeq ($(CONFIG_MMCSD),y) CSRCS += stm32_sdio.c endif diff --git a/configs/nucleo-l496zg/src/nucleo-144.h b/configs/nucleo-l496zg/src/nucleo-144.h index fc4bc9381c3..74ff14a0cc5 100644 --- a/configs/nucleo-l496zg/src/nucleo-144.h +++ b/configs/nucleo-l496zg/src/nucleo-144.h @@ -281,5 +281,17 @@ void stm32_usbinitialize(void); int stm32_adc_setup(void); #endif +/************************************************************************************ + * Name: stm32_dac_setup + * + * Description: + * Initialize DAC and register the DAC driver. + * + ************************************************************************************/ + +#ifdef CONFIG_DAC +int stm32_dac_setup(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __CONFIGS_NUCLEO_L496ZG_SRC_NUCLEO_144_H */ diff --git a/configs/nucleo-l496zg/src/stm32_appinitialize.c b/configs/nucleo-l496zg/src/stm32_appinitialize.c index a37ba99f127..0d21b280e39 100644 --- a/configs/nucleo-l496zg/src/stm32_appinitialize.c +++ b/configs/nucleo-l496zg/src/stm32_appinitialize.c @@ -132,6 +132,16 @@ int board_app_initialize(uintptr_t arg) } #endif +#ifdef CONFIG_DAC + /* Initialize DAC and register the DAC driver. */ + + ret = stm32_dac_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_dac_setup failed: %d\n", ret); + } +#endif + #if defined(CONFIG_FAT_DMAMEMORY) if (stm32_dma_alloc_init() < 0) { diff --git a/configs/nucleo-l496zg/src/stm32_dac.c b/configs/nucleo-l496zg/src/stm32_dac.c new file mode 100644 index 00000000000..cc53b76b192 --- /dev/null +++ b/configs/nucleo-l496zg/src/stm32_dac.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * configs/nucleo-l496zg/src/stm32_dac.c + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Authors: Juha Niskanen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include "stm32l4_gpio.h" +#include "stm32l4_dac.h" +#include "nucleo-144.h" + +#ifdef CONFIG_DAC + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +#ifdef CONFIG_STM32L4_DAC1 +static struct dac_dev_s *g_dac1; +#endif + +#ifdef CONFIG_STM32L4_DAC2 +static struct dac_dev_s *g_dac2; +#endif + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_dac_setup + ************************************************************************************/ + +int stm32_dac_setup(void) +{ + static bool initialized = false; + + if (!initialized) + { + int ret; + +#ifdef CONFIG_STM32L4_DAC1 + g_dac1 = stm32l4_dacinitialize(0); + if (g_dac1 == NULL) + { + aerr("ERROR: Failed to get DAC1 interface\n"); + return -ENODEV; + } + + ret = dac_register("/dev/dac0", g_dac1); + if (ret < 0) + { + aerr("ERROR: dac_register failed: %d\n", ret); + return ret; + } +#endif +#ifdef CONFIG_STM32L4_DAC2 + g_dac2 = stm32l4_dacinitialize(1); + if (g_dac2 == NULL) + { + aerr("ERROR: Failed to get DAC2 interface\n"); + return -ENODEV; + } + + ret = dac_register("/dev/dac1", g_dac2); + if (ret < 0) + { + aerr("ERROR: dac_register failed: %d\n", ret); + return ret; + } +#endif + UNUSED(ret); + initialized = true; + } + + return OK; +} +#endif /* CONFIG_DAC */