diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs index 66c51a9acb9..5a497b3356b 100644 --- a/arch/arm/src/samv7/Make.defs +++ b/arch/arm/src/samv7/Make.defs @@ -214,3 +214,7 @@ endif ifeq ($(CONFIG_SAMV7_PROGMEM),y) CHIP_CSRCS += sam_progmem.c endif + +ifneq (,$(findstring y,$(CONFIG_SAMV7_DAC0) $(CONFIG_SAMV7_DAC1))) +CHIP_CSRCS += sam_dac.c +endif diff --git a/arch/arm/src/samv7/chip/sam_dacc.h b/arch/arm/src/samv7/chip/sam_dacc.h new file mode 100644 index 00000000000..a40b0d09e5a --- /dev/null +++ b/arch/arm/src/samv7/chip/sam_dacc.h @@ -0,0 +1,226 @@ +/**************************************************************************************** + * arch/arm/src/samv7/chip/sam_dacc.h + * Digital-to-Analog Converter Controller (DACC) for the SAMV7 + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_CHIP_SAM_DACC_H +#define __ARCH_ARM_SRC_SAMV7_CHIP_SAM_DACC_H + +/**************************************************************************************** + * Included Files + ****************************************************************************************/ + +#include + +#include "chip.h" +#include "chip/sam_memorymap.h" + +/**************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************/ + +/* DACC register offsets *****************************************************************/ + +#define SAM_DACC_CR_OFFSET 0x0000 /* Control Register */ +#define SAM_DACC_MR_OFFSET 0x0004 /* Mode Register */ +#define SAM_DACC_TRIGR_OFFSET 0x0008 /* Trigger Register */ +#define SAM_DACC_CHER_OFFSET 0x0010 /* Channel Enable Register */ +#define SAM_DACC_CHDR_OFFSET 0x0014 /* Channel Disable Register */ +#define SAM_DACC_CHSR_OFFSET 0x0018 /* Channel Status Register */ +#define SAM_DACC_CDR0_OFFSET 0x001c /* Conversion Data Register 0 */ +#define SAM_DACC_CDR1_OFFSET 0x0020 /* Conversion Data Register 1 */ +#define SAM_DACC_IER_OFFSET 0x0024 /* Interrupt Enable Register */ +#define SAM_DACC_IDR_OFFSET 0x0028 /* Interrupt Disable Register */ +#define SAM_DACC_IMR_OFFSET 0x002c /* Interrupt Mask Register */ +#define SAM_DACC_ISR_OFFSET 0x0030 /* Interrupt Status Register */ +#define SAM_DACC_ACR_OFFSET 0x0094 /* Analog Current Register */ +#define SAM_DACC_WPMR_OFFSET 0x00e4 /* Write Protect Mode register */ +#define SAM_DACC_WPSR_OFFSET 0x00e8 /* Write Protect Status register */ + +/* DACC register addresses **************************************************************/ + +#define SAM_DACC_CR (SAM_DACC_BASE+SAM_DACC_CR_OFFSET) +#define SAM_DACC_MR (SAM_DACC_BASE+SAM_DACC_MR_OFFSET) +#define SAM_DACC_TRIGR (SAM_DACC_BASE+SAM_DACC_TRIGR_OFFSET) +#define SAM_DACC_CHER (SAM_DACC_BASE+SAM_DACC_CHER_OFFSET) +#define SAM_DACC_CHDR (SAM_DACC_BASE+SAM_DACC_CHDR_OFFSET) +#define SAM_DACC_CHSR (SAM_DACC_BASE+SAM_DACC_CHSR_OFFSET) +#define SAM_DACC_CDR0 (SAM_DACC_BASE+SAM_DACC_CDR0_OFFSET) +#define SAM_DACC_CDR1 (SAM_DACC_BASE+SAM_DACC_CDR1_OFFSET) +#define SAM_DACC_IER (SAM_DACC_BASE+SAM_DACC_IER_OFFSET) +#define SAM_DACC_IDR (SAM_DACC_BASE+SAM_DACC_IDR_OFFSET) +#define SAM_DACC_IMR (SAM_DACC_BASE+SAM_DACC_IMR_OFFSET) +#define SAM_DACC_ISR (SAM_DACC_BASE+SAM_DACC_ISR_OFFSET) +#define SAM_DACC_ACR (SAM_DACC_BASE+SAM_DACC_ACR_OFFSET) +#define SAM_DACC_WPMR (SAM_DACC_BASE+SAM_DACC_WPMR_OFFSET) +#define SAM_DACC_WPSR (SAM_DACC_BASE+SAM_DACC_WPSR_OFFSET) + +/* DACC register bit definitions ********************************************************/ + +/* Control Register */ + +#define DACC_CR_SWRST (1 << 0) /* Bit 0: Software reset */ + +/* Mode Register */ + +#define DACC_MR_MAXS0 (1 << 0) /* Max Speed Mode for Channel 0 */ +# define DACC_MR_MAXS0_TRIG_EVENT (0 << 0) /* External trigger mode or Free-running mode enabled */ +# define DACC_MR_MAXS0_MAXIMUM (1 << 0) /* Max speed mode enabled */ +#define DACC_MR_MAXS1 (1 << 1) /* Max Speed Mode for Channel 1 */ +# define DACC_MR_MAXS1_TRIG_EVENT (0 << 1) /* External trigger mode or Free-running mode enabled */ +# define DACC_MR_MAXS1_MAXIMUM (1 << 1) /* Max speed mode enabled */ +#define DACC_MR_WORD (1 << 4) /* Word Transfer Mode */ +# define DACC_MR_WORD_DISABLED (0 << 4) /* One data to convert is written to the FIFO per access to DACC */ +# define DACC_MR_WORD_ENABLED (1 << 4) /* Two data to convert are written to the FIFO per access to DACC */ +#define DACC_MR_ZERO (1 << 5) /* Must always be written to 0 */ +#define DACC_MR_DIFF (1 << 23) /* Differential Mode */ +# define DACC_MR_DIFF_DISABLED (0 << 23) /* DAC0 and DAC1 are single-ended outputs */ +# define DACC_MR_DIFF_ENABLED (1 << 23) /* DACP and DACN are differential outputs. The differential level is configured by the channel 0 value. */ +#define DACC_MR_PRESCALER_SHIFT (24) +#define DACC_MR_PRESCALER_MASK (0xfu << DACC_MR_PRESCALER_SHIFT) /* Peripheral Clock to DAC Clock Ratio */ +#define DACC_MR_PRESCALER(value) ((DACC_MR_PRESCALER_MASK & ((value) << DACC_MR_PRESCALER_SHIFT))) +# define DACC_MR_PRESCALER_2 (0 << DACC_MR_PRESCALER_SHIFT) /* 2 periods of DAC Clock */ +# define DACC_MR_PRESCALER_3 (1 << DACC_MR_PRESCALER_SHIFT) /* 3 periods of DAC Clock */ +# define DACC_MR_PRESCALER_4 (2 << DACC_MR_PRESCALER_SHIFT) /* 4 periods of DAC Clock */ +# define DACC_MR_PRESCALER_5 (3 << DACC_MR_PRESCALER_SHIFT) /* 5 periods of DAC Clock */ +# define DACC_MR_PRESCALER_6 (4 << DACC_MR_PRESCALER_SHIFT) /* 6 periods of DAC Clock */ +# define DACC_MR_PRESCALER_7 (5 << DACC_MR_PRESCALER_SHIFT) /* 7 periods of DAC Clock */ +# define DACC_MR_PRESCALER_8 (6 << DACC_MR_PRESCALER_SHIFT) /* 8 periods of DAC Clock */ +# define DACC_MR_PRESCALER_9 (7 << DACC_MR_PRESCALER_SHIFT) /* 9 periods of DAC Clock */ +# define DACC_MR_PRESCALER_10 (8 << DACC_MR_PRESCALER_SHIFT) /* 10 periods of DAC Clock */ +# define DACC_MR_PRESCALER_11 (9 << DACC_MR_PRESCALER_SHIFT) /* 11 periods of DAC Clock */ +# define DACC_MR_PRESCALER_12 (10 << DACC_MR_PRESCALER_SHIFT) /* 12 periods of DAC Clock */ +# define DACC_MR_PRESCALER_13 (11 << DACC_MR_PRESCALER_SHIFT) /* 13 periods of DAC Clock */ +# define DACC_MR_PRESCALER_14 (12 << DACC_MR_PRESCALER_SHIFT) /* 14 periods of DAC Clock */ +# define DACC_MR_PRESCALER_15 (13 << DACC_MR_PRESCALER_SHIFT) /* 15 periods of DAC Clock */ +# define DACC_MR_PRESCALER_16 (14 << DACC_MR_PRESCALER_SHIFT) /* 16 periods of DAC Clock */ +# define DACC_MR_PRESCALER_17 (15 << DACC_MR_PRESCALER_SHIFT) /* 17 periods of DAC Clock */ + +/* Trigger Register */ + +#define DACC_TRIGR_TRGEN0 (1 << 0) /* Trigger Enable of Channel 0 */ +# define DACC_TRIGR_TRGEN0_DIS (0 << 0) /* External trigger mode disabled. DACC is in Free-running mode or Max speed mode. */ +# define DACC_TRIGR_TRGEN0_EN (1 << 0) /* External trigger mode enabled. */ +#define DACC_TRIGR_TRGEN1 (1 << 1) /* Trigger Enable of Channel 1 */ +# define DACC_TRIGR_TRGEN1_DIS (0 << 1) /* External trigger mode disabled. DACC is in Free-running mode or Max speed mode. */ +# define DACC_TRIGR_TRGEN1_EN (1 << 1) /* External trigger mode enabled. */ +#define DACC_TRIGR_TRGSEL0_SHIFT (4) +#define DACC_TRIGR_TRGSEL0_MASK (0x7u << DACC_TRIGR_TRGSEL0_SHIFT) /* Trigger Selection of Channel 0 */ +#define DACC_TRIGR_TRGSEL0(value) ((DACC_TRIGR_TRGSEL0_MASK & ((value) << DACC_TRIGR_TRGSEL0_SHIFT))) +# define DACC_TRIGR_TRGSEL0_DATRG (0 << 4) /* DATRG output */ +# define DACC_TRIGR_TRGSEL0_TC0 (1 << 4) /* TC0 output */ +# define DACC_TRIGR_TRGSEL0_TC1 (2 << 4) /* TC1 output */ +# define DACC_TRIGR_TRGSEL0_TC2 (3 << 4) /* TC2 output */ +# define DACC_TRIGR_TRGSEL0_PWM0EV0 (4 << 4) /* PWM0 event 0 */ +# define DACC_TRIGR_TRGSEL0_PWM0EV1 (5 << 4) /* PWM0 event 1 */ +# define DACC_TRIGR_TRGSEL0_PWM1EV0 (6 << 4) /* PWM1 event 0 */ +# define DACC_TRIGR_TRGSEL0_PWM1EV1 (7 << 4) /* PWM1 event 1 */ +#define DACC_TRIGR_TRGSEL1_SHIFT (8) +#define DACC_TRIGR_TRGSEL1_MASK (0x7u << DACC_TRIGR_TRGSEL1_SHIFT) /* Trigger Selection of Channel 1 */ +#define DACC_TRIGR_TRGSEL1(value) ((DACC_TRIGR_TRGSEL1_MASK & ((value) << DACC_TRIGR_TRGSEL1_SHIFT))) +# define DACC_TRIGR_TRGSEL1_DATRG (0 << 8) /* DATRG output */ +# define DACC_TRIGR_TRGSEL1_TC0 (1 << 8) /* TC0 output */ +# define DACC_TRIGR_TRGSEL1_TC1 (2 << 8) /* TC1 output */ +# define DACC_TRIGR_TRGSEL1_TC2 (3 << 8) /* TC2 output */ +# define DACC_TRIGR_TRGSEL1_PWM0EV0 (4 << 8) /* PWM0 event 0 */ +# define DACC_TRIGR_TRGSEL1_PWM0EV1 (5 << 8) /* PWM0 event 1 */ +# define DACC_TRIGR_TRGSEL1_PWM1EV0 (6 << 8) /* PWM1 event 0 */ +# define DACC_TRIGR_TRGSEL1_PWM1EV1 (7 << 8) /* PWM1 event 1 */ +#define DACC_TRIGR_OSR0_SHIFT (16) +#define DACC_TRIGR_OSR0_MASK (0x7u << DACC_TRIGR_OSR0_SHIFT) /* Over Sampling Ratio of Channel 0 */ +#define DACC_TRIGR_OSR0(value) ((DACC_TRIGR_OSR0_MASK & ((value) << DACC_TRIGR_OSR0_SHIFT))) +# define DACC_TRIGR_OSR0_OSR_1 (0 << 16) /* OSR = 1 */ +# define DACC_TRIGR_OSR0_OSR_2 (1 << 16) /* OSR = 2 */ +# define DACC_TRIGR_OSR0_OSR_4 (2 << 16) /* OSR = 4 */ +# define DACC_TRIGR_OSR0_OSR_8 (3 << 16) /* OSR = 8 */ +# define DACC_TRIGR_OSR0_OSR_16 (4 << 16) /* OSR = 16 */ +# define DACC_TRIGR_OSR0_OSR_32 (5 << 16) /* OSR = 32 */ +#define DACC_TRIGR_OSR1_SHIFT (20) +#define DACC_TRIGR_OSR1_MASK (0x7u << DACC_TRIGR_OSR1_SHIFT) /* Over Sampling Ratio of Channel 1 */ +#define DACC_TRIGR_OSR1(value) ((DACC_TRIGR_OSR1_MASK & ((value) << DACC_TRIGR_OSR1_SHIFT))) +# define DACC_TRIGR_OSR1_OSR_1 (0 << 20) /* OSR = 1 */ +# define DACC_TRIGR_OSR1_OSR_2 (1 << 20) /* OSR = 2 */ +# define DACC_TRIGR_OSR1_OSR_4 (2 << 20) /* OSR = 4 */ +# define DACC_TRIGR_OSR1_OSR_8 (3 << 20) /* OSR = 8 */ +# define DACC_TRIGR_OSR1_OSR_16 (4 << 20) /* OSR = 16 */ +# define DACC_TRIGR_OSR1_OSR_32 (5 << 20) /* OSR = 32 */ + +/* Channel Enable, Channel Disable, and Channel Status Registers */ + +#define DACC_CH0 (1 << 0) /* Channel 0 */ +#define DACC_CH1 (1 << 1) /* Channel 1 */ +#define DACC_CHSR_DACRDY0 (1 << 8) /* DAC Ready Flag */ +#define DACC_CHSR_DACRDY1 (1 << 9) /* DAC Ready Flag */ + +/* Conversion Data Register -- 32-bit data */ + +#define DACC_CDR_DATA0_SHIFT (0) +#define DACC_CDR_DATA0_MASK (0xffffu << DACC_CDR_DATA0_SHIFT) /* Data to Convert for channel 0 */ +#define DACC_CDR_DATA0(value) ((DACC_CDR_DATA0_MASK & ((value) << DACC_CDR_DATA0_SHIFT))) +#define DACC_CDR_DATA1_SHIFT (16) +#define DACC_CDR_DATA1_MASK (0xffffu << DACC_CDR_DATA1_SHIFT) /* Data to Convert for channel 1 */ +#define DACC_CDR_DATA1(value) ((DACC_CDR_DATA1_MASK & ((value) << DACC_CDR_DATA1_SHIFT))) + +/* Interrupt Enable, Interrupt Disable, Interrupt Mask, and Interrupt Status Register */ + +#define DACC_INT_TXRDY0 (1 << 0) /* Transmit Ready Interrupt of channel 0 */ +#define DACC_INT_TXRDY1 (1 << 1) /* Transmit Ready Interrupt of channel 1 */ +#define DACC_INT_EOC0 (1 << 4) /* End of Conversion Interrupt of channel 0 */ +#define DACC_INT_EOC1 (1 << 5) /* End of Conversion Interrupt of channel 1 */ +#define DACC_INT_ALL (0xffffffffu) /* All interrupts */ + +/* Analog Current Register */ + +#define DACC_ACR_IBCTLCH0_SHIFT (0) +#define DACC_ACR_IBCTLCH0_MASK (0x3u << DACC_ACR_IBCTLCH0_SHIFT) /* Analog Output Current Control */ +#define DACC_ACR_IBCTLCH0(value) ((DACC_ACR_IBCTLCH0_MASK & ((value) << DACC_ACR_IBCTLCH0_SHIFT))) +#define DACC_ACR_IBCTLCH1_SHIFT (2) +#define DACC_ACR_IBCTLCH1_MASK (0x3u << DACC_ACR_IBCTLCH1_SHIFT) /* Analog Output Current Control */ +#define DACC_ACR_IBCTLCH1(value) ((DACC_ACR_IBCTLCH1_MASK & ((value) << DACC_ACR_IBCTLCH1_SHIFT))) + +/* Write Protect Mode register */ + +#define DACC_WPMR_WPEN (1 << 0) /* Write Protection Enable */ +#define DACC_WPMR_WPKEY_SHIFT (8) +#define DACC_WPMR_WPKEY_MASK (0xffffffu << DACC_WPMR_WPKEY_SHIFT) /* Write Protect Key */ +#define DACC_WPMR_WPKEY(value) ((DACC_WPMR_WPKEY_MASK & ((value) << DACC_WPMR_WPKEY_SHIFT))) +# define DACC_WPMR_WPKEY_PASSWD (0x444143u << 8) /* Writing any other value in this field aborts the write operation of bit WPEN. Always reads as 0. */ + +/* Write Protect Status register */ + +#define DACC_WPSR_WPVS (1 << 0) /* Write Protection Violation Status */ +#define DACC_WPSR_WPVSRC_SHIFT (8) +#define DACC_WPSR_WPVSRC_MASK (0xffu << DACC_WPSR_WPVSRC_SHIFT) /* Write Protection Violation Source */ + +#endif /* __ARCH_ARM_SRC_SAMV7_CHIP_SAM_DACC_H */ diff --git a/arch/arm/src/samv7/sam_dac.c b/arch/arm/src/samv7/sam_dac.c new file mode 100644 index 00000000000..598201ce390 --- /dev/null +++ b/arch/arm/src/samv7/sam_dac.c @@ -0,0 +1,658 @@ +/************************************************************************************ + * arch/arm/src/samv7/sam_dac.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include + +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" +#include "cache.h" + +#include "chip/sam_dacc.h" +#include "chip/sam_pmc.h" +#include "chip/sam_pinmap.h" + +#include "sam_gpio.h" +#include "sam_xdmac.h" +#include "sam_periphclks.h" +#include "sam_tc.h" +#include "sam_dac.h" + +#if defined(CONFIG_SAMV7_DAC0) || defined(CONFIG_SAMV7_DAC1) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Get TC channel number from Trigger Selection value */ + +#define SAMV7_DAC_TC_CHANNEL (CONFIG_SAMV7_DAC_TRIGGER_SELECT - 1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the internal state of a single SAMV7 DAC module */ + +struct sam_dac_s +{ + uint8_t initialized : 1; /* True, the DAC block has been initialized */ +#ifdef CONFIG_SAMV7_DAC_TRIGGER + TC_HANDLE tc; /* Timer handle */ +#endif +}; + +/* This structure represents the internal state of one SAMV7 DAC channel */ + +struct sam_chan_s +{ + uint8_t inuse : 1; /* True, the driver is in use and not available */ + uint8_t intf; /* DAC zero-based interface number (0 or 1) */ + uint32_t dro; /* Conversion Data Register */ +#ifdef CONFIG_SAMV7_DAC_TRIGGER + uint32_t reg_dacc_trigr_clear; /* channel DACC_TRIGR register clear bits */ + uint32_t reg_dacc_trigr_set; /* channel DACC_TRIGR register set bits */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Interrupt handler */ + +static int dac_interrupt(int irq, FAR void *context); + +/* DAC methods */ + +static void dac_reset(FAR struct dac_dev_s *dev); +static int dac_setup(FAR struct dac_dev_s *dev); +static void dac_shutdown(FAR struct dac_dev_s *dev); +static void dac_txint(FAR struct dac_dev_s *dev, bool enable); +static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg); +static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg); + +/* Initialization */ + +#ifdef CONFIG_SAMV7_DAC_TRIGGER +static int dac_timer_init(struct sam_dac_s *priv, uint32_t freq_required, + int channel); +static void dac_timer_free(struct sam_dac_s *priv); +#endif +static int dac_channel_init(FAR struct sam_chan_s *chan); +static int dac_module_init(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct dac_ops_s g_dacops = +{ + .ao_reset = dac_reset, + .ao_setup = dac_setup, + .ao_shutdown = dac_shutdown, + .ao_txint = dac_txint, + .ao_send = dac_send, + .ao_ioctl = dac_ioctl, +}; + +#ifdef CONFIG_SAMV7_DAC0 +static struct sam_chan_s g_dac1priv = +{ + .intf = 0, + .dro = SAM_DACC_CDR0, +#ifdef CONFIG_SAMV7_DAC_TRIGGER + .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL0_MASK, + .reg_dacc_trigr_set = DACC_TRIGR_TRGSEL0(CONFIG_SAMV7_DAC_TRIGGER_SELECT) | DACC_TRIGR_TRGEN0, +#endif +}; + +static struct dac_dev_s g_dac1dev = +{ + .ad_ops = &g_dacops, + .ad_priv = &g_dac1priv, +}; +#endif + +#ifdef CONFIG_SAMV7_DAC1 +static struct sam_chan_s g_dac2priv = +{ + .intf = 1, + .dro = SAM_DACC_CDR1, +#ifdef CONFIG_SAMV7_DAC_TRIGGER + .reg_dacc_trigr_clear = DACC_TRIGR_TRGSEL1_MASK, + .reg_dacc_trigr_set = DACC_TRIGR_TRGSEL1(CONFIG_SAMV7_DAC_TRIGGER_SELECT) | DACC_TRIGR_TRGEN1, +#endif +}; + +static struct dac_dev_s g_dac2dev = +{ + .ad_ops = &g_dacops, + .ad_priv = &g_dac2priv, +}; +#endif + +static struct sam_dac_s g_dacmodule; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dac_interrupt + * + * Description: + * DAC interrupt handler. + * + * Input Parameters: + * + * Returned Value: + * OK + * + ****************************************************************************/ + +static int dac_interrupt(int irq, FAR void *context) +{ +#ifdef CONFIG_SAMV7_DAC1 + uint32_t status; + + status = getreg32(SAM_DACC_ISR) & getreg32(SAM_DACC_IMR); + if (status & DACC_INT_TXRDY1) + { + dac_txdone(&g_dac2dev); + } + + if (status & DACC_INT_TXRDY0) +#endif + { + dac_txdone(&g_dac1dev); + } + + return OK; +} + +/**************************************************************************** + * Name: dac_reset + * + * Description: + * Reset the DAC channel. Called early to initialize the hardware. This + * is called, before dac_setup() and on error conditions. + * + * Input Parameters: + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void dac_reset(FAR struct dac_dev_s *dev) +{ + irqstate_t flags; + + /* Reset only the selected DAC channel; the other DAC channel must remain + * functional. + */ + + flags = enter_critical_section(); + +#warning "Missing logic" + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: dac_setup + * + * Description: + * Configure the DAC. This method is called the first time that the DAC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching DAC interrupts. Interrupts + * are all disabled upon return. + * + * Input Parameters: + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int dac_setup(FAR struct dac_dev_s *dev) +{ +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: dac_shutdown + * + * Description: + * Disable the DAC. This method is called when the DAC device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void dac_shutdown(FAR struct dac_dev_s *dev) +{ +#warning "Missing logic" +} + +/**************************************************************************** + * Name: dac_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void dac_txint(FAR struct dac_dev_s *dev, bool enable) +{ + FAR struct sam_chan_s *chan; + + chan = dev->ad_priv; + if (enable) + { + putreg32(DACC_INT_TXRDY0 << chan->intf, SAM_DACC_IER); + } + else + { + putreg32(DACC_INT_TXRDY0 << chan->intf, SAM_DACC_IDR); + } +} + +/**************************************************************************** + * Name: dac_send + * + * Description: + * Set the DAC output. + * + * Input Parameters: + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int dac_send(FAR struct dac_dev_s *dev, FAR struct dac_msg_s *msg) +{ + FAR struct sam_chan_s *chan = dev->ad_priv; + + /* Interrupt based transfer */ + + putreg16(msg->am_data >> 16, chan->dro); + + return OK; +} + +/**************************************************************************** + * Name: dac_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int dac_ioctl(FAR struct dac_dev_s *dev, int cmd, unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Name: dac_timer_init + * + * Description: + * Configure a timer to periodically trigger conversion. Only channels TC0, + * TC1, TC2 can be used with DAC. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_DAC_TRIGGER +static int dac_timer_init(struct sam_dac_s *priv, uint32_t freq_required, + int channel) +{ + uint32_t mode; + uint32_t regval; + uint32_t freq_actual; + + ainfo("required frequency=%ld [Hz], channel=%d\n", + (long)freq_required, channel); + + DEBUGASSERT(priv && (freq_required > 0) && (channel >= 0 && channel <= 2)); + + /* Set the timer/counter waveform mode the the clock input. Use smallest + * MCK divisor of 8 to have highest clock resolution thus smallest frequency + * error. With 32 bit counter the lowest possible frequency of 1 Hz is easily + * supported. + */ + + /* TODO Add support for TC_CMR_TCCLKS_PCK6 to reduce frequency error */ + + mode = (TC_CMR_TCCLKS_MCK8 | /* Use MCK/8 clock signal */ + TC_CMR_WAVSEL_UPRC | /* UP mode w/ trigger on RC Compare */ + TC_CMR_WAVE | /* Wave mode */ + TC_CMR_ACPA_CLEAR | /* RA Compare Effect on TIOA: Clear */ + TC_CMR_ACPC_SET); /* RC Compare Effect on TIOA: Set */ + + /* Now allocate and configure the channel */ + + priv->tc = sam_tc_allocate(channel, mode); + if (!priv->tc) + { + aerr("ERROR: Failed to allocate channel %d mode %08x\n", channel, mode); + return -EINVAL; + } + + /* Calculate the actual counter value from this divider and the tc input + * frequency. + */ + + regval = BOARD_MCK_FREQUENCY / 8 / freq_required; + DEBUGASSERT(regval > 0); /* Will check for integer underflow */ + + /* Set up TC_RA and TC_RC. The frequency is determined by RA and RC: + * TIOA is cleared on RA match; TIOA is set on RC match. + */ + + sam_tc_setregister(priv->tc, TC_REGA, regval >> 1); + sam_tc_setregister(priv->tc, TC_REGC, regval); + + freq_actual = BOARD_MCK_FREQUENCY / 8 / regval; + ainfo("configured frequency=%ld [Hz]\n", (long)freq_actual); + + /* And start the timer */ + + sam_tc_start(priv->tc); + return OK; +} +#endif + +/**************************************************************************** + * Name: dac_timer_free + * + * Description: + * Free the timer resource + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_DAC_TRIGGER +static void dac_timer_free(struct sam_dac_s *priv) +{ + /* Is a timer allocated? */ + + ainfo("tc=%p\n", priv->tc); + + if (priv->tc) + { + /* Yes.. stop it and free it */ + + sam_tc_stop(priv->tc); + sam_tc_free(priv->tc); + priv->tc = NULL; + } +} +#endif + +/**************************************************************************** + * Name: dac_channel_init + * + * Description: + * Initialize the DAC channel. + * + * Input Parameters: + * chan - A reference to the DAC channel state data + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int dac_channel_init(FAR struct sam_chan_s *chan) +{ + /* Is the selected channel already in-use? */ + + if (chan->inuse) + { + /* Yes.. then return EBUSY */ + + return -EBUSY; + } + +#ifdef CONFIG_SAMV7_DAC_TRIGGER + /* Configure trigger mode operation */ + + ainfo("Enabled trigger mode for DAC%d\n", chan->intf); + + modifyreg32(SAM_DACC_TRIGR, + chan->reg_dacc_trigr_clear, + chan->reg_dacc_trigr_set); +#endif + + /* Enable DAC Channel */ + + putreg32(1 << chan->intf, SAM_DACC_CHER); + + /* Mark the DAC channel "in-use" */ + + chan->inuse = 1; + return OK; +} + +/**************************************************************************** + * Name: dac_module_init + * + * Description: + * Initialize the DAC. All ioctl calls will be routed through this method. + * + * Input Parameters: + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int dac_module_init(void) +{ + uint32_t regval; + int ret; + + /* Has the DAC block already been initialized? */ + + if (g_dacmodule.initialized) + { + /* Yes.. then return success We only have to do this once */ + + return OK; + } + + ainfo("Initializing...\n"); + + /* Disable DAC peripheral clock */ + + sam_dacc_disableclk(); + + /* Configure DAC pins */ + +#ifdef CONFIG_SAMV7_DAC0 + sam_configgpio(GPIO_DAC0); +#endif +#ifdef CONFIG_SAMV7_DAC1 + sam_configgpio(GPIO_DAC1); +#endif + + /* Enable the DAC peripheral clock */ + + sam_dacc_enableclk(); + + /* Reset the DAC controller */ + + putreg32(DACC_CR_SWRST, SAM_DACC_CR); + + /* Set the MCK clock prescaler: PRESCAL = (MCK / DACClock) - 2 */ + + regval = DACC_MR_PRESCALER(CONFIG_SAMV7_DAC_PRESCAL); + putreg32(regval, SAM_DACC_MR); + + /* Configure trigger mode operation */ + +#ifdef CONFIG_SAMV7_DAC_TRIGGER + ret = dac_timer_init(&g_dacmodule, + CONFIG_SAMV7_DAC_TRIGGER_FREQUENCY, + SAMV7_DAC_TC_CHANNEL); + if (ret < 0) + { + aerr("ERROR: Failed to initialize the timer: %d\n", ret); + return ret; + } +#endif + + /* Configure interrupts */ + + ret = irq_attach(SAM_IRQ_DACC, dac_interrupt); + if (ret < 0) + { + aerr("irq_attach failed: %d\n", ret); + return ret; + } + + ainfo("Enable the DAC interrupt: irq=%d\n", SAM_IRQ_DACC); + up_enable_irq(SAM_IRQ_DACC); + + /* Mark the DAC module as initialized */ + + g_dacmodule.initialized = 1; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_dac_initialize + * + * Description: + * Initialize the DAC. + * + * Input Parameters: + * intf - The DAC interface number. + * + * Returned Value: + * Valid DAC device structure reference on success, NULL on failure. + * + ****************************************************************************/ + +FAR struct dac_dev_s *sam_dac_initialize(int intf) +{ + FAR struct dac_dev_s *dev; + FAR struct sam_chan_s *chan; + int ret; + +#ifdef CONFIG_SAMV7_DAC0 + if (intf == 0) + { + ainfo("DAC1 Selected\n"); + dev = &g_dac1dev; + } + else +#endif +#ifdef CONFIG_SAMV7_DAC1 + if (intf == 1) + { + ainfo("DAC2 Selected\n"); + dev = &g_dac2dev; + } + else +#endif + { + aerr("ERROR: No such DAC interface: %d\n", intf); + errno = ENODEV; + return NULL; + } + + /* Initialize the DAC peripheral module */ + + ret = dac_module_init(); + if (ret < 0) + { + aerr("ERROR: Failed to initialize the DAC peripheral module: %d\n", ret); + errno = -ret; + return NULL; + } + + /* Configure the selected DAC channel */ + + chan = dev->ad_priv; + ret = dac_channel_init(chan); + if (ret < 0) + { + aerr("ERROR: Failed to initialize DAC channel %d: %d\n", intf, ret); + errno = -ret; + return NULL; + } + + return dev; +} + +#endif /* CONFIG_SAMV7_DAC0 || CONFIG_SAMV7_DAC1 */ diff --git a/arch/arm/src/samv7/sam_dac.h b/arch/arm/src/samv7/sam_dac.h new file mode 100644 index 00000000000..616d25b486c --- /dev/null +++ b/arch/arm/src/samv7/sam_dac.h @@ -0,0 +1,129 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_dac.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_DAC_H +#define __ARCH_ARM_SRC_SAMV7_SAM_DAC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "chip/sam_dacc.h" + +#if defined(CONFIG_SAMV7_DAC0) || defined(CONFIG_SAMV7_DAC1) + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ +/* Default configuration settings may be overridden in the board configuration + * file. + */ + +#if !defined(CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE) +# define CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE 8 +#elif CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE > 65535 +# warning "CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE value does not fit into uint16_t, limiting it to 65535" +# undef CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE +# define CONFIG_SAMV7_DAC_DMA_BUFFER_SIZE (65535) +#endif + +#if !defined(CONFIG_SAMV7_DAC_TRIGGER_FREQUENCY) +# define CONFIG_SAMV7_DAC_TRIGGER_FREQUENCY 8000 +#endif + +/* PRESCAL = (MCK / DACClock) - 2 + * + * Given: + * MCK = 150MHz + * DACClock = 16MHz + * Then: + * PRESCAL = 7 + */ + +#if !defined(CONFIG_SAMV7_DAC_PRESCAL) +#define CONFIG_SAMV7_DAC_PRESCAL (7) +#elif CONFIG_SAMV7_DAC_PRESCAL > 15 +# warning "Maximum valid CONFIG_SAMV7_DAC_PRESCAL value is 15" +#endif + +#if !defined(CONFIG_SAMV7_DAC_TRIGGER_SELECT) +#define CONFIG_SAMV7_DAC_TRIGGER_SELECT (3) +#elif CONFIG_SAMV7_DAC_TRIGGER_SELECT < 1 || CONFIG_SAMV7_DAC_TRIGGER_SELECT > 3 +# warning "Only CONFIG_SAMV7_DAC_TRIGGER_SELECT == [1-3] is supported" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: sam_dac_initialize + * + * Description: + * Initialize the DAC + * + * Input Parameters: + * intf - The DAC interface number. + * + * Returned Value: + * Valid DAC device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct dac_dev_s; +FAR struct dac_dev_s *sam_dac_initialize(int intf); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_SAMV7_DAC0 || CONFIG_SAMV7_DAC1 */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_DAC_H */ diff --git a/configs/same70-xplained/src/Makefile b/configs/same70-xplained/src/Makefile index 4d883fccb75..1f2eafb849a 100644 --- a/configs/same70-xplained/src/Makefile +++ b/configs/same70-xplained/src/Makefile @@ -90,4 +90,8 @@ endif endif endif +ifneq (,$(findstring y,$(CONFIG_SAMV7_DAC0) $(CONFIG_SAMV7_DAC1))) +CSRCS += sam_dac.c +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/same70-xplained/src/sam_bringup.c b/configs/same70-xplained/src/sam_bringup.c index 7cc5fed0c00..9a84f3228ea 100644 --- a/configs/same70-xplained/src/sam_bringup.c +++ b/configs/same70-xplained/src/sam_bringup.c @@ -329,6 +329,14 @@ int sam_bringup(void) } #endif +#if defined(CONFIG_SAMV7_DAC0) || defined(CONFIG_SAMV7_DAC1) + ret = sam_dacdev_initialize(); + if (ret < 0) + { + _err("ERROR: Initialization of the DAC module failed: %d\n", ret); + } +#endif + /* If we got here then perhaps not all initialization was successful, but * at least enough succeeded to bring-up NSH with perhaps reduced * capabilities. diff --git a/configs/same70-xplained/src/sam_dac.c b/configs/same70-xplained/src/sam_dac.c new file mode 100644 index 00000000000..884de6e27ca --- /dev/null +++ b/configs/same70-xplained/src/sam_dac.c @@ -0,0 +1,123 @@ +/************************************************************************************ + * configs/same70-xplained/src/sam_dac.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 "up_arch.h" +#include "chip.h" +#include "sam_dac.h" +#include "same70-xplained.h" + +#if defined(CONFIG_SAMV7_DAC0) || defined(CONFIG_SAMV7_DAC1) + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: sam_dacdev_initialize + * + * Description: + * Called to configure DAC peripheral module and register DAC device driver + ************************************************************************************/ + +int sam_dacdev_initialize(void) +{ + static bool initialized = false; + struct dac_dev_s *dac; + int ret; + + /* Check if we have already initialized */ + + if (!initialized) + { +#ifdef CONFIG_SAMV7_DAC0 + /* Get an instance of the DAC0 interface */ + + dac = sam_dac_initialize(0); + if (dac == NULL) + { + aerr("ERROR: Failed to get DAC0 interface\n"); + return -ENODEV; + } + + /* Register the DAC driver at "/dev/dac0" */ + + ret = dac_register("/dev/dac0", dac); + if (ret < 0) + { + aerr("ERROR: dac_register failed: %d\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_SAMV7_DAC1 + /* Get an instance of the DAC1 interface */ + + dac = sam_dac_initialize(1); + if (dac == NULL) + { + aerr("ERROR: Failed to get DAC1 interface\n"); + return -ENODEV; + } + + /* Register the DAC driver at "/dev/dac1" */ + + ret = dac_register("/dev/dac1", dac); + if (ret < 0) + { + aerr("ERROR: dac_register failed: %d\n", ret); + return ret; + } +#endif + /* Now we are initialized */ + + initialized = true; + } + return OK; +} + +#endif /* CONFIG_SAMV7_DAC0 || CONFIG_SAMV7_DAC1 */ diff --git a/configs/same70-xplained/src/same70-xplained.h b/configs/same70-xplained/src/same70-xplained.h index 0859c0f450b..117c6a68933 100644 --- a/configs/same70-xplained/src/same70-xplained.h +++ b/configs/same70-xplained/src/same70-xplained.h @@ -349,6 +349,18 @@ void sam_sdram_config(void); int sam_bringup(void); #endif +/************************************************************************************ + * Name: sam_dacdev_initialize + * + * Description: + * Called to configure DAC peripheral module + * + ************************************************************************************/ + +#if defined(CONFIG_SAMV7_DAC0) || defined(CONFIG_SAMV7_DAC1) +int sam_dacdev_initialize(void); +#endif + /************************************************************************************ * Name: sam_spidev_initialize * diff --git a/drivers/analog/dac.c b/drivers/analog/dac.c index daf8b5f34a4..fbbc7618334 100644 --- a/drivers/analog/dac.c +++ b/drivers/analog/dac.c @@ -478,6 +478,7 @@ static int dac_ioctl(FAR struct file *filep, int cmd, unsigned long arg) int dac_txdone(FAR struct dac_dev_s *dev) { int ret = -ENOENT; + int sval; /* Verify that the xmit FIFO is not empty */ @@ -497,7 +498,11 @@ int dac_txdone(FAR struct dac_dev_s *dev) { /* Inform any waiting threads that new xmit space is available */ - ret = sem_post(&dev->ad_xmit.af_sem); + ret = sem_getvalue(&dev->ad_xmit.af_sem, &sval); + if (ret == OK && sval <= 0) + { + ret = sem_post(&dev->ad_xmit.af_sem); + } } }