Merged in juniskane/nuttx_stm32l4/dac_work2 (pull request #475)

Some STM32L4 DAC changes

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
Juha Niskanen 2017-09-01 13:43:03 +00:00 committed by Gregory Nutt
commit 8b3555dac7
14 changed files with 383 additions and 155 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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)

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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
************************************************************************************/

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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)
{

View File

@ -0,0 +1,117 @@
/*****************************************************************************
* configs/nucleo-l496zg/src/stm32_dac.c
*
* Copyright (C) 2017 Haltian Ltd. All rights reserved.
* Authors: Juha Niskanen <juha.niskanen@haltian.com>
*
* 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 <nuttx/config.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/board.h>
#include <nuttx/analog/dac.h>
#include <arch/board/board.h>
#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 */