/* This source file is part of the ATMEL AVR-UC3-SoftwareFramework-1.7.0 Release */ /*This file has been prepared for Doxygen automatic documentation generation.*/ /*! \file ********************************************************************* * * \brief Power Manager clocks configuration helper. * * * - Compiler: IAR EWAVR32 and GNU GCC for AVR32 * - Supported devices: All AVR32 devices. * - AppNote: * * \author Atmel Corporation: http://www.atmel.com \n * Support and FAQ: http://support.atmel.no/ * *****************************************************************************/ /* Copyright (c) 2009 Atmel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. This software may only be redistributed and used in connection with an Atmel * AVR product. * * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE * */ #include #include "compiler.h" #include "pm.h" extern void flashc_set_wait_state(unsigned int wait_state); #if (defined AVR32_FLASHC_210_H_INCLUDED) extern void flashc_issue_command(unsigned int command, int page_number); #endif #define PM_MAX_MUL ((1 << AVR32_PM_PLL0_PLLMUL_SIZE) - 1) int pm_configure_clocks(pm_freq_param_t *param) { // Supported frequencies: // Fosc0 mul div PLL div2_en cpu_f pba_f Comment // 12 15 1 192 1 12 12 // 12 9 3 40 1 20 20 PLL out of spec // 12 15 1 192 1 24 12 // 12 9 1 120 1 30 15 // 12 9 3 40 0 40 20 PLL out of spec // 12 15 1 192 1 48 12 // 12 15 1 192 1 48 24 // 12 8 1 108 1 54 27 // 12 9 1 120 1 60 15 // 12 9 1 120 1 60 30 // 12 10 1 132 1 66 16.5 // unsigned long in_cpu_f = param->cpu_f; unsigned long in_osc0_f = param->osc0_f; unsigned long mul, div, div2_en = 0, div2_cpu = 0, div2_pba = 0; unsigned long pll_freq, rest; Bool b_div2_pba, b_div2_cpu; // Switch to external Oscillator 0 pm_switch_to_osc0(&AVR32_PM, in_osc0_f, param->osc0_startup); // Start with CPU freq config if (in_cpu_f == in_osc0_f) { param->cpu_f = in_osc0_f; param->pba_f = in_osc0_f; return PM_FREQ_STATUS_OK; } else if (in_cpu_f < in_osc0_f) { // TBD } rest = in_cpu_f % in_osc0_f; for (div = 1; div < 32; div++) { if ((div * rest) % in_osc0_f == 0) break; } if (div == 32) return PM_FREQ_STATUS_FAIL; mul = (in_cpu_f * div) / in_osc0_f; if (mul > PM_MAX_MUL) return PM_FREQ_STATUS_FAIL; // export 2power from PLL div to div2_cpu while (!(div % 2)) { div /= 2; div2_cpu++; } // Here we know the mul and div parameter of the PLL config. // . Check out if the PLL has a valid in_cpu_f. // . Try to have for the PLL frequency (VCO output) the highest possible value // to reduce jitter. while (in_osc0_f * 2 * mul / div < AVR32_PM_PLL_VCO_RANGE0_MAX_FREQ) { if (2 * mul > PM_MAX_MUL) break; mul *= 2; div2_cpu++; } if (div2_cpu != 0) { div2_cpu--; div2_en = 1; } pll_freq = in_osc0_f * mul / (div * (1 << div2_en)); // Update real CPU Frequency param->cpu_f = pll_freq / (1 << div2_cpu); mul--; pm_pll_setup(&AVR32_PM , 0 // pll , mul // mul , div // div , 0 // osc , 16 // lockcount ); pm_pll_set_option(&AVR32_PM , 0 // pll // PLL clock is lower than 160MHz: need to set pllopt. , (pll_freq < AVR32_PM_PLL_VCO_RANGE0_MIN_FREQ) ? 1 : 0 // pll_freq , div2_en // pll_div2 , 0 // pll_wbwdisable ); rest = pll_freq; while (rest > AVR32_PM_PBA_MAX_FREQ || rest != param->pba_f) { div2_pba++; rest = pll_freq / (1 << div2_pba); if (rest < param->pba_f) break; } // Update real PBA Frequency param->pba_f = pll_freq / (1 << div2_pba); // Enable PLL0 pm_pll_enable(&AVR32_PM, 0); // Wait for PLL0 locked pm_wait_for_pll0_locked(&AVR32_PM); if (div2_cpu) { b_div2_cpu = TRUE; div2_cpu--; } else b_div2_cpu = FALSE; if (div2_pba) { b_div2_pba = TRUE; div2_pba--; } else b_div2_pba = FALSE; pm_cksel(&AVR32_PM , b_div2_pba, div2_pba // PBA , b_div2_cpu, div2_cpu // PBB , b_div2_cpu, div2_cpu // HSB ); if (param->cpu_f > AVR32_FLASHC_FWS_0_MAX_FREQ) { flashc_set_wait_state(1); #if (defined AVR32_FLASHC_210_H_INCLUDED) if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ) flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1); else flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1); #endif } else { flashc_set_wait_state(0); #if (defined AVR32_FLASHC_210_H_INCLUDED) if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ) flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1); else flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1); #endif } pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0); return PM_FREQ_STATUS_OK; } void pm_configure_usb_clock(void) { #if UC3A3 // Setup USB GCLK. pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc 0, // osc_or_pll: use Osc (if 0) or PLL (if 1) 0, // pll_osc: select Osc0/PLL0 or Osc1/PLL1 0, // diven 0); // div // Enable USB GCLK. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB); #else // Use 12MHz from OSC0 and generate 96 MHz pm_pll_setup(&AVR32_PM, 1, // pll. 7, // mul. 1, // div. 0, // osc. 16); // lockcount. pm_pll_set_option(&AVR32_PM, 1, // pll. 1, // pll_freq: choose the range 80-180MHz. 1, // pll_div2. 0); // pll_wbwdisable. // start PLL1 and wait forl lock pm_pll_enable(&AVR32_PM, 1); // Wait for PLL1 locked. pm_wait_for_pll1_locked(&AVR32_PM); pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc. 1, // osc_or_pll: use Osc (if 0) or PLL (if 1). 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1. 0, // diven. 0); // div. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB); #endif }