- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# pm_conf_clocks.c

Go to the documentation of this file.

    00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
    00016 /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
    00017  *
    00018  * Redistribution and use in source and binary forms, with or without
    00019  * modification, are permitted provided that the following conditions are met:
    00020  *
    00021  * 1. Redistributions of source code must retain the above copyright notice, this
    00022  * list of conditions and the following disclaimer.
    00023  *
    00024  * 2. Redistributions in binary form must reproduce the above copyright notice,
    00025  * this list of conditions and the following disclaimer in the documentation
    00026  * and/or other materials provided with the distribution.
    00027  *
    00028  * 3. The name of Atmel may not be used to endorse or promote products derived
    00029  * from this software without specific prior written permission.
    00030  *
    00031  * 4. This software may only be redistributed and used in connection with an Atmel
    00032  * AVR product.
    00033  *
    00034  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
    00035  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00036  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
    00037  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
    00038  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    00039  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    00040  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    00041  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00042  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00043  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
    00044  *
    00045  */
    00046
    00047 #include <string.h>
    00048 #include "compiler.h"
    00049 #include "pm.h"
    00050
    00051
    00052 extern void flashc_set_wait_state(unsigned int wait_state);
    00053 #if (defined AVR32_FLASHC_210_H_INCLUDED)
    00054 extern void flashc_issue_command(unsigned int command, int page_number);
    00055 #endif
    00056
    00057
    00058 #define PM_MAX_MUL                ((1 << AVR32_PM_PLL0_PLLMUL_SIZE) - 1)
    00059
    00060
    00061 int pm_configure_clocks(pm_freq_param_t *param)
    00062 {
    00063   // Supported frequencies:
    00064   // Fosc0 mul div PLL div2_en cpu_f pba_f   Comment
    00065   //  12   15   1  192     1     12    12
    00066   //  12    9   3   40     1     20    20    PLL out of spec
    00067   //  12   15   1  192     1     24    12
    00068   //  12    9   1  120     1     30    15
    00069   //  12    9   3   40     0     40    20    PLL out of spec
    00070   //  12   15   1  192     1     48    12
    00071   //  12   15   1  192     1     48    24
    00072   //  12    8   1  108     1     54    27
    00073   //  12    9   1  120     1     60    15
    00074   //  12    9   1  120     1     60    30
    00075   //  12   10   1  132     1     66    16.5
    00076   //
    00077   unsigned long in_cpu_f  = param->cpu_f;
    00078   unsigned long in_osc0_f = param->osc0_f;
    00079   unsigned long mul, div, div2_en = 0, div2_cpu = 0, div2_pba = 0;
    00080   unsigned long pll_freq, rest;
    00081   Bool b_div2_pba, b_div2_cpu;
    00082
    00083   // Switch to external Oscillator 0
    00084   pm_switch_to_osc0(&AVR32_PM, in_osc0_f, param->osc0_startup);
    00085
    00086   // Start with CPU freq config
    00087   if (in_cpu_f == in_osc0_f)
    00088   {
    00089     param->cpu_f = in_osc0_f;
    00090     param->pba_f = in_osc0_f;
    00091     return PM_FREQ_STATUS_OK;
    00092   }
    00093   else if (in_cpu_f < in_osc0_f)
    00094   {
    00095     // TBD
    00096   }
    00097
    00098   rest = in_cpu_f % in_osc0_f;
    00099
    00100   for (div = 1; div < 32; div++)
    00101   {
    00102     if ((div * rest) % in_osc0_f == 0)
    00103       break;
    00104   }
    00105   if (div == 32)
    00106     return PM_FREQ_STATUS_FAIL;
    00107
    00108   mul = (in_cpu_f * div) / in_osc0_f;
    00109
    00110   if (mul > PM_MAX_MUL)
    00111     return PM_FREQ_STATUS_FAIL;
    00112
    00113   // export 2power from PLL div to div2_cpu
    00114   while (!(div % 2))
    00115   {
    00116     div /= 2;
    00117     div2_cpu++;
    00118   }
    00119
    00120   // Here we know the mul and div parameter of the PLL config.
    00121   // . Check out if the PLL has a valid in_cpu_f.
    00122   // . Try to have for the PLL frequency (VCO output) the highest possible value
    00123   //   to reduce jitter.
    00124   while (in_osc0_f * 2 * mul / div < AVR32_PM_PLL_VCO_RANGE0_MAX_FREQ)
    00125   {
    00126     if (2 * mul > PM_MAX_MUL)
    00127       break;
    00128     mul *= 2;
    00129     div2_cpu++;
    00130   }
    00131
    00132   if (div2_cpu != 0)
    00133   {
    00134     div2_cpu--;
    00135     div2_en = 1;
    00136   }
    00137
    00138   pll_freq = in_osc0_f * mul / (div * (1 << div2_en));
    00139
    00140   // Update real CPU Frequency
    00141   param->cpu_f = pll_freq / (1 << div2_cpu);
    00142   mul--;
    00143
    00144   pm_pll_setup(&AVR32_PM
    00145   , 0   // pll
    00146   , mul // mul
    00147   , div // div
    00148   , 0   // osc
    00149   , 16  // lockcount
    00150   );
    00151
    00152   pm_pll_set_option(&AVR32_PM
    00153   , 0 // pll
    00154   // PLL clock is lower than 160MHz: need to set pllopt.
    00155   , (pll_freq < AVR32_PM_PLL_VCO_RANGE0_MIN_FREQ) ? 1 : 0 // pll_freq
    00156   , div2_en // pll_div2
    00157   , 0 // pll_wbwdisable
    00158   );
    00159
    00160   rest = pll_freq;
    00161   while (rest > AVR32_PM_PBA_MAX_FREQ ||
    00162          rest != param->pba_f)
    00163   {
    00164     div2_pba++;
    00165     rest = pll_freq / (1 << div2_pba);
    00166     if (rest < param->pba_f)
    00167       break;
    00168   }
    00169
    00170   // Update real PBA Frequency
    00171   param->pba_f = pll_freq / (1 << div2_pba);
    00172
    00173   // Enable PLL0
    00174   pm_pll_enable(&AVR32_PM, 0);
    00175
    00176   // Wait for PLL0 locked
    00177   pm_wait_for_pll0_locked(&AVR32_PM);
    00178
    00179   if (div2_cpu)
    00180   {
    00181     b_div2_cpu = TRUE;
    00182     div2_cpu--;
    00183   }
    00184   else
    00185     b_div2_cpu = FALSE;
    00186
    00187   if (div2_pba)
    00188   {
    00189     b_div2_pba = TRUE;
    00190     div2_pba--;
    00191   }
    00192   else
    00193     b_div2_pba = FALSE;
    00194
    00195   pm_cksel(&AVR32_PM
    00196   , b_div2_pba, div2_pba // PBA
    00197   , b_div2_cpu, div2_cpu // PBB
    00198   , b_div2_cpu, div2_cpu // HSB
    00199   );
    00200
    00201   if (param->cpu_f > AVR32_FLASHC_FWS_0_MAX_FREQ)
    00202   {
    00203     flashc_set_wait_state(1);
    00204 #if (defined AVR32_FLASHC_210_H_INCLUDED)
    00205     if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ)
    00206       flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
    00207     else
    00208       flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
    00209 #endif
    00210   }
    00211   else
    00212   {
    00213     flashc_set_wait_state(0);
    00214 #if (defined AVR32_FLASHC_210_H_INCLUDED)
    00215     if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ)
    00216       flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
    00217     else
    00218       flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
    00219 #endif
    00220   }
    00221
    00222   pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0);
    00223
    00224   return PM_FREQ_STATUS_OK;
    00225 }
    00226
    00227
    00228 void pm_configure_usb_clock(void)
    00229 {
    00230 #if (defined __AVR32_UC3A3256__)  || (defined __AVR32_UC3A3128__)  || (defined __AVR32_UC3A364__)  || \
    00231     (defined __AVR32_UC3A3256S__) || (defined __AVR32_UC3A3128S__) || (defined __AVR32_UC3A364S__) || \
    00232     (defined __AT32UC3A3256__)  || (defined __AT32UC3A3128__)  || (defined __AT32UC3A364__) ||        \
    00233     (defined __AT32UC3A3256S__) || (defined __AT32UC3A3128S__) || (defined __AT32UC3A364S__)
    00234
    00235   // Setup USB GCLK.
    00236   pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc
    00237                   0,                  // osc_or_pll: use Osc (if 0) or PLL (if 1)
    00238                   0,                  // pll_osc: select Osc0/PLL0 or Osc1/PLL1
    00239                   0,                  // diven
    00240                   0);                 // div
    00241
    00242   // Enable USB GCLK.
    00243   pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
    00244 #else
    00245   // Use 12MHz from OSC0 and generate 96 MHz
    00246   pm_pll_setup(&AVR32_PM, 1,  // pll.
    00247       7,   // mul.
    00248       1,   // div.
    00249       0,   // osc.
    00250       16); // lockcount.
    00251
    00252   pm_pll_set_option(&AVR32_PM, 1, // pll.
    00253       1,  // pll_freq: choose the range 80-180MHz.
    00254       1,  // pll_div2.
    00255       0); // pll_wbwdisable.
    00256
    00257   // start PLL1 and wait forl lock
    00258   pm_pll_enable(&AVR32_PM, 1);
    00259
    00260   // Wait for PLL1 locked.
    00261   pm_wait_for_pll1_locked(&AVR32_PM);
    00262
    00263   pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB,  // gc.
    00264             1,  // osc_or_pll: use Osc (if 0) or PLL (if 1).
    00265             1,  // pll_osc: select Osc0/PLL0 or Osc1/PLL1.
    00266             0,  // diven.
    00267             0); // div.
    00268   pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
    00269 #endif
    00270 }