⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.c

📁 Freescale MCF5445evb 参考测试代码
💻 C
字号:
/*!  * \file    clock.c * \brief   Driver for the on-chip Clock Module * \version $Revision: 1.4 $ * \author  Michael Norman * * Driver for the on-chip clock module which includes a PLL,  * crystal oscillator, and low-power divider. * * \todo    Add section assignment to allow linker files to  *          force all code and data into non-sdram address */#include "common.h"#include "clock.h"#include "sdramc.h"/********************************************************************//*!  * The input reference frequency (in Hz).  This variable should be placed in * stable RAM that will be accessible at all possible clock frequencies. */static int clock_fref = FREF;/********************************************************************//*! * \brief   Initialize the on-chip PLL * \param   fref    Input reference frequency (in Hz) * \param   fsys    Desired system frequency (in Hz) * \param   flags   Optional parameter bit field * \return  The resulting output system frequency (in Hz) *  * The PLL has three modes of operation: normal mode with crystal reference, * normal mode with external reference, and limp mode.  In normal mode with  * a crystal reference, the PLL receives an input clock frequency from the  * crystal oscillator circuit and multiplies the frequency to create the PLL * output clock. It can synthesize frequencies ranging from 4x to 34x the  * input frequency. Normal mode with external reference is the same except * EXTAL is driven by an external clock. * *  * In limp mode the PLL is bypassed and the device runs from a factor of the * input clock (EXTAL). In this mode, EXTAL feeds a 5-bit programmable  * counter that divides the input clock by 2^n, where n is the value of the  * programmable counter field, MISCCR[LPDIV].  *  * \todo    Add flags for *          1) CLOCK_PLL_FORCE_60 - try to force fvco to be a valid multiple *             of 60 MHz so the USB clock can be derived from the PLL */intclock_pll_init (int fref, int fsys, int flags, void (*isr)(void)){    int p, pn, px, o, on, ox, fvco, pfd, outdiv1, outdiv3, diff;            ASSERT ((fref >= CLOCK_PLL_FREF_MIN) && (fref <= CLOCK_PLL_FREF_MAX));    ASSERT ((fsys >= CLOCK_PLL_FSYS_MIN) && (fsys <= CLOCK_PLL_FSYS_MAX));        /* Save off fref value */    clock_fref = fref;        if (!(flags & CLOCK_PLL_DEFAULT))    {        /*         * Calculate the PFD and OUTDIV1:         * Fsys = Fvco / OUTDIV1         * Fvco = Fref * PFD         */                /* minimum possible pfd */        pn = (CLOCK_PLL_FVCO_MIN / fref) + ((CLOCK_PLL_FVCO_MIN % fref) ? 1 : 0);                /* maximum possible pfd */        px = CLOCK_PLL_FVCO_MAX / fref;        /* minimum possible outdiv1 */        on = ((pn * fref) / fsys) + (((pn * fref) % fsys) ? 1 : 0);                /* maximum possible outdiv1 */        ox = ((px * fref) / fsys) + (((px * fref) % fsys) ? 1 : 0);                diff = fsys;        for (p = pn; p <= px; p++)        {            fvco = fref * p;                        for (o = on; o <= ox; o++)            {                /* exact match */                if ((fvco / o) == fsys)                {                    pfd = p;                    outdiv1 = o;                    p = px;                    break;                }                /* We've gone below the desired fsys                 * Check diff and move on to next iteration of pfd */                else if ((fvco / o) < fsys)                {                    if ((fsys - (fvco / o)) < diff)                    {                        diff = fsys - (fvco / o);                        pfd = p;                        outdiv1 = o;                    }                    break;                }                /* We are still above the desired fsys.                 * Check diff and move on to next iteration of outdiv1                  * within this pfd value.  Notice this will allow a value                 * larger than the desired fsys to be the outcome if it                 * results in the closest valid setting. */                else /* ((fvco / o) > fsys) */                {                    /* Make sure these settings result in a valid fsys.                     * It is possible to step off the upper edge here... */                    if ((fvco / o) > CLOCK_PLL_FSYS_MAX)                        break;                                        if (((fvco / o) - fsys) < diff)                    {                        diff = (fvco / o) - fsys;                        pfd = p;                        outdiv1 = o;                    }                }            }        }          //        sdram_enter_self_refresh();        clock_enter_limp(1);        /* Determine FBCLK output divider */        if (flags & CLOCK_PLL_FBCLK_NONE)            outdiv3 = 0;        else        {            if (flags & CLOCK_PLL_FBCLK_DIV8)                outdiv3 = outdiv1*8 - 1;            else                outdiv3 = outdiv1*4 - 1;        }                /* Apply new PLL settings */        MCF_PLL_PCR = 0            | MCF_PLL_PCR_OUTDIV1(outdiv1 - 1)            | MCF_PLL_PCR_OUTDIV2(outdiv1*2 - 1)            | MCF_PLL_PCR_OUTDIV3(outdiv3)            | MCF_PLL_PCR_OUTDIV4(pfd-1)            | MCF_PLL_PCR_OUTDIV5(0)            | MCF_PLL_PCR_PFDR(pfd);        clock_exit_limp();//        sdram_exit_self_refresh();    }        if (flags & CLOCK_PLL_LOLIRQ)    {        if (isr == NULL)            isr = clock_irq_handler;                MCF_INTC1_ICR57 = MCF_INTC_ICR_IL(7);        MCF_INTC1_CIMR = MCF_INTC_CIMR_CIMR(57);        mcf5xxx_set_handler (128 + 57, (ADDRESS) isr);        MCF_PLL_PSR |= MCF_PLL_PSR_LOLIRQ;    }        if (flags & CLOCK_PLL_LOLRE)    {        MCF_PLL_PSR |= MCF_PLL_PSR_LOLRE;    }        if (flags & CLOCK_PLL_LOLDIS)    {        MCF_PLL_PSR |= MCF_PLL_PSR_LOLDIS;    }            return clock_get_fsys();}/********************************************************************/voidclock_irq_handler (void){    if (MCF_PLL_PSR & MCF_PLL_PSR_LOCKS)    {        MCF_PLL_PSR &= ~MCF_PLL_PSR_LOCKS;                #ifdef DEBUG_PRINT         printf("Loss of Lock!\n");        #endif        /* Add additional code here if desired */    }}/********************************************************************//* * \brief   Enter Limp mode  *           * Place the device into low-frequency limp mode, in which the PLL is  * bypassed and the device runs from a factor of the input clock (EXTAL).  * In this mode, EXTAL feeds a 5-bit programmable counter that divides  * the input clock by 2^n, where n is the value of the programmable  * counter field, MISCCR[LPDIV]. * * \param   lpdiv   decoded divider (2^n (not just n)) */voidclock_enter_limp (int lpdiv){    int i, j, retval;        /* Check bounds of divider */    if (lpdiv < CLOCK_LPD_MIN)     	lpdiv = CLOCK_LPD_MIN;    if (lpdiv > CLOCK_LPD_MAX)        lpdiv = CLOCK_LPD_MAX;        /* Round divider down to nearest power of two */    for (i = 0, j = lpdiv; j != 1; j >>= 1, i++)     {};        /* Apply the divider to the system clock */    MCF_CCM_CDR = (MCF_CCM_CDR & 0x00FF) | MCF_CCM_CDR_LPDIV(i);        /* Enable Limp Mode */    MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;}/********************************************************************//* * \brief   Exit Limp mode * \warning The PLL should be set and locked prior to exiting Limp mode */voidclock_exit_limp (void){	int pfd, outdiv1;	    /* Exit Limp mode */    MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_LIMP;}/********************************************************************//* * \brief Get the value of the current system clock * \return  current system clock frequency (in Hz) */intclock_get_fsys (void){	int fsys;		if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP)	{	    /* Calculate Limp mode low-power divider setting */	    int lpdiv = (MCF_CCM_CDR & MCF_CCM_CDR_LPDIV_MASK) >> 8;        fsys = clock_fref / (1 << lpdiv);	}	else	{        /* Calculate PLL settings */	    int pfd, outdiv1;        pfd = (MCF_PLL_PCR & MCF_PLL_PCR_PFDR_MASK) >> 24;        outdiv1 = MCF_PLL_PCR & MCF_PLL_PCR_OUTDIV1_MASK;        fsys = (clock_fref * pfd) / (outdiv1 + 1);	}    return fsys;}/********************************************************************//* * \brief Get the value of the current (internal) bus clock * \return  current bus clock frequency (in Hz) */intclock_get_fbus (void){    int pfd, outdiv2;        /* Calculate PLL settings */    pfd = (MCF_PLL_PCR & MCF_PLL_PCR_PFDR_MASK) >> 24;    outdiv2 = (MCF_PLL_PCR & MCF_PLL_PCR_OUTDIV2_MASK) >> 4;    return ((clock_fref * pfd) / (outdiv2 + 1));}/********************************************************************//* * \brief Get the value of the current FlexBus clock * \return  current FlexBus clock frequency (in Hz) */intclock_get_ffb (void){    int pfd, outdiv3;        /* Calculate PLL settings */    pfd = (MCF_PLL_PCR & MCF_PLL_PCR_PFDR_MASK) >> 24;    outdiv3 = (MCF_PLL_PCR & MCF_PLL_PCR_OUTDIV3_MASK) >> 8;        if (outdiv3 == 0)        return 0;    else        return ((clock_fref * pfd) / (outdiv3 + 1));}/********************************************************************//* * \brief Get the value of the current PCI clock * \return  current PCI clock frequency (in Hz) */intclock_get_fpci (void){    int pfd, outdiv4;        /* Calculate PLL settings */    pfd = (MCF_PLL_PCR & MCF_PLL_PCR_PFDR_MASK) >> 24;    outdiv4 = (MCF_PLL_PCR & MCF_PLL_PCR_OUTDIV4_MASK) >> 12;    if (outdiv4 == 0)        return 0;    else        return ((clock_fref * pfd) / (outdiv4 + 1));}/********************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -