示例#1
0
文件: efm32_emu.c 项目: spqr/EFMoo
/***************************************************************************//**
 * @brief
 *   Restore oscillators and core clock after having been in EM2 or EM3.
 ******************************************************************************/
static void EMU_Restore(void)
{
  uint32_t cmuLocked;

  /* Although we could use the CMU API for most of the below handling, we */
  /* would like this function to be as efficient as possible. */

  /* CMU registers may be locked */
  cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
  CMU_Unlock();

  /* AUXHFRCO was automatically disabled (except if using debugger). */
  /* HFXO was automatically disabled. */
  /* LFRCO/LFXO were possibly disabled by SW in EM3. */
  /* Restore according to status prior to entering EM. */
  CMU->OSCENCMD = cmuStatus & (CMU_STATUS_AUXHFRCOENS |
                               CMU_STATUS_HFXOENS |
                               CMU_STATUS_LFRCOENS |
                               CMU_STATUS_LFXOENS);

  /* Restore oscillator used for clocking core */
  switch (cmuStatus & (CMU_STATUS_HFXOSEL | CMU_STATUS_HFRCOSEL |
                       CMU_STATUS_LFXOSEL | CMU_STATUS_LFRCOSEL))
  {
  case CMU_STATUS_LFRCOSEL:
    /* Wait for LFRCO to stabilize */
    while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) ;
    CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
    break;

  case CMU_STATUS_LFXOSEL:
    /* Wait for LFXO to stabilize */
    while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) ;
    CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
    break;

  case CMU_STATUS_HFXOSEL:
    /* Wait for HFXO to stabilize */
    while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) ;
    CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
    break;

  default: /* CMU_STATUS_HFRCOSEL */
    /* If core clock was HFRCO core clock, it is automatically restored to */
    /* state prior to entering energy mode. No need for further action. */
    break;
  }

  /* Restore CMU register locking */
  if (cmuLocked)
  {
    CMU_Lock();
  }
}
示例#2
0
/***************************************************************************//**
 * @brief
 *   Enter energy mode 3 (EM3).
 *
 * @details
 *   When entering EM3, the high frequency clocks are disabled by HW, ie HFXO,
 *   HFRCO and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
 *   the low frequency clocks, ie LFXO and LFRCO are disabled by SW. When
 *   re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
 *   configured HFRCO band. This ensures a quick wakeup from EM3.
 *
 *   However, prior to entering EM3, the core may have been using another
 *   oscillator than HFRCO. The @p restore parameter gives the user the option
 *   to restore all HF/LF oscillators according to state prior to entering EM3,
 *   as well as the clock used to clock the core. This restore procedure is
 *   handled by SW. However, since handled by SW, it will not be restored
 *   before completing the interrupt function(s) waking up the core!
 *
 * @note
 *   If restoring core clock to use an oscillator other than HFRCO, this
 *   function will stall until the oscillator has stabilized. Stalling time
 *   can be reduced by adding interrupt support detecting stable oscillator,
 *   and an asynchronous switch to the original oscillator. See CMU
 *   documentation. Such a feature is however outside the scope of the
 *   implementation in this function.
 * @par
 *   If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
 *   the core, this function will not wait for those oscillators to stabilize.
 *   This must be considered by the application if trying to use features
 *   relying on those oscillators upon return.
 * @par
 *   If a debugger is attached, the AUXHFRCO will not be disabled if enabled
 *   upon entering EM3. It will thus remain enabled when returning to EM0
 *   regardless of the @p restore parameter.
 *
 * @param[in] restore
 *   @li true - restore oscillators and clocks, see function details.
 *   @li false - do not restore oscillators and clocks, see function details.
 * @par
 *   The @p restore option should only be used if all clock control is done
 *   via the CMU API.
 ******************************************************************************/
void EMU_EnterEM3(bool restore)
{
	uint32_t cmuLocked;

	/* Auto-update CMU status just in case before entering energy mode. */
	/* This variable is normally kept up-to-date by the CMU API. */
	cmuStatus = (uint16_t)(CMU->STATUS);

	/* CMU registers may be locked */
	cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
	CMU_Unlock();

	/* Disable LF oscillators */
	CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;

	/* Restore CMU register locking */
	if (cmuLocked)
	{
		CMU_Lock();
	}

	/* Enter Cortex-M3 deep sleep mode */
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__WFI();

	/* Restore oscillators/clocks if specified */
	if (restore)
	{
		EMU_Restore();
	}
	/* If not restoring, and original clock was not HFRCO, we have to */
	/* update CMSIS core clock variable since core clock has changed */
	/* to using HFRCO. */
	else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
	{
		SystemCoreClockUpdate();
	}
}