/** * \brief Enable PLLA clock. * * \param mula PLLA multiplier. * \param pllacount PLLA counter. * \param diva Divider. */ void pmc_enable_pllack(uint32_t mula, uint32_t pllacount, uint32_t diva) { /* first disable the PLL to unlock the lock!*/ pmc_disable_pllack(); PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_DIVA(diva) | CKGR_PLLAR_PLLACOUNT(pllacount) | CKGR_PLLAR_MULA(mula); while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0); }
/** * \brief Enable PLLA clock. * * \param mula PLLA multiplier. * \param pllacount PLLA counter. * \param diva Divider. */ void pmc_enable_pllack(uint32_t mula, uint32_t pllacount, uint32_t diva) { pmc_disable_pllack(); // Hardware BUG FIX : first disable the PLL to unlock the lock! // It occurs when re-enabling the PLL with the same parameters. PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_DIVA(diva) | CKGR_PLLAR_PLLACOUNT(pllacount) | CKGR_PLLAR_MULA(mula); while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0); }
/** * \brief Enable PLLA clock. * * \param mula PLLA multiplier. * \param pllacount PLLA counter. * \param diva Divider. */ void pmc_enable_pllack(uint32_t mula, uint32_t pllacount, uint32_t diva) { /* first disable the PLL to unlock the lock */ pmc_disable_pllack(); #if (SAM4C || SAM4CM || SAM4CP || SAMG) PMC->CKGR_PLLAR = CKGR_PLLAR_PLLAEN(diva) | CKGR_PLLAR_PLLACOUNT(pllacount) | CKGR_PLLAR_MULA(mula); #else PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_DIVA(diva) | CKGR_PLLAR_PLLACOUNT(pllacount) | CKGR_PLLAR_MULA(mula); #endif while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0); }
/** * Save clock settings and shutdown PLLs */ __always_inline static void pmc_save_clock_settings( uint32_t *p_osc_setting, uint32_t *p_pll0_setting, uint32_t *p_pll1_setting, uint32_t *p_mck_setting) { if (p_osc_setting) { *p_osc_setting = PMC->CKGR_MOR; } if (p_pll0_setting) { *p_pll0_setting = PMC->CKGR_PLLAR; } if (p_pll1_setting) { #if (SAM3S || SAM4S) *p_pll1_setting = PMC->CKGR_PLLBR; #elif (SAM3U || SAM3XA) *p_pll1_setting = PMC->CKGR_UCKR; #else *p_pll1_setting = 0; #endif } if (p_mck_setting) { *p_mck_setting = PMC->PMC_MCKR; } /* Switch MCK to internal 4/8/12M RC for fast wakeup and disable unused clock for power saving. */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz); pmc_osc_disable_xtal(0); pmc_disable_pllack(); #if (SAM3S || SAM4S) pmc_disable_pllbck(); #elif (SAM3U || SAM3XA) pmc_disable_upll_clock(); #endif pmc_switch_mck_to_mainck(PMC_MCKR_PRES_CLK_1); }
/** * Save clock settings and shutdown PLLs */ __always_inline static void pmc_save_clock_settings( uint32_t *p_osc_setting, uint32_t *p_pll0_setting, uint32_t *p_pll1_setting, uint32_t *p_mck_setting, uint32_t *p_fmr_setting, #if defined(EFC1) uint32_t *p_fmr_setting1, #endif const bool disable_xtal) { uint32_t mor = PMC->CKGR_MOR; uint32_t mckr = PMC->PMC_MCKR; uint32_t fmr = EFC0->EEFC_FMR; # if defined(EFC1) uint32_t fmr1 = EFC1->EEFC_FMR; # endif if (p_osc_setting) { *p_osc_setting = mor; } if (p_pll0_setting) { *p_pll0_setting = PMC->CKGR_PLLAR; } if (p_pll1_setting) { #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) *p_pll1_setting = PMC->CKGR_PLLBR; #elif (SAM3U || SAM3XA) *p_pll1_setting = PMC->CKGR_UCKR; #else *p_pll1_setting = 0; #endif } if (p_mck_setting) { *p_mck_setting = mckr; } if (p_fmr_setting) { *p_fmr_setting = fmr; } #if defined(EFC1) if (p_fmr_setting1) { *p_fmr_setting1 = fmr1; } #endif /* Enable FAST RC */ PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor | CKGR_MOR_MOSCRCEN; /* if MCK source is PLL, switch to mainck */ if ((mckr & PMC_MCKR_CSS_Msk) > PMC_MCKR_CSS_MAIN_CLK) { /* MCK -> MAINCK */ mckr = (mckr & (~PMC_MCKR_CSS_Msk)) | PMC_MCKR_CSS_MAIN_CLK; PMC->PMC_MCKR = mckr; while(!(PMC->PMC_SR & PMC_SR_MCKRDY)); } /* MCK prescale -> 1 */ if (mckr & PMC_MCKR_PRES_Msk) { mckr = (mckr & (~PMC_MCKR_PRES_Msk)); PMC->PMC_MCKR = mckr; while(!(PMC->PMC_SR & PMC_SR_MCKRDY)); } /* Disable PLLs */ pmc_disable_pllack(); #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) pmc_disable_pllbck(); #elif (SAM3U || SAM3XA) pmc_disable_upll_clock(); #endif /* Prepare for entering WAIT mode */ /* Wait fast RC ready */ while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)); /* Switch mainck to FAST RC */ #if SAMG /** * For the sleepwalking feature, we need an accurate RC clock. Only 24M and * 16M are trimmed in production. Here we select the 24M. * And so wait state need to be 1. */ EFC0->EEFC_FMR = (fmr & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(1); PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_MOSCRCF_24_MHz | CKGR_MOR_KEY_PASSWD; #else PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_KEY_PASSWD; #endif while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)); #if (!SAMG) /* FWS update */ EFC0->EEFC_FMR = fmr & (~EEFC_FMR_FWS_Msk); #if defined(EFC1) EFC1->EEFC_FMR = fmr1 & (~EEFC_FMR_FWS_Msk); #endif #endif /* Disable XTALs */ if (disable_xtal) { PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | CKGR_MOR_KEY_PASSWD; } }
static unsigned long wait_mode_power_down_hook( unsigned long delay_ms ) { bool jtag_enabled = ( ( CoreDebug ->DHCSR & CoreDebug_DEMCR_TRCENA_Msk ) != 0 ) ? true : false; bool jtag_delay_elapsed = ( mico_get_time() > JTAG_DEBUG_SLEEP_DELAY_MS ) ? true : false; uint32_t elapsed_cycles = 0; /* Criteria to enter WAIT mode * 1. Clock needed counter is 0 and no JTAG debugging * 2. Clock needed counter is 0, in JTAG debugging session, and MiCO system tick has progressed over 3 seconds. * This is to give OpenOCD enough time to poke the JTAG tap before the CPU enters WAIT mode. */ if ( ( samg5x_clock_needed_counter == 0 ) && ( ( jtag_enabled == false ) || ( ( jtag_enabled == true ) && ( jtag_delay_elapsed == true ) ) ) ) { uint32_t total_sleep_cycles; uint32_t total_delay_cycles; /* Start real-time timer */ rtt_init( RTT, RTT_CLOCK_PRESCALER ); /* Start atomic operation */ DISABLE_INTERRUPTS; /* Ensure deep sleep bit is enabled, otherwise system doesn't go into deep sleep */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Disable SysTick */ SysTick->CTRL &= ( ~( SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk ) ); /* End atomic operation */ ENABLE_INTERRUPTS; /* Expected total time CPU executing in this function (including WAIT mode time) */ total_sleep_cycles = MS_TO_CYCLES( delay_ms ); /* Total cycles in WAIT mode loop */ total_delay_cycles = ( total_sleep_cycles / RTT_MAX_CYCLES + 1 ) * RC_OSC_DELAY_CYCLES + WAIT_MODE_ENTER_DELAY_CYCLES + WAIT_MODE_EXIT_DELAY_CYCLES; if ( total_sleep_cycles > total_delay_cycles ) { /* Adjust total sleep cycle to exclude exit delay */ total_sleep_cycles -= WAIT_MODE_EXIT_DELAY_CYCLES; /* Prepare platform specific settings before entering powersave */ // platform_enter_powersave(); ///* Prepare WLAN bus before entering powersave */ //platform_bus_enter_powersave(); /* Disable brownout detector */ supc_disable_brownout_detector( SUPC ); /* Backup system I/0 functions and set all to GPIO to save power */ system_io_backup_value = matrix_get_system_io(); matrix_set_system_io( 0x0CF0 ); /* Switch Master Clock to Main Clock (internal fast RC oscillator) */ pmc_switch_mck_to_mainck( PMC_PCK_PRES_CLK_1 ); /* Switch on internal fast RC oscillator, switch Main Clock source to internal fast RC oscillator and disables external fast crystal */ pmc_switch_mainck_to_fastrc( CKGR_MOR_MOSCRCF_8_MHz ); /* Disable external fast crystal */ pmc_osc_disable_xtal( 0 ); /* Disable PLLA */ pmc_disable_pllack( ); /* This above process introduces certain delay. Add delay to the elapsed cycles */ elapsed_cycles += rtt_read_timer_value( RTT ); while ( wake_up_interrupt_triggered == false && elapsed_cycles < total_sleep_cycles ) { uint32_t current_sleep_cycles = total_sleep_cycles - elapsed_cycles; /* Start real-time timer and alarm */ rtt_init( RTT, RTT_CLOCK_PRESCALER ); rtt_write_alarm_time( RTT, ( current_sleep_cycles > RTT_MAX_CYCLES ) ? RTT_MAX_CYCLES - RC_OSC_DELAY_CYCLES : current_sleep_cycles - RC_OSC_DELAY_CYCLES ); __asm("wfi"); /* Enter WAIT mode */ //pmc_enable_waitmode(); /* Clear wake-up status */ rtt_get_status( RTT ); /* Add sleep time to the elapsed cycles */ elapsed_cycles += rtt_read_timer_value( RTT ); } /* Re-enable real-time timer to time clock reinitialisation delay */ rtt_init( RTT, RTT_CLOCK_PRESCALER ); /* Reinit fast clock. This takes ~19ms, but the timing has been compensated */ init_clocks(); /* Disable unused clock to save power */ pmc_osc_disable_fastrc(); /* Restore system I/O pins */ matrix_set_system_io( system_io_backup_value ); /* Restore WLAN bus */ //platform_bus_exit_powersave(); // /* Restore platform-specific settings */ // platform_exit_powersave(); /* Add clock reinitialisation delay to elapsed cycles */ elapsed_cycles += rtt_read_timer_value( RTT ); /* Disable RTT to save power */ RTT->RTT_MR = (uint32_t)( 1 << 20 ); } } /* Start atomic operation */ DISABLE_INTERRUPTS; /* Switch SysTick back on */ SysTick->CTRL |= ( SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk ); /* Clear flag indicating interrupt triggered by wake up pin */ wake_up_interrupt_triggered = false; /* End atomic operation */ ENABLE_INTERRUPTS; /* Return total time in milliseconds */ return CYCLES_TO_MS( elapsed_cycles ); }