/***************************************************************************//** * @brief * Set the LETIMER compare register value. * * @note * The setting of a compare register requires synchronization into the * low frequency domain. If the same register is modified before a previous * update has completed, this function will stall until the previous * synchronization has completed. This only applies to the Gecko Family. See * comments in the LETIMER_Sync() internal function call. * * @param[in] letimer * A pointer to the LETIMER peripheral register block. * * @param[in] comp * A compare register to set, either 0 or 1. * * @param[in] value * An initialization value (<= 0x0000ffff). ******************************************************************************/ void LETIMER_CompareSet(LETIMER_TypeDef *letimer, unsigned int comp, uint32_t value) { volatile uint32_t *compReg; EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp) && ((value & ~(_LETIMER_COMP0_COMP0_MASK >> _LETIMER_COMP0_COMP0_SHIFT)) == 0)); /* Initialize the selected compare value. */ switch (comp) { case 0: compReg = &(letimer->COMP0); break; case 1: compReg = &(letimer->COMP1); break; default: /* An unknown compare register selected, abort. */ return; } #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, comp ? LETIMER_SYNCBUSY_COMP1 : LETIMER_SYNCBUSY_COMP0); #endif *compReg = value; }
/***************************************************************************//** * @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 * Start/stop LETIMER. * * @note * The enabling/disabling of the LETIMER modifies the LETIMER CMD register * which requires synchronization into the low-frequency domain. If this * register is modified before a previous update to the same register has * completed, this function will stall until the previous synchronization has * completed. This only applies to the Gecko Family. See comments in the * LETIMER_Sync() internal function call. * * @param[in] letimer * A pointer to the LETIMER peripheral register block. * * @param[in] enable * True to enable counting, false to disable. ******************************************************************************/ void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable) { EFM_ASSERT(LETIMER_REF_VALID(letimer)); #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, LETIMER_SYNCBUSY_CMD); #elif defined (LETIMER_SYNCBUSY_START) && defined (LETIMER_SYNCBUSY_STOP) uint32_t syncBusyMask = LETIMER_SYNCBUSY_STOP | LETIMER_SYNCBUSY_START; while (letimer->SYNCBUSY & syncBusyMask) { } #endif if (enable) { letimer->CMD = LETIMER_CMD_START; } else { letimer->CMD = LETIMER_CMD_STOP; } }
/***************************************************************************//** * @brief * Set the LETIMER repeat counter register value. * * @note * The setting of a repeat counter register requires synchronization into the * low-frequency domain. If the same register is modified before a previous * update has completed, this function will stall until the previous * synchronization has completed. This only applies to the Gecko Family. See * comments in the LETIMER_Sync() internal function call. * * @param[in] letimer * A pointer to the LETIMER peripheral register block. * * @param[in] rep * Repeat counter register to set, either 0 or 1. * * @param[in] value * An initialization value (<= 0x0000ffff). ******************************************************************************/ void LETIMER_RepeatSet(LETIMER_TypeDef *letimer, unsigned int rep, uint32_t value) { volatile uint32_t *repReg; #if defined(_EFM32_GECKO_FAMILY) uint32_t syncbusy; #endif EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep) && ((value & ~(_LETIMER_REP0_REP0_MASK >> _LETIMER_REP0_REP0_SHIFT)) == 0)); /* Initialize the selected compare value. */ switch (rep) { case 0: repReg = &(letimer->REP0); #if defined(_EFM32_GECKO_FAMILY) syncbusy = LETIMER_SYNCBUSY_REP0; #endif break; case 1: repReg = &(letimer->REP1); #if defined(_EFM32_GECKO_FAMILY) syncbusy = LETIMER_SYNCBUSY_REP1; #endif break; default: /* An unknown compare register selected, abort. */ return; } #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, syncbusy); #endif *repReg = value; }
/***************************************************************************//** * @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 * Initialize LETIMER. * * @details * Note that the compare/repeat values must be set separately with * LETIMER_CompareSet() and LETIMER_RepeatSet(). That should probably be done * prior using this function if configuring the LETIMER to start when * initialization is complete. * * @note * The initialization of the LETIMER modifies the LETIMER CTRL/CMD registers * which require synchronization into the low-frequency domain. If any of those * registers are modified before a previous update to the same register has * completed, this function will stall until the previous synchronization has * completed. This only applies to the Gecko Family. See comments in the * LETIMER_Sync() internal function call. * * @param[in] letimer * A pointer to the LETIMER peripheral register block. * * @param[in] init * A pointer to the LETIMER initialization structure. ******************************************************************************/ void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init) { uint32_t tmp = 0; EFM_ASSERT(LETIMER_REF_VALID(letimer)); #if defined (LETIMER_EN_EN) letimer->EN_SET = LETIMER_EN_EN; #endif /* Stop the timer if specified to be disabled and running. */ if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING)) { #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, LETIMER_SYNCBUSY_CMD); #elif defined(LETIMER_SYNCBUSY_STOP) while (letimer->SYNCBUSY & LETIMER_SYNCBUSY_STOP) { } #endif letimer->CMD = LETIMER_CMD_STOP; } /* Configure the DEBUGRUN flag, which sets whether or not the counter should be * updated when the debugger is active. */ if (init->debugRun) { tmp |= LETIMER_CTRL_DEBUGRUN; } #if defined(LETIMER_CTRL_RTCC0TEN) if (init->rtcComp0Enable) { tmp |= LETIMER_CTRL_RTCC0TEN; } if (init->rtcComp1Enable) { tmp |= LETIMER_CTRL_RTCC1TEN; } #endif if ((init->comp0Top) || (init->topValue != 0U)) { #if defined (LETIMER_CTRL_COMP0TOP) tmp |= LETIMER_CTRL_COMP0TOP; letimer->COMP0 = init->topValue; #elif defined (LETIMER_CTRL_CNTTOPEN) tmp |= LETIMER_CTRL_CNTTOPEN; letimer->TOP = init->topValue; #endif } if (init->bufTop) { tmp |= LETIMER_CTRL_BUFTOP; } if (init->out0Pol) { tmp |= LETIMER_CTRL_OPOL0; } if (init->out1Pol) { tmp |= LETIMER_CTRL_OPOL1; } tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT; tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT; tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT; #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, LETIMER_SYNCBUSY_CTRL); #endif letimer->CTRL = tmp; /* Start the timer if specified to be enabled and not already running. */ if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING)) { #if defined(_EFM32_GECKO_FAMILY) /* LF register about to be modified requires sync; busy check. */ regSync(letimer, LETIMER_SYNCBUSY_CMD); #elif defined(LETIMER_SYNCBUSY_START) while (letimer->SYNCBUSY & LETIMER_SYNCBUSY_START) { } #endif letimer->CMD = LETIMER_CMD_START; } }