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_burtc.c
- Revision:
- 144:ef7eb2e8f9f7
- Parent:
- 50:a417edff4437
diff -r 423e1876dc07 -r ef7eb2e8f9f7 targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_burtc.c --- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_burtc.c Tue Aug 02 14:07:36 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_burtc.c Fri Sep 02 15:07:44 2016 +0100 @@ -1,314 +1,314 @@ -/***************************************************************************//** - * @file em_burtc.c - * @brief Backup Real Time Counter (BURTC) 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_burtc.h" -#if defined(BURTC_PRESENT) - -/***************************************************************************//** - * @addtogroup EM_Library - * @{ - ******************************************************************************/ - -/***************************************************************************//** - * @addtogroup BURTC - * @brief Backup Real Time Counter (BURTC) Peripheral API - * @{ - ******************************************************************************/ - -/******************************************************************************* - ******************************* DEFINES *********************************** - ******************************************************************************/ - -/******************************************************************************* - ************************** LOCAL FUNCTIONS ******************************** - ******************************************************************************/ - -/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ -/***************************************************************************//** - * @brief Convert dividend to prescaler logarithmic value. Only works for even - * numbers equal to 2^n - * @param[in] div Unscaled dividend, - * @return Base 2 logarithm of input, as used by fixed prescalers - ******************************************************************************/ -__STATIC_INLINE uint32_t divToLog2(uint32_t div) -{ - uint32_t log2; - - /* Prescaler accepts an argument of 128 or less, valid values being 2^n */ - EFM_ASSERT((div > 0) && (div <= 32768)); - - /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */ - log2 = (31 - __CLZ(div)); - - return log2; -} - - -/***************************************************************************//** - * @brief - * Wait for ongoing sync of register(s) to low frequency domain to complete. - * - * @param[in] mask - * Bitmask corresponding to SYNCBUSY register defined bits, indicating - * registers that must complete any ongoing synchronization. - ******************************************************************************/ -__STATIC_INLINE void regSync(uint32_t mask) -{ - /* Avoid deadlock if modifying the same register twice when freeze mode is - activated, or when no clock is selected for the BURTC. If no clock is - selected, then the sync is done once the clock source is set. */ - if ((BURTC->FREEZE & BURTC_FREEZE_REGFREEZE) - || ((BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK) != _BURTC_CTRL_CLKSEL_NONE)) - { - return; - } - /* Wait for any pending previous write operation to have been completed */ - /* in low frequency domain. This is only required for the Gecko Family */ - while (BURTC->SYNCBUSY & mask) - ; -} -/** @endcond */ - - -/******************************************************************************* - ************************** GLOBAL FUNCTIONS ******************************* - ******************************************************************************/ - -/***************************************************************************//** - * @brief Initialize BURTC - * - * @details - * Configures the BURTC peripheral. - * - * @note - * Before initialization, BURTC module must first be enabled by clearing the - * reset bit in the RMU, i.e. - * @verbatim - * RMU_ResetControl(rmuResetBU, rmuResetModeClear); - * @endverbatim - * Compare channel 0 must be configured outside this function, before - * initialization if enable is set to true. The counter will always be reset. - * - * @param[in] burtcInit - * Pointer to BURTC initialization structure - ******************************************************************************/ -void BURTC_Init(const BURTC_Init_TypeDef *burtcInit) -{ - uint32_t ctrl; - uint32_t presc; - - /* Check initializer structure integrity */ - EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0); - /* Clock divider must be between 1 and 128, really on the form 2^n */ - EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128)); - /* Ignored compare bits during low power operation must be less than 7 */ - /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */ - EFM_ASSERT(burtcInit->lowPowerComp <= 6); - /* You cannot enable the BURTC if mode is set to disabled */ - EFM_ASSERT((burtcInit->enable == false) || - ((burtcInit->enable == true) - && (burtcInit->mode != burtcModeDisable))); - /* Low power mode is only available with LFRCO or LFXO as clock source */ - EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO) - || ((burtcInit->clkSel == burtcClkSelULFRCO) - && (burtcInit->lowPowerMode == burtcLPDisable))); - - /* Calculate prescaler value from clock divider input */ - /* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of - value 1 will select a 2kHz ULFRCO clock, while any other value will - select a 1kHz ULFRCO clock source. */ - presc = divToLog2(burtcInit->clkDiv); - - /* Make sure all registers are updated simultaneously */ - if (burtcInit->enable) - { - BURTC_FreezeEnable(true); - } - - /* Modification of LPMODE register requires sync with potential ongoing - * register updates in LF domain. */ - regSync(BURTC_SYNCBUSY_LPMODE); - - /* Configure low power mode */ - BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode); - - /* New configuration */ - ctrl = (BURTC_CTRL_RSTEN - | (burtcInit->mode) - | (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT) - | (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT) - | (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT) - | (presc << _BURTC_CTRL_PRESC_SHIFT) - | (burtcInit->clkSel) - | (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT)); - - /* Clear interrupts */ - BURTC_IntClear(0xFFFFFFFF); - - /* Set new configuration */ - BURTC->CTRL = ctrl; - - /* Enable BURTC and counter */ - if (burtcInit->enable) - { - /* To enable BURTC counter, we need to disable reset */ - BURTC_Enable(true); - - /* Clear freeze */ - BURTC_FreezeEnable(false); - } -} - - -/***************************************************************************//** - * @brief Set BURTC compare channel - * - * @param[in] comp Compare channel index, must be 0 for Giant / Leopard Gecko - * - * @param[in] value New compare value - ******************************************************************************/ -void BURTC_CompareSet(unsigned int comp, uint32_t value) -{ - (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */ - - EFM_ASSERT(comp == 0); - - /* Modification of COMP0 register requires sync with potential ongoing - * register updates in LF domain. */ - regSync(BURTC_SYNCBUSY_COMP0); - - /* Configure compare channel 0 */ - BURTC->COMP0 = value; -} - - -/***************************************************************************//** - * @brief Get BURTC compare value - * - * @param[in] comp Compare channel index value, must be 0 for Giant/Leopard. - * - * @return Currently configured value for this compare channel - ******************************************************************************/ -uint32_t BURTC_CompareGet(unsigned int comp) -{ - (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */ - - EFM_ASSERT(comp == 0); - - return BURTC->COMP0; -} - - -/***************************************************************************//** - * @brief Reset counter - ******************************************************************************/ -void BURTC_CounterReset(void) -{ - /* Set and clear reset bit */ - BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1); - BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0); -} - - -/***************************************************************************//** - * @brief - * Restore BURTC to reset state - * @note - * Before accessing the BURTC, BURSTEN in RMU->CTRL must be cleared. - * LOCK will not be reset to default value, as this will disable access - * to core BURTC registers. - ******************************************************************************/ -void BURTC_Reset(void) -{ - bool buResetState; - - /* Read reset state, set reset and restore state */ - buResetState = BUS_RegBitRead(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT); - BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 1); - BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, buResetState); -} - - -/***************************************************************************//** - * @brief - * Get clock frequency of the BURTC. - * - * @return - * The current frequency in Hz. - ******************************************************************************/ -uint32_t BURTC_ClockFreqGet(void) -{ - uint32_t clkSel; - uint32_t clkDiv; - uint32_t frequency; - - clkSel = BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK; - clkDiv = (BURTC->CTRL & _BURTC_CTRL_PRESC_MASK) >> _BURTC_CTRL_PRESC_SHIFT; - - switch (clkSel) - { - /** Ultra low frequency (1 kHz) clock */ - case BURTC_CTRL_CLKSEL_ULFRCO: - if (_BURTC_CTRL_PRESC_DIV1 == clkDiv) - { - frequency = 2000; /* 2KHz when clock divisor is 1. */ - } - else - { - frequency = SystemULFRCOClockGet(); /* 1KHz when divisor is different - from 1. */ - } - break; - - /** Low frequency RC oscillator */ - case BURTC_CTRL_CLKSEL_LFRCO: - frequency = SystemLFRCOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */ - break; - - /** Low frequency crystal osciallator */ - case BURTC_CTRL_CLKSEL_LFXO: - frequency = SystemLFXOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */ - break; - - default: - /* No clock selected for BURTC. */ - frequency = 0; - } - return frequency; -} - - -/** @} (end addtogroup BURTC) */ -/** @} (end addtogroup EM_Library) */ - -#endif /* BURTC_PRESENT */ +/***************************************************************************//** + * @file em_burtc.c + * @brief Backup Real Time Counter (BURTC) 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_burtc.h" +#if defined(BURTC_PRESENT) + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup BURTC + * @brief Backup Real Time Counter (BURTC) Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ +/***************************************************************************//** + * @brief Convert dividend to prescaler logarithmic value. Only works for even + * numbers equal to 2^n + * @param[in] div Unscaled dividend, + * @return Base 2 logarithm of input, as used by fixed prescalers + ******************************************************************************/ +__STATIC_INLINE uint32_t divToLog2(uint32_t div) +{ + uint32_t log2; + + /* Prescaler accepts an argument of 128 or less, valid values being 2^n */ + EFM_ASSERT((div > 0) && (div <= 32768)); + + /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */ + log2 = (31 - __CLZ(div)); + + return log2; +} + + +/***************************************************************************//** + * @brief + * Wait for ongoing sync of register(s) to low frequency domain to complete. + * + * @param[in] mask + * Bitmask corresponding to SYNCBUSY register defined bits, indicating + * registers that must complete any ongoing synchronization. + ******************************************************************************/ +__STATIC_INLINE void regSync(uint32_t mask) +{ + /* Avoid deadlock if modifying the same register twice when freeze mode is + activated, or when no clock is selected for the BURTC. If no clock is + selected, then the sync is done once the clock source is set. */ + if ((BURTC->FREEZE & BURTC_FREEZE_REGFREEZE) + || ((BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK) != _BURTC_CTRL_CLKSEL_NONE)) + { + return; + } + /* Wait for any pending previous write operation to have been completed */ + /* in low frequency domain. This is only required for the Gecko Family */ + while (BURTC->SYNCBUSY & mask) + ; +} +/** @endcond */ + + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief Initialize BURTC + * + * @details + * Configures the BURTC peripheral. + * + * @note + * Before initialization, BURTC module must first be enabled by clearing the + * reset bit in the RMU, i.e. + * @verbatim + * RMU_ResetControl(rmuResetBU, rmuResetModeClear); + * @endverbatim + * Compare channel 0 must be configured outside this function, before + * initialization if enable is set to true. The counter will always be reset. + * + * @param[in] burtcInit + * Pointer to BURTC initialization structure + ******************************************************************************/ +void BURTC_Init(const BURTC_Init_TypeDef *burtcInit) +{ + uint32_t ctrl; + uint32_t presc; + + /* Check initializer structure integrity */ + EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0); + /* Clock divider must be between 1 and 128, really on the form 2^n */ + EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128)); + /* Ignored compare bits during low power operation must be less than 7 */ + /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */ + EFM_ASSERT(burtcInit->lowPowerComp <= 6); + /* You cannot enable the BURTC if mode is set to disabled */ + EFM_ASSERT((burtcInit->enable == false) || + ((burtcInit->enable == true) + && (burtcInit->mode != burtcModeDisable))); + /* Low power mode is only available with LFRCO or LFXO as clock source */ + EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO) + || ((burtcInit->clkSel == burtcClkSelULFRCO) + && (burtcInit->lowPowerMode == burtcLPDisable))); + + /* Calculate prescaler value from clock divider input */ + /* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of + value 1 will select a 2kHz ULFRCO clock, while any other value will + select a 1kHz ULFRCO clock source. */ + presc = divToLog2(burtcInit->clkDiv); + + /* Make sure all registers are updated simultaneously */ + if (burtcInit->enable) + { + BURTC_FreezeEnable(true); + } + + /* Modification of LPMODE register requires sync with potential ongoing + * register updates in LF domain. */ + regSync(BURTC_SYNCBUSY_LPMODE); + + /* Configure low power mode */ + BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode); + + /* New configuration */ + ctrl = (BURTC_CTRL_RSTEN + | (burtcInit->mode) + | (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT) + | (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT) + | (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT) + | (presc << _BURTC_CTRL_PRESC_SHIFT) + | (burtcInit->clkSel) + | (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT)); + + /* Clear interrupts */ + BURTC_IntClear(0xFFFFFFFF); + + /* Set new configuration */ + BURTC->CTRL = ctrl; + + /* Enable BURTC and counter */ + if (burtcInit->enable) + { + /* To enable BURTC counter, we need to disable reset */ + BURTC_Enable(true); + + /* Clear freeze */ + BURTC_FreezeEnable(false); + } +} + + +/***************************************************************************//** + * @brief Set BURTC compare channel + * + * @param[in] comp Compare channel index, must be 0 for Giant / Leopard Gecko + * + * @param[in] value New compare value + ******************************************************************************/ +void BURTC_CompareSet(unsigned int comp, uint32_t value) +{ + (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */ + + EFM_ASSERT(comp == 0); + + /* Modification of COMP0 register requires sync with potential ongoing + * register updates in LF domain. */ + regSync(BURTC_SYNCBUSY_COMP0); + + /* Configure compare channel 0 */ + BURTC->COMP0 = value; +} + + +/***************************************************************************//** + * @brief Get BURTC compare value + * + * @param[in] comp Compare channel index value, must be 0 for Giant/Leopard. + * + * @return Currently configured value for this compare channel + ******************************************************************************/ +uint32_t BURTC_CompareGet(unsigned int comp) +{ + (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */ + + EFM_ASSERT(comp == 0); + + return BURTC->COMP0; +} + + +/***************************************************************************//** + * @brief Reset counter + ******************************************************************************/ +void BURTC_CounterReset(void) +{ + /* Set and clear reset bit */ + BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1); + BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0); +} + + +/***************************************************************************//** + * @brief + * Restore BURTC to reset state + * @note + * Before accessing the BURTC, BURSTEN in RMU->CTRL must be cleared. + * LOCK will not be reset to default value, as this will disable access + * to core BURTC registers. + ******************************************************************************/ +void BURTC_Reset(void) +{ + bool buResetState; + + /* Read reset state, set reset and restore state */ + buResetState = BUS_RegBitRead(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT); + BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 1); + BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, buResetState); +} + + +/***************************************************************************//** + * @brief + * Get clock frequency of the BURTC. + * + * @return + * The current frequency in Hz. + ******************************************************************************/ +uint32_t BURTC_ClockFreqGet(void) +{ + uint32_t clkSel; + uint32_t clkDiv; + uint32_t frequency; + + clkSel = BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK; + clkDiv = (BURTC->CTRL & _BURTC_CTRL_PRESC_MASK) >> _BURTC_CTRL_PRESC_SHIFT; + + switch (clkSel) + { + /** Ultra low frequency (1 kHz) clock */ + case BURTC_CTRL_CLKSEL_ULFRCO: + if (_BURTC_CTRL_PRESC_DIV1 == clkDiv) + { + frequency = 2000; /* 2KHz when clock divisor is 1. */ + } + else + { + frequency = SystemULFRCOClockGet(); /* 1KHz when divisor is different + from 1. */ + } + break; + + /** Low frequency RC oscillator */ + case BURTC_CTRL_CLKSEL_LFRCO: + frequency = SystemLFRCOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */ + break; + + /** Low frequency crystal osciallator */ + case BURTC_CTRL_CLKSEL_LFXO: + frequency = SystemLFXOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */ + break; + + default: + /* No clock selected for BURTC. */ + frequency = 0; + } + return frequency; +} + + +/** @} (end addtogroup BURTC) */ +/** @} (end addtogroup EM_Library) */ + +#endif /* BURTC_PRESENT */