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..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" @@ -3254,7 +3259,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,8 +3274,19 @@ 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 + 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 @@ -3278,7 +3294,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 @@ -3294,11 +3310,18 @@ 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_DAC_DMA_BUFFER_SIZE - int "DAC DMA buffer size" - default 256 +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. 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/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_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..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,21 +91,16 @@ /* 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 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 +114,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 @@ -127,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: @@ -266,10 +281,6 @@ # define DAC2_TSEL_VALUE DAC_CR_TSEL_SW #endif -#ifndef CONFIG_STM32L4_DAC_DMA_BUFFER_SIZE -# 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,11 +322,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 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 }; @@ -347,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 @@ -366,21 +379,21 @@ static const struct dac_ops_s g_dacops = #ifdef CONFIG_STM32L4_DAC1 /* Channel 1 */ +#ifdef CONFIG_STM32L4_DAC1_DMA +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 = stm32l4_dac1_dmabuffer, .timer = CONFIG_STM32L4_DAC1_TIMER, .tsel = DAC1_TSEL_VALUE, .tbase = DAC1_TIMER_BASE, @@ -394,26 +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 +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 = stm32l4_dac2_dmabuffer, .timer = CONFIG_STM32L4_DAC2_TIMER, .tsel = DAC2_TSEL_VALUE, .tbase = DAC2_TIMER_BASE, @@ -426,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; @@ -475,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 @@ -488,6 +482,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; + + /* 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 + * Bit 0 = 1: Shift = 16 + */ + + shift = (chan->intf & 1) << 4; + modifyreg32(STM32L4_DAC_MCR, clearbits << shift, setbits << shift); +} + /**************************************************************************** * Name: tim_putreg * @@ -646,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); @@ -710,6 +729,19 @@ 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 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; + chan->buffer_pos = (chan->buffer_pos + 1) % chan->buffer_len; + /* Configure the DMA stream/channel. * * - Channel number @@ -727,7 +759,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 */ @@ -1001,7 +1033,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 */ @@ -1050,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; @@ -1063,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; } /**************************************************************************** @@ -1133,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 ************************************************************************************/ 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 */