diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralNames.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralNames.h index 48c43cae82..1951518dfa 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralNames.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralNames.h @@ -44,7 +44,9 @@ typedef enum { UART_5 = (int)0x42001C00UL // Base address of SERCOM5 } UARTName; -typedef enum { // for each input control mux 4,5,6,7,16,17,10,11 used in R21 +typedef enum { + ADC_0 = 0x0ul, + ADC_1 = 0x1ul, ADC_2 = 0x2ul, ADC_3 = 0x3ul, ADC_4 = 0x4ul, @@ -52,14 +54,23 @@ typedef enum { // for each input control mux 4,5,6,7,16,17,10,11 used in R21 ADC_6 = 0x6ul, ADC_7 = 0x7ul, ADC_8 = 0x8ul, + ADC_9 = 0x8ul, ADC_10 = 0xAul, ADC_11 = 0xBul, + ADC_12 = 0xCul, + ADC_13 = 0xDul, + ADC_14 = 0xEul, + ADC_15 = 0xFul, ADC_16 = 0x10ul, ADC_17 = 0x11ul, ADC_18 = 0x12ul, ADC_19 = 0x13ul } ADCName; +typedef enum { + DAC_0 = 0x42004800UL +} DACName; + typedef enum { // for each channel EXTINT_0 = 0, EXTINT_1, diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.c index f36fdd2d80..c7f35b9743 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.c @@ -18,6 +18,8 @@ /************ADC***************/ const PinMap PinMap_ADC[] = { + {PA02, ADC_0, 1}, + {PA03, ADC_1, 1}, {PB08, ADC_2, 1}, {PB09, ADC_3, 1}, {PA04, ADC_4, 1}, @@ -25,8 +27,13 @@ const PinMap PinMap_ADC[] = { {PA06, ADC_6, 1}, {PA07, ADC_7, 1}, {PB00, ADC_8, 1}, + {PB01, ADC_9, 1}, {PB02, ADC_10, 1}, {PB03, ADC_11, 1}, + {PB04, ADC_12, 1}, + {PB05, ADC_13, 1}, + {PB06, ADC_14, 1}, + {PB07, ADC_15, 1}, {PA08, ADC_16, 1}, {PA09, ADC_17, 1}, {PA10, ADC_18, 1}, @@ -36,6 +43,14 @@ const PinMap PinMap_ADC[] = { {NC , NC , NC} }; +/************DAC***************/ +const PinMap PinMap_DAC[] = { + {PA02, DAC_0, 1}, + + /* Not connected */ + {NC , NC , NC} +}; + /************SERCOM Pins***********/ const PinMap PinMap_SERCOM_PAD[] = { {PA00, SERCOM1_PAD0, 3}, diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.h index 0571b092e6..9c66f5587a 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/PeripheralPins.h @@ -23,7 +23,10 @@ /************ADC***************/ extern const PinMap PinMap_ADC[]; -//*********SERCOM*************/ +/************DAC***************/ +extern const PinMap PinMap_DAC[]; + +/*********SERCOM*************/ extern const PinMap PinMap_SERCOM_PAD[]; extern const PinMap PinMap_SERCOM_PADEx[]; diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/analogout_api.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/analogout_api.c index 456b75ddc6..ecef528e2b 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/analogout_api.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMD21J18A/analogout_api.c @@ -19,36 +19,89 @@ #include "cmsis.h" #include "pinmap.h" #include "PeripheralPins.h" +#include "dac.h" + +struct dac_module dac_instance; +extern uint8_t g_sys_init; + +#define MAX_VAL_10BIT 0x03FF void analogout_init(dac_t *obj, PinName pin) { + MBED_ASSERT(obj); + if (g_sys_init == 0) { + system_init(); + g_sys_init = 1; + } + + struct dac_chan_config config_dac_chan; + uint32_t pos_input = 0; + pos_input = pinmap_find_peripheral(pin, PinMap_DAC); + MBED_ASSERT(pos_input != NC); + + obj->dac = DAC_0; + + dac_get_config_defaults(&(obj->config_dac)); + dac_init(&dac_instance, DAC, &(obj->config_dac)); + + dac_chan_get_config_defaults(&config_dac_chan); + dac_chan_set_config(&dac_instance, DAC_CHANNEL_0, &config_dac_chan); + dac_chan_enable(&dac_instance, DAC_CHANNEL_0); + + dac_enable(&dac_instance); } -void analogout_free(dac_t *obj) {} - -static inline void dac_write(dac_t *obj, int value) +void analogout_free(dac_t *obj) { -} + MBED_ASSERT(obj); + struct system_pinmux_config pin_conf; -static inline int dac_read(dac_t *obj) -{ - return 0; + dac_disable(&dac_instance); + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; + pin_conf.powersave = false; + pin_conf.mux_position = SYSTEM_PINMUX_GPIO; + system_pinmux_pin_set_config(PA02, &pin_conf); /*PA04 is the only DAC pin available*/ } void analogout_write(dac_t *obj, float value) { + MBED_ASSERT(obj); + uint32_t count_val = 0; + if (value < 0.0) { + count_val = 0; + } else if (value > 1.0) { + count_val = (uint32_t)MAX_VAL_10BIT; + } else { + count_val = (uint32_t) (value * (float)MAX_VAL_10BIT); + } + dac_chan_write(&dac_instance, DAC_CHANNEL_0, (uint16_t)count_val); + } void analogout_write_u16(dac_t *obj, uint16_t value) { + MBED_ASSERT(obj); + uint32_t count_val; + count_val = (uint32_t)((value * (float)MAX_VAL_10BIT) / 0xFFFF); /*Normalization to the value 0xFFFF*/ + dac_chan_write(&dac_instance, DAC_CHANNEL_0, (uint16_t)count_val); + } float analogout_read(dac_t *obj) { - return 0.0; + MBED_ASSERT(obj); + uint32_t data_val = 0; + Dac *const dac_module = (uint32_t)obj->dac; + data_val = dac_module->DATA.reg; + return data_val/(float)MAX_VAL_10BIT; } uint16_t analogout_read_u16(dac_t *obj) { - return 0; + MBED_ASSERT(obj); + uint32_t data_val = 0; + Dac *const dac_module = (uint32_t)obj->dac; + data_val = dac_module->DATA.reg; + return (uint16_t)((data_val /MAX_VAL_10BIT) * 0xFFFF); /*Normalization to the value 0xFFFF*/ } diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac.h new file mode 100644 index 0000000000..d925388bfd --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac.h @@ -0,0 +1,207 @@ +/** + * \file + * + * \brief SAM Peripheral Digital-to-Analog Converter Driver + * + * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ +#ifndef DAC_H_INCLUDED +#define DAC_H_INCLUDED + + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * \addtogroup asfdoc_sam0_dac_group + * + * @{ + */ + +/** + * Define DAC features set according to different device families. + * @{ + */ +#if (SAMD21 || SAMD10 || SAMD11 || SAMDA1) +# define FEATURE_DAC_DATABUF_WRITE_PROTECTION +#endif +/**@}*/ + +#ifndef DAC_TIMEOUT +# define DAC_TIMEOUT 0xFFFF +#endif + +#if DAC_CALLBACK_MODE == true +# include + +/** Forward definition of the device instance. */ +struct dac_module; + +#if !defined(__DOXYGEN__) +extern struct dac_module *_dac_instances[DAC_INST_NUM]; +#endif + +/** Type definition for a DAC module callback function. */ +typedef void (*dac_callback_t)(uint8_t channel); + +/** Enum for the possible callback types for the DAC module. */ +enum dac_callback { + /** Callback type for when a DAC channel data empty condition occurs + * (requires event triggered mode) */ + DAC_CALLBACK_DATA_EMPTY, + + /** Callback type for when a DAC channel data underrun condition occurs + * (requires event triggered mode) */ + DAC_CALLBACK_DATA_UNDERRUN, + + /** Callback type for when a DAC channel write buffer job complete (requires + * event triggered mode) */ + DAC_CALLBACK_TRANSFER_COMPLETE, +#if !defined(__DOXYGEN__) + DAC_CALLBACK_N, +#endif +}; + +#endif + +#include + +/** + * \name Configuration and Initialization + * @{ + */ + +bool dac_is_syncing( + struct dac_module *const dev_inst); + +void dac_get_config_defaults( + struct dac_config *const config); + +enum status_code dac_init( + struct dac_module *const dev_inst, + Dac *const module, + struct dac_config *const config); + +void dac_reset( + struct dac_module *const dev_inst); + +void dac_enable( + struct dac_module *const dev_inst); + +void dac_disable( + struct dac_module *const dev_inst); + +void dac_enable_events( + struct dac_module *const module_inst, + struct dac_events *const events); + +void dac_disable_events( + struct dac_module *const module_inst, + struct dac_events *const events); + +/** @} */ + +/** + * \name Configuration and Initialization (Channel) + * @{ + */ + +void dac_chan_get_config_defaults( + struct dac_chan_config *const config); + +void dac_chan_set_config( + struct dac_module *const dev_inst, + const enum dac_channel channel, + struct dac_chan_config *const config); + +void dac_chan_enable( + struct dac_module *const dev_inst, + enum dac_channel channel); + +void dac_chan_disable( + struct dac_module *const dev_inst, + enum dac_channel channel); + +/** @} */ + +/** + * \name Channel Data Management + * @{ + */ + +enum status_code dac_chan_write( + struct dac_module *const dev_inst, + enum dac_channel channel, + const uint16_t data); + +enum status_code dac_chan_write_buffer_wait( + struct dac_module *const module_inst, + enum dac_channel channel, + uint16_t *buffer, + uint32_t length); + +/** @} */ + +/** + * \name Status Management + * @{ + */ +uint32_t dac_get_status( + struct dac_module *const module_inst); +void dac_clear_status( + struct dac_module *const module_inst, + uint32_t status_flags); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + + +#endif /* DAC_H_INCLUDED */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac.c new file mode 100644 index 0000000000..ef476f1b97 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac.c @@ -0,0 +1,774 @@ +/** + * \file + * + * \brief SAM Peripheral Digital-to-Analog Converter Driver + * + * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ +#include "dac.h" +#include +#include + +/** + * \internal Writes a DAC configuration to the hardware module. + * + * Writes out a given configuration to the hardware module. + * + * \param[out] module_inst Pointer to the DAC software instance struct + * \param[in] config Pointer to the configuration struct + * + */ +static void _dac_set_config( + struct dac_module *const module_inst, + struct dac_config *const config) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(config); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + /* Set selected DAC output to be enabled when enabling the module */ + module_inst->output = config->output; + module_inst->start_on_event = false; + + uint32_t new_ctrla = 0; + uint32_t new_ctrlb = 0; + + /* Enable DAC in standby sleep mode if configured */ + if (config->run_in_standby) { + new_ctrla |= DAC_CTRLA_RUNSTDBY; + } + + /* Set reference voltage */ + new_ctrlb |= config->reference; + + /* Left adjust data if configured */ + if (config->left_adjust) { + new_ctrlb |= DAC_CTRLB_LEFTADJ; + } + +#ifdef FEATURE_DAC_DATABUF_WRITE_PROTECTION + /* Bypass DATABUF write protection if configured */ + if (config->databuf_protection_bypass) { + new_ctrlb |= DAC_CTRLB_BDWP; + } +#endif + + /* Voltage pump disable if configured */ + if (config->voltage_pump_disable) { + new_ctrlb |= DAC_CTRLB_VPD; + } + + /* Apply the new configuration to the hardware module */ + dac_module->CTRLA.reg = new_ctrla; + + while (dac_is_syncing(module_inst)) { + /* Wait until the synchronization is complete */ + } + + dac_module->CTRLB.reg = new_ctrlb; +} + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus, This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] dev_inst Pointer to the DAC software instance struct + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval true If the module synchronization is ongoing + * \retval false If the module has completed synchronization + */ +bool dac_is_syncing( + struct dac_module *const dev_inst) +{ + /* Sanity check arguments */ + Assert(dev_inst); + + Dac *const dac_module = dev_inst->hw; + +#if (SAMC21) + if (dac_module->SYNCBUSY.reg) { +#else + if (dac_module->STATUS.reg & DAC_STATUS_SYNCBUSY) { +#endif + return true; + } + + return false; +} + +/** + * \brief Initializes a DAC configuration structure to defaults. + * + * Initializes a given DAC configuration structure to a set of + * known default values. This function should be called on any new + * instance of the configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li 1V from internal bandgap reference + * \li Drive the DAC output to the VOUT pin + * \li Right adjust data + * \li GCLK generator 0 (GCLK main) clock source + * \li The output buffer is disabled when the chip enters STANDBY sleep + * mode + * + * \param[out] config Configuration structure to initialize to default values + */ +void dac_get_config_defaults( + struct dac_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->reference = DAC_REFERENCE_INT1V; + config->output = DAC_OUTPUT_EXTERNAL; + config->left_adjust = false; +#ifdef FEATURE_DAC_DATABUF_WRITE_PROTECTION + config->databuf_protection_bypass = false; +#endif + config->voltage_pump_disable = false; + config->clock_source = GCLK_GENERATOR_0; + config->run_in_standby = false; +#if (SAMC21) + config->dither_mode = false; +#endif +} + +/** + * \brief Initialize the DAC device struct. + * + * Use this function to initialize the Digital to Analog Converter. Resets the + * underlying hardware module and configures it. + * + * \note The DAC channel must be configured separately. + * + * \param[out] module_inst Pointer to the DAC software instance struct + * \param[in] module Pointer to the DAC module instance + * \param[in] config Pointer to the config struct, created by the user + * application + * + * \return Status of initialization. + * \retval STATUS_OK Module initiated correctly + * \retval STATUS_ERR_DENIED If module is enabled + * \retval STATUS_BUSY If module is busy resetting + */ +enum status_code dac_init( + struct dac_module *const module_inst, + Dac *const module, + struct dac_config *const config) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module); + Assert(config); + + /* Initialize device instance */ + module_inst->hw = module; + + /* Turn on the digital interface clock */ +#if (SAMC21) + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_DAC); +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_DAC); +#endif + + /* Check if module is enabled. */ + if (module->CTRLA.reg & DAC_CTRLA_ENABLE) { + return STATUS_ERR_DENIED; + } + + /* Check if reset is in progress. */ + if (module->CTRLA.reg & DAC_CTRLA_SWRST) { + return STATUS_BUSY; + } + + /* Configure GCLK channel and enable clock */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->clock_source; + system_gclk_chan_set_config(DAC_GCLK_ID, &gclk_chan_conf); + system_gclk_chan_enable(DAC_GCLK_ID); + + /* MUX the DAC VOUT pin */ + struct system_pinmux_config pin_conf; + system_pinmux_get_config_defaults(&pin_conf); + + /* Set up the DAC VOUT pin */ + pin_conf.mux_position = MUX_PA02B_DAC_VOUT; + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + system_pinmux_pin_set_config(PIN_PA02B_DAC_VOUT, &pin_conf); + + /* Write configuration to module */ + _dac_set_config(module_inst, config); + + /* Store reference selection for later use */ + module_inst->reference = config->reference; + +#if DAC_CALLBACK_MODE == true + for (uint8_t i = 0; i < DAC_CALLBACK_N; i++) { + module_inst->callback[i] = NULL; + }; + + _dac_instances[0] = module_inst; +#endif + + return STATUS_OK; +} + +/** + * \brief Resets the DAC module. + * + * This function will reset the DAC module to its power on default values and + * disable it. + * + * \param[in] module_inst Pointer to the DAC software instance struct + */ +void dac_reset( + struct dac_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + while (dac_is_syncing(module_inst)) { + /* Wait until the synchronization is complete */ + } + + /* Software reset the module */ + dac_module->CTRLA.reg |= DAC_CTRLA_SWRST; +} + +/** + * \brief Enable the DAC module. + * + * Enables the DAC interface and the selected output. If any internal reference + * is selected it will be enabled. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * + */ +void dac_enable( + struct dac_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + /* Enable selected output */ + dac_module->CTRLB.reg |= module_inst->output; + + while (dac_is_syncing(module_inst)) { + /* Wait until the synchronization is complete */ + } + + /* Enable the module */ + dac_module->CTRLA.reg |= DAC_CTRLA_ENABLE; + + /* Enable internal bandgap reference if selected in the configuration */ + if (module_inst->reference == DAC_REFERENCE_INT1V) { +#if (SAMC21) + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_OUTPUT); + } + + if(dac_module->CTRLA.reg & DAC_CTRLA_ENABLE) { + while(! (dac_module->STATUS.reg & DAC_STATUS_READY)) { + }; + } +#else + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP); + } + +#endif +} + +/** + * \brief Disable the DAC module. + * + * Disables the DAC interface and the output buffer. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * + */ +void dac_disable( + struct dac_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + /* Wait until the synchronization is complete */ + while (dac_is_syncing(module_inst)) { + }; + + /* Disable DAC */ + dac_module->CTRLA.reg &= ~DAC_CTRLA_ENABLE; +} + +/** + * \brief Enables a DAC event input or output. + * + * Enables one or more input or output events to or from the DAC module. See + * \ref dac_events "here" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the DAC peripheral + * \param[in] events Struct containing flags of events to enable + */ +void dac_enable_events( + struct dac_module *const module_inst, + struct dac_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Dac *const dac_module = module_inst->hw; + + uint32_t event_mask = 0; + +#if(SAMC21) + /* Configure Enable Inversion of input event */ + if (events->generate_event_on_chan_falling_edge) { + event_mask |= DAC_EVCTRL_INVEI; + } +#endif + + /* Configure Buffer Empty event */ + if (events->generate_event_on_buffer_empty) { + event_mask |= DAC_EVCTRL_EMPTYEO; + } + + /* Configure Conversion Start event */ + if (events->on_event_start_conversion) { + event_mask |= DAC_EVCTRL_STARTEI; + module_inst->start_on_event = true; + } + + dac_module->EVCTRL.reg |= event_mask; +} + +/** + * \brief Disables a DAC event input or output. + * + * Disables one or more input or output events to or from the DAC module. See + * \ref dac_events "here" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the DAC peripheral + * \param[in] events Struct containing flags of events to disable + */ +void dac_disable_events( + struct dac_module *const module_inst, + struct dac_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Dac *const dac_module = module_inst->hw; + + uint32_t event_mask = 0; + + /* Configure Buffer Empty event */ + if (events->generate_event_on_buffer_empty) { + event_mask |= DAC_EVCTRL_EMPTYEO; + } + + /* Configure Conversion Start event */ + if (events->on_event_start_conversion) { + event_mask |= DAC_EVCTRL_STARTEI; + module_inst->start_on_event = false; + } + + dac_module->EVCTRL.reg &= ~event_mask; +} + +/** + * \brief Initializes a DAC channel configuration structure to defaults. + * + * Initializes a given DAC channel configuration structure to a set of + * known default values. This function should be called on any new + * instance of the configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Start Conversion Event Input enabled + * \li Start Data Buffer Empty Event Output disabled + * + * \param[out] config Configuration structure to initialize to default values + */ +void dac_chan_get_config_defaults( + struct dac_chan_config *const config) +{ + /* Sanity check arguments */ + Assert(config); +} + +/** + * \brief Writes a DAC channel configuration to the hardware module. + * + * Writes a given channel configuration to the hardware module. + * + * \note The DAC device instance structure must be initialized before calling + * this function. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * \param[in] channel Channel to configure + * \param[in] config Pointer to the configuration struct + * + */ +void dac_chan_set_config( + struct dac_module *const module_inst, + const enum dac_channel channel, + struct dac_chan_config *const config) +{ + /* No channel support yet */ + UNUSED(channel); +} + +/** + * \brief Enable a DAC channel. + * + * Enables the selected DAC channel. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * \param[in] channel Channel to enable + * + */ +void dac_chan_enable( + struct dac_module *const module_inst, + enum dac_channel channel) +{ + /* No channel support yet */ + UNUSED(channel); +} + +/** + * \brief Disable a DAC channel. + * + * Disables the selected DAC channel. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * \param[in] channel Channel to disable + * + */ +void dac_chan_disable( + struct dac_module *const module_inst, + enum dac_channel channel) +{ + /* No channel support yet */ + UNUSED(channel); +} + +/** + * \brief Enable the output buffer. + * + * Enables the output buffer and drives the DAC output to the VOUT pin. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * \param[in] channel DAC channel to alter + */ +void dac_chan_enable_output_buffer( + struct dac_module *const module_inst, + enum dac_channel channel) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* No channel support yet */ + UNUSED(channel); + + Dac *const dac_module = module_inst->hw; + + /* Enable output buffer */ + dac_module->CTRLB.reg |= DAC_OUTPUT_EXTERNAL; +} + +/** + * \brief Disable the output buffer. + * + * Disables the output buffer. + * + * \note The output buffer(s) should be disabled when a channel's output is not + * currently needed, as it will draw current even if the system is in + * sleep mode. + * + * \param[in] module_inst Pointer to the DAC software instance struct + * \param[in] channel DAC channel to alter + */ +void dac_chan_disable_output_buffer( + struct dac_module *const module_inst, + enum dac_channel channel) +{ + /* Sanity check arguments*/ + Assert(module_inst); + Assert(module_inst->hw); + + /* No channel support yet */ + UNUSED(channel); + + Dac *const dac_module = module_inst->hw; + + /* Disable output buffer */ + dac_module->CTRLB.reg &= ~DAC_OUTPUT_EXTERNAL; +} + +/** + * \brief Write to the DAC. + * + * This function writes to the DATA or DATABUF register. + * If the conversion is not event-triggered, the data will be written to + * the DATA register and the conversion will start. + * If the conversion is event-triggered, the data will be written to DATABUF + * and transferred to the DATA register and converted when a Start Conversion + * Event is issued. + * Conversion data must be right or left adjusted according to configuration + * settings. + * \note To be event triggered, the enable_start_on_event must be + * enabled in the configuration. + * + * \param[in] module_inst Pointer to the DAC software device struct + * \param[in] channel DAC channel to write to + * \param[in] data Conversion data + * + * \return Status of the operation. + * \retval STATUS_OK If the data was written + */ +enum status_code dac_chan_write( + struct dac_module *const module_inst, + enum dac_channel channel, + const uint16_t data) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* No channel support yet */ + UNUSED(channel); + + Dac *const dac_module = module_inst->hw; + + /* Wait until the synchronization is complete */ + while (dac_is_syncing(module_inst)) { + }; + + if (module_inst->start_on_event) { + /* Write the new value to the buffered DAC data register */ + dac_module->DATABUF.reg = data; + } else { + /* Write the new value to the DAC data register */ + dac_module->DATA.reg = data; + } + + return STATUS_OK; +} + +/** + * \brief Write to the DAC. + * + * This function converts a specific number of digital data. + * The conversion should be event-triggered, the data will be written to DATABUF + * and transferred to the DATA register and converted when a Start Conversion + * Event is issued. + * Conversion data must be right or left adjusted according to configuration + * settings. + * \note To be event triggered, the enable_start_on_event must be + * enabled in the configuration. + * + * \param[in] module_inst Pointer to the DAC software device struct + * \param[in] channel DAC channel to write to + * \param[in] buffer Pointer to the digital data write buffer to be converted + * \param[in] length Length of the write buffer + * + * \return Status of the operation. + * \retval STATUS_OK If the data was written or no data conversion required + * \retval STATUS_ERR_UNSUPPORTED_DEV The DAC is not configured as using event trigger + * \retval STATUS_BUSY The DAC is busy to convert + */ +enum status_code dac_chan_write_buffer_wait( + struct dac_module *const module_inst, + enum dac_channel channel, + uint16_t *buffer, + uint32_t length) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* No channel support yet */ + UNUSED(channel); + + Dac *const dac_module = module_inst->hw; + + /* Wait until the synchronization is complete */ + while (dac_is_syncing(module_inst)) { + }; + + /* Zero length request */ + if (length == 0) { + /* No data to be converted */ + return STATUS_OK; + } + +#if DAC_CALLBACK_MODE == true + /* Check if busy */ + if (module_inst->job_status == STATUS_BUSY) { + return STATUS_BUSY; + } +#endif + + /* Only support event triggered conversion */ + if (module_inst->start_on_event == false) { + return STATUS_ERR_UNSUPPORTED_DEV; + } + + /* Blocks while buffer is being transferred */ + while (length--) { + /* Convert one data */ + dac_chan_write(module_inst, channel, buffer[length]); + + /* Wait until Transmit is complete or timeout */ + for (uint32_t i = 0; i <= DAC_TIMEOUT; i++) { + if (dac_module->INTFLAG.reg & DAC_INTFLAG_EMPTY) { + break; + } else if (i == DAC_TIMEOUT) { + return STATUS_ERR_TIMEOUT; + } + } + } + + return STATUS_OK; +} + +/** + * \brief Retrieves the current module status + * + * Checks the status of the module and returns it as a bitmask of status + * flags. + * + * \param[in] module_inst Pointer to the DAC software device struct + * + * \return Bitmask of status flags. + * + * \retval DAC_STATUS_CHANNEL_0_EMPTY Data has been transferred from DATABUF + * to DATA by a start conversion event + * and DATABUF is ready for new data + * \retval DAC_STATUS_CHANNEL_0_UNDERRUN A start conversion event has occurred + * when DATABUF is empty + * + */ +uint32_t dac_get_status( + struct dac_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + uint8_t intflags = dac_module->INTFLAG.reg; + uint32_t status_flags = 0; + + if (intflags & DAC_INTFLAG_EMPTY) { + status_flags |= DAC_STATUS_CHANNEL_0_EMPTY; + } + + if (intflags & DAC_INTFLAG_UNDERRUN) { + status_flags |= DAC_STATUS_CHANNEL_0_UNDERRUN; + } + + return status_flags; +} + +/** + * \brief Clears a module status flag + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the DAC software device struct + * \param[in] status_flags Bit mask of status flags to clear + * + */ +void dac_clear_status( + struct dac_module *const module_inst, + uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Dac *const dac_module = module_inst->hw; + + uint32_t intflags = 0; + + if (status_flags & DAC_STATUS_CHANNEL_0_EMPTY) { + intflags |= DAC_INTFLAG_EMPTY; + } + + if (status_flags & DAC_STATUS_CHANNEL_0_UNDERRUN) { + intflags |= DAC_INTFLAG_UNDERRUN; + } + + dac_module->INTFLAG.reg = intflags; +} diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac_feature.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac_feature.h new file mode 100644 index 0000000000..8203d7ee09 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/TARGET_SAMD21/dac/dac_sam_d_c/dac_feature.h @@ -0,0 +1,635 @@ +/** + * \file + * + * \brief SAM Peripheral Digital-to-Analog Converter Driver + * + * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ +#ifndef DAC_FEATURE_H_INCLUDED +#define DAC_FEATURE_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_dac_group SAM Digital-to-Analog Driver (DAC) + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the conversion of + * digital values to analog voltage. The following driver API modes are covered + * by this manual: + * + * - Polled APIs + * \if DAC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripherals are used by this module: + * - DAC (Digital-to-Analog Converter) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM D10/D11 + * - Atmel | SMART SAM DA0/DA1 + * - Atmel | SMART SAM C21 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_dac_prerequisites + * - \ref asfdoc_sam0_dac_module_overview + * - \ref asfdoc_sam0_dac_special_considerations + * - \ref asfdoc_sam0_dac_extra_info + * - \ref asfdoc_sam0_dac_examples + * - \ref asfdoc_sam0_dac_api_overview + * + * + * \section asfdoc_sam0_dac_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_dac_module_overview Module Overview + * + * The Digital-to-Analog converter converts a digital value to analog voltage. + * The SAM DAC module has one channel with 10-bit resolution, + * and is capable of converting up to 350k samples per second (ksps). + * + * A common use of DAC is to generate audio signals by connecting the DAC + * output to a speaker, or to generate a reference voltage; either for an + * external circuit or an internal peripheral such as the Analog Comparator. + * + * After being set up, the DAC will convert new digital values written to the + * conversion data register (DATA) to an analog value either on the VOUT pin of + * the device, or internally for use as an input to the AC, ADC, and other analog + * modules. + * + * Writing the DATA register will start a new conversion. It is also possible + * to trigger the conversion from the event system. + * + * A simplified block diagram of the DAC can be seen in + * \ref asfdoc_sam0_dac_module_block_diagram "the figure below". + * + * \anchor asfdoc_sam0_dac_module_block_diagram + * \image html dac_block_diagram.svg "DAC Block Diagram" + * + * \subsection asfdoc_sam0_dac_conversion_range Conversion Range + * The conversion range is between GND and the selected voltage reference. + * Available voltage references are: + * \li AVCC voltage reference + * \li Internal 1V reference (INT1V) + * \li External voltage reference (AREF) + * + * \note Internal references will be enabled by the driver, but not disabled. + * Any reference not used by the application should be disabled by the application. + * + * The output voltage from a DAC channel is given as: + * \f[ + * V_{OUT} = \frac{DATA}{0x3FF} \times VREF + * \f] + * + * \subsection asfdoc_sam0_dac_conversion Conversion + * The digital value written to the conversion data register (DATA) will be + * converted to an analog value. + * Writing the DATA register will start a new conversion. + * It is also possible to write the conversion data to the DATABUF register, + * the writing of the DATA register can then be triggered from the event + * system, which will load the value from DATABUF to DATA. + * + * \subsection asfdoc_sam0_dac_analog_output Analog Output + * The analog output value can be output to either the VOUT pin or internally, + * but not both at the same time. + * + * \subsubsection asfdoc_sam0_dac_analog_output_external External Output + * The output buffer must be enabled in order to drive the DAC output to the + * VOUT pin. Due to the output buffer, the DAC has high drive strength, and is + * capable of driving both resistive and capacitive loads, as well as loads + * which combine both. + * + * \subsubsection asfdoc_sam0_dac_analog_output_internal Internal Output + * The analog value can be internally available for use as input to the + * AC or ADC modules. + * + * \subsection asfdoc_sam0_dac_events Events + * Events generation and event actions are configurable in the DAC. + * The DAC has one event line input and one event output: Start Conversion + * and Data Buffer Empty. + * + * If the Start Conversion input event is enabled in the module configuration, + * an incoming event will load data from the data buffer to the data register + * and start a new conversion. This method synchronizes conversions with + * external events (such as those from a timer module) and ensures regular and + * fixed conversion intervals. + * + * If the Data Buffer Empty output event is enabled in the module configuration, + * events will be generated when the DAC data buffer register becomes empty and + * new data can be loaded to the buffer. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * \subsection asfdoc_sam0_dac_data_adjust Left and Right Adjusted Values + * The 10-bit input value to the DAC is contained in a 16-bit register. This + * can be configured to be either left or right adjusted. In + * \ref asfdoc_sam0_dac_module_adj_modes "the figure below" both options are + * shown, and the position of the most (MSB) and the least (LSB) significant bits + * are indicated. The unused bits should always be written to zero. + * + * \anchor asfdoc_sam0_dac_module_adj_modes + * \dot + * digraph { + * subgraph cluster_right { + * msbl [label="MSB", shape=none, group="msbl"]; + * lsbl [label="LSB", shape=none]; + * node [shape=none]; + * color="white"; + * reg_left [label=< + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
1514131211109876543210
DATA[9:0]
+ * >]; + * msbl -> reg_left:msb:n; + * lsbl -> reg_left:lsb; + * label ="Left adjusted.\n"; + * } + * subgraph cluster_left { + * rankdir=TB; + * msb [label="MSB", shape=none]; + * lsb [label="LSB", shape=none]; + * color="white"; + * node [shape=none]; + * reg_right [label=< + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
1514131211109876543210
DATA[9:0]
+ * >]; + * msb -> reg_right:msb; + * lsb -> reg_right:lsb:n; + * label = "Right adjusted.\n"; + * graph [shape=none]; + * } + * } + * \enddot + * + * \subsection asfdoc_sam0_dac_clk_sources Clock Sources + * The clock for the DAC interface (CLK_DAC) is generated by the Power Manager. + * This clock is turned on by default, and can be enabled and disabled in the + * Power Manager. + * + * Additionally, an asynchronous clock source (GCLK_DAC) is required. + * These clocks are normally disabled by default. The selected clock source + * must be enabled in the Power Manager before it can be used by the DAC. + * The DAC core operates asynchronously from the user interface and + * peripheral bus. As a consequence, the DAC needs two clock cycles of both + * CLK_DAC and GCLK_DAC to synchronize the values written to some of the + * control and data registers. + * The oscillator source for the GCLK_DAC clock is selected in the System + * Control Interface (SCIF). + * + * \section asfdoc_sam0_dac_special_considerations Special Considerations + * + * \subsection asfdoc_sam0_dac_special_considerations_output_buffer Output Driver + * The DAC can only do conversions in Active or Idle modes. However, if the + * output buffer is enabled it will draw current even if the system is in + * sleep mode. Therefore, always make sure that the output buffer is not + * enabled when it is not needed, to ensure minimum power consumption. + * + * \subsection asfdoc_sam0_dac_special_considerations_conversion_time Conversion Time + * DAC conversion time is approximately 2.85µs. The user must ensure that new + * data is not written to the DAC before the last conversion is complete. + * Conversions should be triggered by a periodic event from a Timer/Counter or + * another peripheral. + * + * + * \section asfdoc_sam0_dac_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_dac_extra. This includes: + * - \ref asfdoc_sam0_dac_extra_acronyms + * - \ref asfdoc_sam0_dac_extra_dependencies + * - \ref asfdoc_sam0_dac_extra_errata + * - \ref asfdoc_sam0_dac_extra_history + * + * + * \section asfdoc_sam0_dac_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_dac_exqsg. + * + * + * \section asfdoc_sam0_dac_api_overview API Overview + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + + +/** + * \name DAC Status Flags + * + * DAC status flags, returned by \ref dac_get_status() and cleared by + * \ref dac_clear_status(). + * @{ + */ + +/** Data Buffer Empty Channel 0 - Set when data is transferred from DATABUF + * to DATA by a start conversion event and DATABUF is ready for new data. + */ +#define DAC_STATUS_CHANNEL_0_EMPTY (1UL << 0) + +/** Under-run Channel 0 - Set when a start conversion event occurs when + * DATABUF is empty. + */ +#define DAC_STATUS_CHANNEL_0_UNDERRUN (1UL << 1) + +/** @} */ + +/** + * \brief DAC reference voltage enum. + * + * Enum for the possible reference voltages for the DAC. + */ +enum dac_reference { + /** 1V from the internal band-gap reference.*/ + DAC_REFERENCE_INT1V = DAC_CTRLB_REFSEL(0), + /** Analog VCC as reference. */ + DAC_REFERENCE_AVCC = DAC_CTRLB_REFSEL(1), + /** External reference on AREF. */ + DAC_REFERENCE_AREF = DAC_CTRLB_REFSEL(2), +}; + +/** + * \brief DAC output selection enum. + * + * Enum for the DAC output selection. + */ +enum dac_output { + /** DAC output to VOUT pin */ + DAC_OUTPUT_EXTERNAL = DAC_CTRLB_EOEN, + /** DAC output as internal reference */ + DAC_OUTPUT_INTERNAL = DAC_CTRLB_IOEN, + /** No output */ + DAC_OUTPUT_NONE = 0, +}; + +/** + * \brief DAC channel selection enum. + * + * Enum for the DAC channel selection. + */ +enum dac_channel { + /** DAC output channel 0. */ + DAC_CHANNEL_0, +}; + +/** + * \brief DAC software device instance structure. + * + * DAC software instance structure, used to retain software state information + * of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct dac_module { +#if !defined(__DOXYGEN__) + /** DAC hardware module. */ + Dac *hw; + /** DAC output selection. */ + enum dac_output output; + /** Reference selection. */ + enum dac_reference reference; + /** DAC event selection. */ + bool start_on_event; +# if DAC_CALLBACK_MODE == true + /** Pointer to buffer used for ADC results. */ + volatile uint16_t *job_buffer; + /** Remaining number of conversions in current job. */ + volatile uint16_t remaining_conversions; + /** Transferred number of conversions in current job. */ + volatile uint16_t transferred_conversions; + /** DAC callback enable. */ + bool callback_enable[DAC_CALLBACK_N]; + /** DAC registered callback functions. */ + dac_callback_t callback[DAC_CALLBACK_N]; + /** Holds the status of the ongoing or last conversion job. */ + volatile enum status_code job_status; +# endif +#endif +}; + +/** + * \brief DAC configuration structure. + * + * Configuration structure for a DAC instance. This structure should be + * initialized by the \ref dac_get_config_defaults() + * function before being modified by the user application. + */ +struct dac_config { + /** Reference voltage. */ + enum dac_reference reference; + /** Select DAC output. */ + enum dac_output output; + /** Left adjusted data. */ + bool left_adjust; + /** GCLK generator used to clock the peripheral. */ + enum gclk_generator clock_source; +#ifdef FEATURE_DAC_DATABUF_WRITE_PROTECTION + /** Bypass DATABUF write protection. */ + bool databuf_protection_bypass; +#endif + /** Voltage pump disable. */ + bool voltage_pump_disable; + /** + * The DAC behaves as in normal mode when the chip enters STANDBY sleep + * mode. + */ + bool run_in_standby; +#if (SAMC21) + /** Dither mode enable data. */ + bool dither_mode; +#endif +}; + +/** + * \brief DAC event enable/disable structure. + * + * Event flags for the DAC module. This is used to enable and + * disable events via \ref dac_enable_events() and \ref dac_disable_events(). + */ +struct dac_events { + /** Start a new DAC conversion. */ + bool on_event_start_conversion; + /** Enable event generation on data buffer empty. */ + bool generate_event_on_buffer_empty; +#if (SAMC21) + /** Enable the falling edge of the input event for DAC1. */ + bool generate_event_on_chan_falling_edge; +#endif +}; + +/** + * \brief DAC channel configuration structure + * + * Configuration for a DAC channel. This structure should be initialized by the + * \ref dac_chan_get_config_defaults() function before being modified by the + * user application. + */ +struct dac_chan_config { +#if !defined(__DOXYGEN__) + /** Dummy value to ensure the struct has at least one member. */ + uint8_t _dummy; +#endif +}; + +/** + * \name Configuration and Initialization (Channel) + * @{ + */ + +void dac_chan_enable_output_buffer( + struct dac_module *const dev_inst, + const enum dac_channel channel); + +void dac_chan_disable_output_buffer( + struct dac_module *const dev_inst, + const enum dac_channel channel); + +/** @} */ + +/** @} */ + +/** + * \page asfdoc_sam0_dac_extra Extra Information for DAC Driver + * + * \section asfdoc_sam0_dac_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
ADCAnalog-to-Digital Converter
ACAnalog Comparator
DACDigital-to-Analog Converter
LSBLeast Significant Bit
MSBMost Significant Bit
DMADirect Memory Access
+ * + * + * \section asfdoc_sam0_dac_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_dac_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_dac_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Add configuration for using 14-bit hardware dithering (SAMC21 support)
Added new configuration parameters \c databuf_protection_bypass, + * \c voltage_pump_disable. Added new callback functions + * \c dac_chan_write_buffer_wait, + * \c dac_chan_write_buffer_job, \c dac_chan_write_job, + * \c dac_get_job_status, \c dac_abort_job and new callback type + * \c DAC_CALLBACK_TRANSFER_COMPLETE for DAC conversion job
Initial Release
+ */ + +/** + * \page asfdoc_sam0_dac_exqsg Examples for DAC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_dac_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_dac_basic_use_case + * \if DAC_CALLBACK_MODE + * - \subpage asfdoc_sam0_dac_basic_use_case_callback + * \endif + * \if DAC_DMA_USE_MODE_SELECTION + * - \subpage asfdoc_sam0_adc_dma_use_case_dac_in_dma + * \endif + * + * \if DAC_DMA_USE_MODE_SELECTION + * \page asfdoc_sam0_adc_dma_use_case_dac_in_dma Quick Start Guide for Using DMA with ADC/DAC + * For this examples, see + * \ref asfdoc_sam0_adc_dma_use_case + * \endif + * + * \page asfdoc_sam0_dac_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42110E06/2015Add SAMC21 and SAMDAx support
42110D12/2014Add SAMD10/D11 support
42110C01/2014Add SAMD21 support
42110B06/2013Added additional documentation on the event system. Corrected + * documentation typos.
42110A06/2013Initial document release
+ */ + +#ifdef __cplusplus +} +#endif + + +#endif /* DAC_FEATURE_H_INCLUDED */ + diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0+/objects.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0+/objects.h index 35dd257769..8e060caf9d 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0+/objects.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0+/objects.h @@ -28,6 +28,10 @@ #include "i2c_slave.h" #include "dma_api.h" +#if DEVICE_ANALOGOUT +#include "dac.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -69,10 +73,16 @@ struct serial_s { struct analogin_s { ADCName adc; - struct adc_module adc_instance; struct adc_config config_adc; }; +#if DEVICE_ANALOGOUT +struct dac_s { + DACName dac; + struct dac_config config_dac; +}; +#endif + struct pwmout_s { struct tcc_module tcc; PinName pin;