added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_dac.c
- Revision:
- 144:ef7eb2e8f9f7
- Parent:
- 50:a417edff4437
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_dac.c Tue Aug 02 14:07:36 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_dac.c Fri Sep 02 15:07:44 2016 +0100 @@ -1,341 +1,341 @@ -/***************************************************************************//** - * @file em_dac.c - * @brief Digital to Analog Coversion (DAC) Peripheral API - * @version 4.2.1 - ******************************************************************************* - * @section License - * <b>(C) Copyright 2015 Silicon Labs, http://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. - * - ******************************************************************************/ - -#include "em_dac.h" -#if defined(DAC_COUNT) && (DAC_COUNT > 0) -#include "em_cmu.h" -#include "em_assert.h" -#include "em_bus.h" - -/***************************************************************************//** - * @addtogroup EM_Library - * @{ - ******************************************************************************/ - -/***************************************************************************//** - * @addtogroup DAC - * @brief Digital to Analog Coversion (DAC) Peripheral API - * @{ - ******************************************************************************/ - -/******************************************************************************* - ******************************* DEFINES *********************************** - ******************************************************************************/ - -/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ - -/** Validation of DAC channel for assert statements. */ -#define DAC_CH_VALID(ch) ((ch) <= 1) - -/** Max DAC clock */ -#define DAC_MAX_CLOCK 1000000 - -/** @endcond */ - -/******************************************************************************* - ************************** GLOBAL FUNCTIONS ******************************* - ******************************************************************************/ - -/***************************************************************************//** - * @brief - * Enable/disable DAC channel. - * - * @param[in] dac - * Pointer to DAC peripheral register block. - * - * @param[in] ch - * Channel to enable/disable. - * - * @param[in] enable - * true to enable DAC channel, false to disable. - ******************************************************************************/ -void DAC_Enable(DAC_TypeDef *dac, unsigned int ch, bool enable) -{ - volatile uint32_t *reg; - - EFM_ASSERT(DAC_REF_VALID(dac)); - EFM_ASSERT(DAC_CH_VALID(ch)); - - if (!ch) - { - reg = &(dac->CH0CTRL); - } - else - { - reg = &(dac->CH1CTRL); - } - - BUS_RegBitWrite(reg, _DAC_CH0CTRL_EN_SHIFT, enable); -} - - -/***************************************************************************//** - * @brief - * Initialize DAC. - * - * @details - * Initializes common parts for both channels. In addition, channel control - * configuration must be done, please refer to DAC_InitChannel(). - * - * @note - * This function will disable both channels prior to configuration. - * - * @param[in] dac - * Pointer to DAC peripheral register block. - * - * @param[in] init - * Pointer to DAC initialization structure. - ******************************************************************************/ -void DAC_Init(DAC_TypeDef *dac, const DAC_Init_TypeDef *init) -{ - uint32_t tmp; - - EFM_ASSERT(DAC_REF_VALID(dac)); - - /* Make sure both channels are disabled. */ - BUS_RegBitWrite(&(dac->CH0CTRL), _DAC_CH0CTRL_EN_SHIFT, 0); - BUS_RegBitWrite(&(dac->CH1CTRL), _DAC_CH0CTRL_EN_SHIFT, 0); - - /* Load proper calibration data depending on selected reference */ - switch (init->reference) - { - case dacRef2V5: - dac->CAL = DEVINFO->DAC0CAL1; - break; - - case dacRefVDD: - dac->CAL = DEVINFO->DAC0CAL2; - break; - - default: /* 1.25V */ - dac->CAL = DEVINFO->DAC0CAL0; - break; - } - - tmp = ((uint32_t)(init->refresh) << _DAC_CTRL_REFRSEL_SHIFT) - | (((uint32_t)(init->prescale) << _DAC_CTRL_PRESC_SHIFT) - & _DAC_CTRL_PRESC_MASK) - | ((uint32_t)(init->reference) << _DAC_CTRL_REFSEL_SHIFT) - | ((uint32_t)(init->outMode) << _DAC_CTRL_OUTMODE_SHIFT) - | ((uint32_t)(init->convMode) << _DAC_CTRL_CONVMODE_SHIFT); - - if (init->ch0ResetPre) - { - tmp |= DAC_CTRL_CH0PRESCRST; - } - - if (init->outEnablePRS) - { - tmp |= DAC_CTRL_OUTENPRS; - } - - if (init->sineEnable) - { - tmp |= DAC_CTRL_SINEMODE; - } - - if (init->diff) - { - tmp |= DAC_CTRL_DIFF; - } - - dac->CTRL = tmp; -} - - -/***************************************************************************//** - * @brief - * Initialize DAC channel. - * - * @param[in] dac - * Pointer to DAC peripheral register block. - * - * @param[in] init - * Pointer to DAC initialization structure. - * - * @param[in] ch - * Channel number to initialize. - ******************************************************************************/ -void DAC_InitChannel(DAC_TypeDef *dac, - const DAC_InitChannel_TypeDef *init, - unsigned int ch) -{ - uint32_t tmp; - - EFM_ASSERT(DAC_REF_VALID(dac)); - EFM_ASSERT(DAC_CH_VALID(ch)); - - tmp = (uint32_t)(init->prsSel) << _DAC_CH0CTRL_PRSSEL_SHIFT; - - if (init->enable) - { - tmp |= DAC_CH0CTRL_EN; - } - - if (init->prsEnable) - { - tmp |= DAC_CH0CTRL_PRSEN; - } - - if (init->refreshEnable) - { - tmp |= DAC_CH0CTRL_REFREN; - } - - if (ch) - { - dac->CH1CTRL = tmp; - } - else - { - dac->CH0CTRL = tmp; - } -} - - -/***************************************************************************//** - * @brief - * Set the output signal of a DAC channel to a given value. - * - * @details - * This function sets the output signal of a DAC channel by writing @p value - * to the corresponding CHnDATA register. - * - * @param[in] dac - * Pointer to DAC peripheral register block. - * - * @param[in] channel - * Channel number to set output of. - * - * @param[in] value - * Value to write to the channel output register CHnDATA. - ******************************************************************************/ -void DAC_ChannelOutputSet( DAC_TypeDef *dac, - unsigned int channel, - uint32_t value ) -{ - switch(channel) - { - case 0: - DAC_Channel0OutputSet(dac, value); - break; - case 1: - DAC_Channel1OutputSet(dac, value); - break; - default: - EFM_ASSERT(0); - break; - } -} - - -/***************************************************************************//** - * @brief - * Calculate prescaler value used to determine DAC clock. - * - * @details - * The DAC clock is given by: HFPERCLK / (prescale ^ 2). If the requested - * DAC frequency is low and the max prescaler value can not adjust the - * actual DAC frequency lower than the requested DAC frequency, then the - * max prescaler value is returned, resulting in a higher DAC frequency - * than requested. - * - * @param[in] dacFreq DAC frequency wanted. The frequency will automatically - * be adjusted to be below max allowed DAC clock. - * - * @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to - * use currently defined HFPER clock setting. - * - * @return - * Prescaler value to use for DAC in order to achieve a clock value - * <= @p dacFreq. - ******************************************************************************/ -uint8_t DAC_PrescaleCalc(uint32_t dacFreq, uint32_t hfperFreq) -{ - uint32_t ret; - - /* Make sure selected DAC clock is below max value */ - if (dacFreq > DAC_MAX_CLOCK) - { - dacFreq = DAC_MAX_CLOCK; - } - - /* Use current HFPER frequency? */ - if (!hfperFreq) - { - hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER); - } - - /* Iterate in order to determine best prescale value. Only a few possible */ - /* values. We start with lowest prescaler value in order to get first */ - /* equal or below wanted DAC frequency value. */ - for (ret = 0; ret <= (_DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT); ret++) - { - if ((hfperFreq >> ret) <= dacFreq) - break; - } - - /* If ret is higher than the max prescaler value, make sure to return - the max value. */ - if (ret > (_DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT)) - { - ret = _DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT; - } - - return (uint8_t)ret; -} - - -/***************************************************************************//** - * @brief - * Reset DAC to same state as after a HW reset. - * - * @param[in] dac - * Pointer to ADC peripheral register block. - ******************************************************************************/ -void DAC_Reset(DAC_TypeDef *dac) -{ - /* Disable channels, before resetting other registers. */ - dac->CH0CTRL = _DAC_CH0CTRL_RESETVALUE; - dac->CH1CTRL = _DAC_CH1CTRL_RESETVALUE; - dac->CTRL = _DAC_CTRL_RESETVALUE; - dac->IEN = _DAC_IEN_RESETVALUE; - dac->IFC = _DAC_IFC_MASK; - dac->CAL = DEVINFO->DAC0CAL0; - dac->BIASPROG = _DAC_BIASPROG_RESETVALUE; - /* Do not reset route register, setting should be done independently */ -} - - -/** @} (end addtogroup DAC) */ -/** @} (end addtogroup EM_Library) */ -#endif /* defined(DAC_COUNT) && (DAC_COUNT > 0) */ +/***************************************************************************//** + * @file em_dac.c + * @brief Digital to Analog Coversion (DAC) Peripheral API + * @version 4.2.1 + ******************************************************************************* + * @section License + * <b>(C) Copyright 2015 Silicon Labs, http://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. + * + ******************************************************************************/ + +#include "em_dac.h" +#if defined(DAC_COUNT) && (DAC_COUNT > 0) +#include "em_cmu.h" +#include "em_assert.h" +#include "em_bus.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup DAC + * @brief Digital to Analog Coversion (DAC) Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/** Validation of DAC channel for assert statements. */ +#define DAC_CH_VALID(ch) ((ch) <= 1) + +/** Max DAC clock */ +#define DAC_MAX_CLOCK 1000000 + +/** @endcond */ + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Enable/disable DAC channel. + * + * @param[in] dac + * Pointer to DAC peripheral register block. + * + * @param[in] ch + * Channel to enable/disable. + * + * @param[in] enable + * true to enable DAC channel, false to disable. + ******************************************************************************/ +void DAC_Enable(DAC_TypeDef *dac, unsigned int ch, bool enable) +{ + volatile uint32_t *reg; + + EFM_ASSERT(DAC_REF_VALID(dac)); + EFM_ASSERT(DAC_CH_VALID(ch)); + + if (!ch) + { + reg = &(dac->CH0CTRL); + } + else + { + reg = &(dac->CH1CTRL); + } + + BUS_RegBitWrite(reg, _DAC_CH0CTRL_EN_SHIFT, enable); +} + + +/***************************************************************************//** + * @brief + * Initialize DAC. + * + * @details + * Initializes common parts for both channels. In addition, channel control + * configuration must be done, please refer to DAC_InitChannel(). + * + * @note + * This function will disable both channels prior to configuration. + * + * @param[in] dac + * Pointer to DAC peripheral register block. + * + * @param[in] init + * Pointer to DAC initialization structure. + ******************************************************************************/ +void DAC_Init(DAC_TypeDef *dac, const DAC_Init_TypeDef *init) +{ + uint32_t tmp; + + EFM_ASSERT(DAC_REF_VALID(dac)); + + /* Make sure both channels are disabled. */ + BUS_RegBitWrite(&(dac->CH0CTRL), _DAC_CH0CTRL_EN_SHIFT, 0); + BUS_RegBitWrite(&(dac->CH1CTRL), _DAC_CH0CTRL_EN_SHIFT, 0); + + /* Load proper calibration data depending on selected reference */ + switch (init->reference) + { + case dacRef2V5: + dac->CAL = DEVINFO->DAC0CAL1; + break; + + case dacRefVDD: + dac->CAL = DEVINFO->DAC0CAL2; + break; + + default: /* 1.25V */ + dac->CAL = DEVINFO->DAC0CAL0; + break; + } + + tmp = ((uint32_t)(init->refresh) << _DAC_CTRL_REFRSEL_SHIFT) + | (((uint32_t)(init->prescale) << _DAC_CTRL_PRESC_SHIFT) + & _DAC_CTRL_PRESC_MASK) + | ((uint32_t)(init->reference) << _DAC_CTRL_REFSEL_SHIFT) + | ((uint32_t)(init->outMode) << _DAC_CTRL_OUTMODE_SHIFT) + | ((uint32_t)(init->convMode) << _DAC_CTRL_CONVMODE_SHIFT); + + if (init->ch0ResetPre) + { + tmp |= DAC_CTRL_CH0PRESCRST; + } + + if (init->outEnablePRS) + { + tmp |= DAC_CTRL_OUTENPRS; + } + + if (init->sineEnable) + { + tmp |= DAC_CTRL_SINEMODE; + } + + if (init->diff) + { + tmp |= DAC_CTRL_DIFF; + } + + dac->CTRL = tmp; +} + + +/***************************************************************************//** + * @brief + * Initialize DAC channel. + * + * @param[in] dac + * Pointer to DAC peripheral register block. + * + * @param[in] init + * Pointer to DAC initialization structure. + * + * @param[in] ch + * Channel number to initialize. + ******************************************************************************/ +void DAC_InitChannel(DAC_TypeDef *dac, + const DAC_InitChannel_TypeDef *init, + unsigned int ch) +{ + uint32_t tmp; + + EFM_ASSERT(DAC_REF_VALID(dac)); + EFM_ASSERT(DAC_CH_VALID(ch)); + + tmp = (uint32_t)(init->prsSel) << _DAC_CH0CTRL_PRSSEL_SHIFT; + + if (init->enable) + { + tmp |= DAC_CH0CTRL_EN; + } + + if (init->prsEnable) + { + tmp |= DAC_CH0CTRL_PRSEN; + } + + if (init->refreshEnable) + { + tmp |= DAC_CH0CTRL_REFREN; + } + + if (ch) + { + dac->CH1CTRL = tmp; + } + else + { + dac->CH0CTRL = tmp; + } +} + + +/***************************************************************************//** + * @brief + * Set the output signal of a DAC channel to a given value. + * + * @details + * This function sets the output signal of a DAC channel by writing @p value + * to the corresponding CHnDATA register. + * + * @param[in] dac + * Pointer to DAC peripheral register block. + * + * @param[in] channel + * Channel number to set output of. + * + * @param[in] value + * Value to write to the channel output register CHnDATA. + ******************************************************************************/ +void DAC_ChannelOutputSet( DAC_TypeDef *dac, + unsigned int channel, + uint32_t value ) +{ + switch(channel) + { + case 0: + DAC_Channel0OutputSet(dac, value); + break; + case 1: + DAC_Channel1OutputSet(dac, value); + break; + default: + EFM_ASSERT(0); + break; + } +} + + +/***************************************************************************//** + * @brief + * Calculate prescaler value used to determine DAC clock. + * + * @details + * The DAC clock is given by: HFPERCLK / (prescale ^ 2). If the requested + * DAC frequency is low and the max prescaler value can not adjust the + * actual DAC frequency lower than the requested DAC frequency, then the + * max prescaler value is returned, resulting in a higher DAC frequency + * than requested. + * + * @param[in] dacFreq DAC frequency wanted. The frequency will automatically + * be adjusted to be below max allowed DAC clock. + * + * @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to + * use currently defined HFPER clock setting. + * + * @return + * Prescaler value to use for DAC in order to achieve a clock value + * <= @p dacFreq. + ******************************************************************************/ +uint8_t DAC_PrescaleCalc(uint32_t dacFreq, uint32_t hfperFreq) +{ + uint32_t ret; + + /* Make sure selected DAC clock is below max value */ + if (dacFreq > DAC_MAX_CLOCK) + { + dacFreq = DAC_MAX_CLOCK; + } + + /* Use current HFPER frequency? */ + if (!hfperFreq) + { + hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER); + } + + /* Iterate in order to determine best prescale value. Only a few possible */ + /* values. We start with lowest prescaler value in order to get first */ + /* equal or below wanted DAC frequency value. */ + for (ret = 0; ret <= (_DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT); ret++) + { + if ((hfperFreq >> ret) <= dacFreq) + break; + } + + /* If ret is higher than the max prescaler value, make sure to return + the max value. */ + if (ret > (_DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT)) + { + ret = _DAC_CTRL_PRESC_MASK >> _DAC_CTRL_PRESC_SHIFT; + } + + return (uint8_t)ret; +} + + +/***************************************************************************//** + * @brief + * Reset DAC to same state as after a HW reset. + * + * @param[in] dac + * Pointer to ADC peripheral register block. + ******************************************************************************/ +void DAC_Reset(DAC_TypeDef *dac) +{ + /* Disable channels, before resetting other registers. */ + dac->CH0CTRL = _DAC_CH0CTRL_RESETVALUE; + dac->CH1CTRL = _DAC_CH1CTRL_RESETVALUE; + dac->CTRL = _DAC_CTRL_RESETVALUE; + dac->IEN = _DAC_IEN_RESETVALUE; + dac->IFC = _DAC_IFC_MASK; + dac->CAL = DEVINFO->DAC0CAL0; + dac->BIASPROG = _DAC_BIASPROG_RESETVALUE; + /* Do not reset route register, setting should be done independently */ +} + + +/** @} (end addtogroup DAC) */ +/** @} (end addtogroup EM_Library) */ +#endif /* defined(DAC_COUNT) && (DAC_COUNT > 0) */