/** * \brief Set default clock (MCK = 24MHz). */ static void set_default_working_clock(void) { #if (SAMG) /* Switch MCK to slow clock */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); /* * Configure PLL and switch clock. * MCK = XTAL * (PLL_DEFAULT_MUL+1) / PLL_DEFAULT_DIV / MCK_DEFAULT_DIV * = 24 MHz */ example_switch_clock(PLL_DEFAULT_MUL, PLL_COUNT, PLL_DEFAULT_DIV, MCK_DEFAULT_DIV); #else /* Switch MCK to slow clock */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); /* Switch mainck to external xtal */ pmc_switch_mainck_to_xtal(0, BOARD_OSC_STARTUP_US); /* * Configure PLL and switch clock. * MCK = XTAL * (PLL_DEFAULT_MUL+1) / PLL_DEFAULT_DIV / MCK_DEFAULT_DIV * = 24 MHz */ example_switch_clock(PLL_DEFAULT_MUL, PLL_COUNT, PLL_DEFAULT_DIV, MCK_DEFAULT_DIV); /* Disable unused clock to save power */ pmc_osc_disable_fastrc(); #endif /* Save current clock */ g_ul_current_mck = 24000000; /* 24MHz */ }
/** * Restore clock settings */ __always_inline static void pmc_restore_clock_setting( uint32_t osc_setting, uint32_t pll0_setting, uint32_t pll1_setting, uint32_t mck_setting) { uint32_t mckr; uint32_t pll_sr = 0; /* Switch MCK to slow clock */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); /* Switch mainck to external xtal */ if (CKGR_MOR_MOSCXTBY == (osc_setting & CKGR_MOR_MOSCXTBY)) { /* Bypass mode */ pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS, pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, CHIP_FREQ_SLCK_RC)); pmc_osc_disable_fastrc(); } else if (CKGR_MOR_MOSCXTEN == (osc_setting & CKGR_MOR_MOSCXTEN)) { /* External XTAL */ pmc_switch_mainck_to_xtal(PMC_OSC_XTAL, pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, CHIP_FREQ_SLCK_RC)); pmc_osc_disable_fastrc(); } if (pll0_setting & CKGR_PLLAR_MULA_Msk) { PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | pll0_setting; pll_sr |= PMC_SR_LOCKA; } #if (SAM3S || SAM4S) if (pll1_setting & CKGR_PLLBR_MULB_Msk) { PMC->CKGR_PLLBR = pll1_setting; pll_sr |= PMC_SR_LOCKB; } #elif (SAM3U || SAM3XA) if (pll1_setting & CKGR_UCKR_UPLLEN) { PMC->CKGR_UCKR = pll1_setting; pll_sr |= PMC_SR_LOCKU; } #else UNUSED(pll1_setting); #endif /* Wait MCK source ready */ switch(mck_setting & PMC_MCKR_CSS_Msk) { case PMC_MCKR_CSS_PLLA_CLK: while (!(PMC->PMC_SR & PMC_SR_LOCKA)); break; #if (SAM3S || SAM4S) case PMC_MCKR_CSS_PLLB_CLK: while (!(PMC->PMC_SR & PMC_SR_LOCKB)); break; #elif (SAM3U || SAM3XA) case PMC_MCKR_CSS_UPLL_CLK: while (!(PMC->PMC_SR & PMC_SR_LOCKU)); break; #endif } /* Switch to faster clock */ mckr = PMC->PMC_MCKR; /* Set PRES */ PMC->PMC_MCKR = (mckr & ~PMC_MCKR_PRES_Msk) | (mck_setting & PMC_MCKR_PRES_Msk); while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); /* Set CSS and others */ PMC->PMC_MCKR = mck_setting; while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); /* Waiting all restored PLLs ready */ while (!(PMC->PMC_SR & pll_sr)); }
/** * \brief Change clock configuration. * * \param p_uc_str Hint string to be output on console before changing clock. */ static void user_change_clock(uint8_t *p_uc_str) { uint8_t uc_key; uint32_t ul_id; /* Print menu */ puts(CLOCK_LIST_MENU); while (uart_read(CONSOLE_UART, &uc_key)) { } printf("Select option is: %c\n\r\n\r", uc_key); if (p_uc_str) { puts((char const *)p_uc_str); } while (!uart_is_tx_empty(CONSOLE_UART)) { } if ((uc_key >= MIN_CLOCK_FAST_RC_ITEM) && (uc_key <= MAX_CLOCK_FAST_RC_ITEM)) { ul_id = uc_key - MIN_CLOCK_FAST_RC_ITEM; /* Save current clock */ g_ul_current_mck = g_fastrc_clock_list[ul_id][0]; /* Switch MCK to Slow clock */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); /* Switch mainck to fast RC */ pmc_osc_enable_fastrc(CKGR_MOR_MOSCRCF_8_MHz); pmc_switch_mainck_to_fastrc(g_fastrc_clock_list[ul_id][1]); /* Switch MCK to mainck */ pmc_switch_mck_to_mainck(g_fastrc_clock_list[ul_id][2]); /* Disable unused clock to save power */ pmc_osc_disable_xtal(0); example_disable_pll(); } else if ((uc_key >= MIN_CLOCK_PLL_ITEM) && (uc_key <= MAX_CLOCK_PLL_ITEM)) { ul_id = uc_key - MIN_CLOCK_PLL_ITEM; /* Save current clock */ g_ul_current_mck = g_pll_clock_list[ul_id][0]; #if (SAMG) /* Switch MCK to main clock */ pmc_switch_mck_to_mainck(PMC_MCKR_PRES_CLK_1); #else /* Switch MCK to slow clock */ pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1); /* Switch mainck to external xtal */ pmc_switch_mainck_to_xtal(0, BOARD_OSC_STARTUP_US); #endif /* Configure PLL and switch clock */ example_switch_clock(g_pll_clock_list[ul_id][1], PLL_COUNT, g_pll_clock_list[ul_id][2], g_pll_clock_list[ul_id][3]); #if (!SAMG) /* Disable unused clock to save power */ pmc_osc_disable_fastrc(); #endif } else { puts("Clock is not changed.\r"); } }
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 ); }