blob: 91398d79ecc9f42a603620bff8653b23293b800d [file] [log] [blame]
/***************************************************************************//**
* @file em_vdac.h
* @brief Digital to Analog Converter (VDAC) peripheral API
* @version 5.6.0
*******************************************************************************
* # License
* <b>Copyright 2016 Silicon Laboratories, Inc. www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#ifndef EM_VDAC_H
#define EM_VDAC_H
#include "em_device.h"
#if defined(VDAC_COUNT) && (VDAC_COUNT > 0)
#include "em_assert.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup emlib
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup VDAC
* @brief Digital to Analog Voltage Converter (VDAC) Peripheral API
*
* @details
* This module contains functions to control the VDAC peripheral of Silicon
* Labs' 32-bit MCUs and SoCs. VDAC converts digital values to analog
* signals at up to 500 ksps with 12-bit accuracy. VDAC is designed for
* low energy consumption, but can also provide very good performance.
*
* The following steps are necessary for basic operation:
*
* Clock enable:
* @code
CMU_ClockEnable(cmuClock_VDAC0, true);@endcode
*
* Initialize the VDAC with default settings and modify selected fields:
* @code
VDAC_Init_TypeDef vdacInit = VDAC_INIT_DEFAULT;
VDAC_InitChannel_TypeDef vdacChInit = VDAC_INITCHANNEL_DEFAULT;
// Set prescaler to get 1 MHz VDAC clock frequency.
vdacInit.prescaler = VDAC_PrescaleCalc(1000000, true, 0);
VDAC_Init(VDAC0, &vdacInit);
vdacChInit.enable = true;
VDAC_InitChannel(VDAC0, &vdacChInit, 0);@endcode
*
* Perform a conversion:
* @code
VDAC_ChannelOutputSet(VDAC0, 0, 250);@endcode
*
* @note The output stage of a VDAC channel consists of an on-chip operational
* amplifier (OPAMP) in the OPAMP module. This OPAMP is highly configurable;
* and to exploit the VDAC functionality fully, configure the OPAMP using
* the OPAMP API. Using the OPAMP API also loads OPAMP calibration values.
* The default (reset) settings of OPAMP is sufficient for many applications.
* @{
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of VDAC register block pointer reference for assert statements.*/
#define VDAC_REF_VALID(ref) ((ref) == VDAC0)
/** @endcond */
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Channel refresh period. */
typedef enum {
vdacRefresh8 = _VDAC_CTRL_REFRESHPERIOD_8CYCLES, /**< Refresh every 8 clock cycles. */
vdacRefresh16 = _VDAC_CTRL_REFRESHPERIOD_16CYCLES, /**< Refresh every 16 clock cycles. */
vdacRefresh32 = _VDAC_CTRL_REFRESHPERIOD_32CYCLES, /**< Refresh every 32 clock cycles. */
vdacRefresh64 = _VDAC_CTRL_REFRESHPERIOD_64CYCLES, /**< Refresh every 64 clock cycles. */
} VDAC_Refresh_TypeDef;
/** Reference voltage for VDAC. */
typedef enum {
vdacRef1V25Ln = _VDAC_CTRL_REFSEL_1V25LN, /**< Internal low noise 1.25 V band gap reference. */
vdacRef2V5Ln = _VDAC_CTRL_REFSEL_2V5LN, /**< Internal low noise 2.5 V band gap reference. */
vdacRef1V25 = _VDAC_CTRL_REFSEL_1V25, /**< Internal 1.25 V band gap reference. */
vdacRef2V5 = _VDAC_CTRL_REFSEL_2V5, /**< Internal 2.5 V band gap reference. */
vdacRefAvdd = _VDAC_CTRL_REFSEL_VDD, /**< AVDD reference. */
vdacRefExtPin = _VDAC_CTRL_REFSEL_EXT, /**< External pin reference. */
} VDAC_Ref_TypeDef;
/** Peripheral Reflex System signal used to trigger VDAC channel conversion. */
typedef enum {
vdacPrsSelCh0 = _VDAC_CH0CTRL_PRSSEL_PRSCH0, /**< PRS ch 0 triggers conversion. */
vdacPrsSelCh1 = _VDAC_CH0CTRL_PRSSEL_PRSCH1, /**< PRS ch 1 triggers conversion. */
vdacPrsSelCh2 = _VDAC_CH0CTRL_PRSSEL_PRSCH2, /**< PRS ch 2 triggers conversion. */
vdacPrsSelCh3 = _VDAC_CH0CTRL_PRSSEL_PRSCH3, /**< PRS ch 3 triggers conversion. */
vdacPrsSelCh4 = _VDAC_CH0CTRL_PRSSEL_PRSCH4, /**< PRS ch 4 triggers conversion. */
vdacPrsSelCh5 = _VDAC_CH0CTRL_PRSSEL_PRSCH5, /**< PRS ch 5 triggers conversion. */
vdacPrsSelCh6 = _VDAC_CH0CTRL_PRSSEL_PRSCH6, /**< PRS ch 6 triggers conversion. */
vdacPrsSelCh7 = _VDAC_CH0CTRL_PRSSEL_PRSCH7, /**< PRS ch 7 triggers conversion. */
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH8)
vdacPrsSelCh8 = _VDAC_CH0CTRL_PRSSEL_PRSCH8, /**< PRS ch 8 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH9)
vdacPrsSelCh9 = _VDAC_CH0CTRL_PRSSEL_PRSCH9, /**< PRS ch 9 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH10)
vdacPrsSelCh10 = _VDAC_CH0CTRL_PRSSEL_PRSCH10, /**< PRS ch 10 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH11)
vdacPrsSelCh11 = _VDAC_CH0CTRL_PRSSEL_PRSCH11, /**< PRS ch 11 triggers conversion. */
#endif
} VDAC_PrsSel_TypeDef;
/** Channel conversion trigger mode. */
typedef enum {
vdacTrigModeSw = _VDAC_CH0CTRL_TRIGMODE_SW, /**< Channel is triggered by CHnDATA or COMBDATA write. */
vdacTrigModePrs = _VDAC_CH0CTRL_TRIGMODE_PRS, /**< Channel is triggered by PRS input. */
vdacTrigModeRefresh = _VDAC_CH0CTRL_TRIGMODE_REFRESH, /**< Channel is triggered by Refresh timer. */
vdacTrigModeSwPrs = _VDAC_CH0CTRL_TRIGMODE_SWPRS, /**< Channel is triggered by CHnDATA/COMBDATA write or PRS input. */
vdacTrigModeSwRefresh = _VDAC_CH0CTRL_TRIGMODE_SWREFRESH, /**< Channel is triggered by CHnDATA/COMBDATA write or Refresh timer. */
vdacTrigModeLesense = _VDAC_CH0CTRL_TRIGMODE_LESENSE, /**< Channel is triggered by LESENSE. */
} VDAC_TrigMode_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** VDAC initialization structure, common for both channels. */
typedef struct {
/** Selects between main and alternate output path calibration values. */
bool mainCalibration;
/** Selects clock from asynchronous or synchronous (with respect to
peripheral clock) source. */
bool asyncClockMode;
/** Warm-up mode, keep VDAC on (in idle) - or shutdown between conversions.*/
bool warmupKeepOn;
/** Channel refresh period. */
VDAC_Refresh_TypeDef refresh;
/** Prescaler for VDAC clock. Clock is source clock divided by prescaler+1. */
uint32_t prescaler;
/** Reference voltage to use. */
VDAC_Ref_TypeDef reference;
/** Enable/disable reset of prescaler on CH 0 start. */
bool ch0ResetPre;
/** Enable/disable output enable control by CH1 PRS signal. */
bool outEnablePRS;
/** Enable/disable sine mode. */
bool sineEnable;
/** Select if single ended or differential output mode. */
bool diff;
} VDAC_Init_TypeDef;
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT \
{ \
true, /* Use main output path calibration values. */ \
false, /* Use synchronous clock mode. */ \
false, /* Turn off between sample off conversions.*/ \
vdacRefresh8, /* Refresh every 8th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25Ln, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* VDAC output enable always on. */ \
false, /* Disable sine mode. */ \
false /* Single ended mode. */ \
}
/** VDAC channel initialization structure. */
typedef struct {
/** Enable channel. */
bool enable;
/**
* Peripheral reflex system trigger selection. Only applicable if @p trigMode
* is set to @p vdacTrigModePrs or @p vdacTrigModeSwPrs. */
VDAC_PrsSel_TypeDef prsSel;
/** Treat the PRS signal asynchronously. */
bool prsAsync;
/** Channel conversion trigger mode. */
VDAC_TrigMode_TypeDef trigMode;
/** Set channel conversion mode to sample/shut-off mode. Default is
* continuous.*/
bool sampleOffMode;
} VDAC_InitChannel_TypeDef;
/** Default configuration for VDAC channel initialization structure. */
#define VDAC_INITCHANNEL_DEFAULT \
{ \
false, /* Leave channel disabled when initialization is done. */ \
vdacPrsSelCh0, /* PRS CH 0 triggers conversion. */ \
false, /* Treat PRS channel as a synchronous signal. */ \
vdacTrigModeSw, /* Conversion trigged by CH0DATA or COMBDATA write. */ \
false, /* Channel conversion set to continuous. */ \
}
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
void VDAC_ChannelOutputSet(VDAC_TypeDef *vdac,
unsigned int channel,
uint32_t value);
void VDAC_Enable(VDAC_TypeDef *vdac, unsigned int ch, bool enable);
void VDAC_Init(VDAC_TypeDef *vdac, const VDAC_Init_TypeDef *init);
void VDAC_InitChannel(VDAC_TypeDef *vdac,
const VDAC_InitChannel_TypeDef *init,
unsigned int ch);
/***************************************************************************//**
* @brief
* Set the output signal of VDAC channel 0 to a given value.
*
* @details
* This function sets the output signal of VDAC channel 0 by writing @p value
* to the CH0DATA register.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] value
* Value to write to channel 0 output register CH0DATA.
******************************************************************************/
__STATIC_INLINE void VDAC_Channel0OutputSet(VDAC_TypeDef *vdac,
uint32_t value)
{
EFM_ASSERT(value <= _VDAC_CH0DATA_MASK);
vdac->CH0DATA = value;
}
/***************************************************************************//**
* @brief
* Set the output signal of VDAC channel 1 to a given value.
*
* @details
* This function sets the output signal of VDAC channel 1 by writing @p value
* to the CH1DATA register.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] value
* Value to write to channel 1 output register CH1DATA.
******************************************************************************/
__STATIC_INLINE void VDAC_Channel1OutputSet(VDAC_TypeDef *vdac,
uint32_t value)
{
EFM_ASSERT(value <= _VDAC_CH1DATA_MASK);
vdac->CH1DATA = value;
}
/***************************************************************************//**
* @brief
* Clear one or more pending VDAC interrupts.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* Pending VDAC interrupt source to clear. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntClear(VDAC_TypeDef *vdac, uint32_t flags)
{
vdac->IFC = flags;
}
/***************************************************************************//**
* @brief
* Disable one or more VDAC interrupts.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntDisable(VDAC_TypeDef *vdac, uint32_t flags)
{
vdac->IEN &= ~flags;
}
/***************************************************************************//**
* @brief
* Enable one or more VDAC interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* VDAC_IntClear() prior to enabling the interrupt.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to enable. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntEnable(VDAC_TypeDef *vdac, uint32_t flags)
{
vdac->IEN |= flags;
}
/***************************************************************************//**
* @brief
* Get pending VDAC interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @return
* VDAC interrupt sources pending. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGet(VDAC_TypeDef *vdac)
{
return vdac->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending VDAC interrupt flags.
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @note
* Interrupt flags are not cleared by the use of this function.
*
* @return
* Pending and enabled VDAC interrupt sources.
* The return value is the bitwise AND combination of
* - the OR combination of enabled interrupt sources in VDACx_IEN_nnn
* register (VDACx_IEN_nnn) and
* - the OR combination of valid interrupt flags of the VDAC module
* (VDACx_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGetEnabled(VDAC_TypeDef *vdac)
{
uint32_t ien = vdac->IEN;
/* Bitwise AND of pending and enabled interrupts */
return vdac->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending VDAC interrupts from SW.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to set to pending. Use a bitwise logic OR
* combination of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntSet(VDAC_TypeDef *vdac, uint32_t flags)
{
vdac->IFS = flags;
}
uint32_t VDAC_PrescaleCalc(uint32_t vdacFreq, bool syncMode, uint32_t hfperFreq);
void VDAC_Reset(VDAC_TypeDef *vdac);
/** @} (end addtogroup VDAC) */
/** @} (end addtogroup emlib) */
#ifdef __cplusplus
}
#endif
#endif /* defined(VDAC_COUNT) && (VDAC_COUNT > 0) */
#endif /* EM_VDAC_H */