예제 #1
0
void SYS_CLK_Initialize ( const SYS_CLK_INIT *clkInit )
{
    CLK_SOURCES_SYSTEM systemSource;
    uint32_t clockClosest = 0;

    /* If the user has not passed anything that means he want to retain the
     * configuration bit settings  */
    if ( clkInit != NULL )
    {
        systemSource = PLIB_OSC_CurrentSysClockGet ( OSC_PLIB_ID );

        if (!_SYS_CLK_SystemClockSet ( systemSource, clkInit->systemClockFrequencyHz,
                clkInit->waitTillComplete, &clockClosest ))
        {
            SYS_ASSERT(false, "Critical failure when setting system clock");
            return;
        }
        
        #if defined(PLIB_OSC_ExistsOnWaitAction)
        if ( PLIB_OSC_ExistsOnWaitAction ( OSC_PLIB_ID ) )
        {
            /* Sets the oscillator's response to a 'Wait' instruction */
            PLIB_OSC_OnWaitActionSet ( OSC_PLIB_ID, clkInit->onWaitInstruction );
        }
        #endif
    }
    else
    {
        clkObject.systemClock = _SYS_CLK_SystemClockRead ();
    }

    clkObject.callback=NULL;
}
예제 #2
0
bool _SYS_CLK_ReferenceFrequencySet ( CLK_BUSES_REFERENCE referenceBus, CLK_SOURCES_REFERENCE referenceSource,
            uint32_t targetFreqHz, bool waitUntilComplete, uint32_t *clockClosest )
{
    unsigned long inputFreq = 0, tempFreq = 0;
    uint32_t pllMult = 0, pllIDiv = 0;
    double  number = 0.f;
    unsigned long ipart_number = 0;
    double  fpart_number = 0.f;
    unsigned long  divisor = 0;
    float trimValue = 0.f;
    const long  scale = 100;
    CLK_SOURCES_SYSTEM systemSource;

    if (referenceBus != CLK_BUS_REFERENCE_1)
        return false;

    switch ( referenceSource )
    {
        case CLK_SOURCE_REF_SYSTEMCLK:
            /* The clock source is System clock itself */
            inputFreq = clkObject.systemClock;
            break;
        case CLK_SOURCE_REF_PBCLK_BUS1:
            /* The clock source is Peripheral clock */
            inputFreq = clkObject.peripheralClock[referenceBus];
            break;

        case CLK_SOURCE_REF_PRIMARY:
            /* If the System clock is directly using the from the Primary oscillator
            clock, return the configured primary oscillator frequency */
            inputFreq = SYS_CLK_CONFIG_PRIMARY_XTAL;
            break;

        case CLK_SOURCE_REF_FRC:
            /* Source of system clock is internal fast RC. If the System clock
            is directly using the fast RC clock, return the Fast RC clock */
            inputFreq = SYS_CLK_FRC_CLOCK;
            break;

        case CLK_SOURCE_REF_LPRC:
            /* Processor's internal LPRC clock */
            inputFreq = SYS_CLK_LPRC_CLOCK;
            break;

        case CLK_SOURCE_REF_SECONDARY:
            inputFreq = SYS_CLK_CONFIG_SECONDARY_XTAL;
            break;
        case CLK_SOURCE_REF_USBPLL_OUT:
            /* Find the closest register value in the hardware */
            /* USBPLL_OUT is not directly an input to REFCLOCK. The USBPLL_OUT
             * is given to REFCLOCK before the SYS_CLK_CONFIG_USBPLL_DIVISOR
             * (value 2) is applied. */
            inputFreq = SYS_CLK_UPLL_BEFORE_DIV2_FREQ;
            break;

        case CLK_SOURCE_REF_SYSPLL_OUT:
            /* Source of system clock is SPLL with divisors */
            pllMult = _SYS_CLK_PLLMultiplierRead();
            pllIDiv = _SYS_CLK_PLLInputDividerRead();

            /* Read the current system clock source from the register */
            systemSource = PLIB_OSC_CurrentSysClockGet ( OSC_PLIB_ID );

            if (systemSource == SYS_CLK_SOURCE_PRIMARY_SYSPLL)
            {
                inputFreq = ( SYS_CLK_CONFIG_PRIMARY_XTAL * pllMult ) / pllIDiv;
            }
            else if (systemSource == SYS_CLK_SOURCE_FRC_SYSPLL)
            {
                inputFreq = ( SYS_CLK_FRC_CLOCK * pllMult ) / pllIDiv;
            }
            else
            {
                inputFreq = 0;
            }
            break;

        case CLK_SOURCE_REF_EXTERNAL:
            /* Source of system clock is internal fast RC with PLL.
             Find the closest register value in the hardware */
            inputFreq = SYS_CLK_CONFIG_EXTERNAL_CLOCK;
            break;

        default:
            break;
    }

    /* Failure case if the input is not supported */
    if (inputFreq == 0)
    {
        *clockClosest = 0;
        clkObject.systemClockStatus = SYS_CLK_OPERATION_FAIL_NOT_ACHIEVABLE;
        return false;
    }

    /* Find the divisor value, find the equation in the datasheet */
    number = inputFreq  / ( targetFreqHz * 2.0 );
    ipart_number = (unsigned long) number;
    divisor = ipart_number;
    fpart_number = number - ipart_number;

    /* Check whether the divisor is within limit */
    if ( ( divisor > 0 ) && ( divisor <= CLK_REFERENCE_DIVISOR_MAX ) )
    {
        //Blocking implementation
        while(waitUntilComplete && PLIB_OSC_ReferenceOscSourceChangeIsActive ( OSC_PLIB_ID, referenceBus ))
        {
            PLIB_OSC_ReferenceOscDisable( OSC_PLIB_ID, referenceBus );
            continue;
        }
        trimValue  = fpart_number*512;

        if (trimValue > CLK_REFERENCE_TRIM_MAX)
        {
            trimValue = CLK_REFERENCE_TRIM_MAX;
        }
        else if (trimValue < 0)
        {
            //We really should not have -ive trim value
            trimValue = 0;
        }

        if ( !PLIB_OSC_ReferenceOscSourceChangeIsActive ( OSC_PLIB_ID, referenceBus ) )
        {
            /* Unlock before you switch */
            SYS_DEVCON_SystemUnlock ( );

            /* Switch the Reference clock source */
            PLIB_OSC_ReferenceOscBaseClockSelect ( OSC_PLIB_ID,
                    CLK_BUS_REFERENCE_1, referenceSource );

            PLIB_OSC_ReferenceOscDivisorValueSet ( OSC_PLIB_ID, referenceBus, divisor );
            PLIB_OSC_ReferenceOscTrimSet ( OSC_PLIB_ID, referenceBus, trimValue );

            PLIB_OSC_ReferenceOscEnable ( OSC_PLIB_ID, referenceBus );
            PLIB_OSC_ReferenceOutputEnable ( OSC_PLIB_ID, referenceBus );
            /* Lock it back right after completing all the register related operations */
            SYS_DEVCON_SystemLock ( );

            tempFreq = inputFreq / ( 2 * ( divisor * scale + ( trimValue * scale / 512 ) ) ) ;
            *clockClosest = tempFreq * scale;
        }
        else
        {
            *clockClosest = 0;

            clkObject.systemClockStatus =
                    SYS_CLK_OPERATION_FAIL_REGISTER_NOT_READY;

            return false;
        }
    }
    else
    {
        clkObject.systemClockStatus = SYS_CLK_OPERATION_FAIL_NOT_ACHIEVABLE;

        *clockClosest = 0;

        return false;
    }


    /* Control is here, means switching operation is either complete or in
    progress, not failure */
    return true;
}
예제 #3
0
uint32_t _SYS_CLK_SystemClockRead ( void )
{
    CLK_SOURCES_SYSTEM systemSource;
    uint32_t systemClockHz = 0, multiplier = 0, divisor = 0, pllInput = 0;
    uint32_t inputDivisor = 0;

    /* Read the current system clock source from the register */
    systemSource = PLIB_OSC_CurrentSysClockGet ( OSC_PLIB_ID );
    inputDivisor = _SYS_CLK_PLLInputDividerRead();

    if ( ( systemSource == SYS_CLK_SOURCE_PRIMARY_SYSPLL ) ||
            ( systemSource == SYS_CLK_SOURCE_FRC_SYSPLL ) )
    {
        /* Check if the source is a PLL based one, validate the input frequency */
        pllInput = SYS_CLK_CONFIG_PRIMARY_XTAL / inputDivisor;

        if ( ( pllInput < OSC_SYSPLL_UFIN_MIN  ) || ( pllInput > OSC_SYSPLL_UFIN_MAX ) )
        {
            clkObject.systemClockStatus = SYS_CLK_PLL_INVALID_INP_FREQUENCY;
            return 0;
        }
    }
    /* we need the source later for other clocks  */
    clkObject.systemClockSource = systemSource;
    switch ( systemSource )
    {
        case SYS_CLK_SOURCE_FRC_BY_DIV:
            /* System clock is FRC clock divided by the configured divisor value */
            divisor = _SYS_CLK_FRCDividerRead();
            
            /* FRC clock is a constant. Do direct division */
            systemClockHz = ( SYS_CLK_FRC_CLOCK / divisor );
            break;
        case SYS_CLK_SOURCE_FRC_BY_16:
            /* The System clock clock is FRC/16 */
            systemClockHz =( SYS_CLK_FRC_CLOCK / 16 );
            break;

        case SYS_CLK_SOURCE_LPRC:
            /* System clock is processor's internal LPRC clock */
            systemClockHz = SYS_CLK_LPRC_CLOCK;
            break;
        case SYS_CLK_SOURCE_SECONDARY:
            /* System clock is processor's Secondary oscillator. The secondary
               oscillator frequency is user configured */
            systemClockHz = SYS_CLK_CONFIG_SECONDARY_XTAL;
            break;
        case SYS_CLK_SOURCE_PRIMARY_SYSPLL:
            /* Source of system clock is primary oscillator multiplied by
            the PLL value and divided by the divisor configured by software.
            Software cannot access the input divisor, so that must be configured
            by the user */
            multiplier = _SYS_CLK_PLLMultiplierRead();
            divisor = _SYS_CLK_PLLOutputDividerRead();

            systemClockHz = ( SYS_CLK_CONFIG_PRIMARY_XTAL * multiplier ) /
                    ( divisor * inputDivisor );
            break;
        /* Source of system clock is primary oscillator */
        case SYS_CLK_SOURCE_PRIMARY:
            /* If the System clock is directly using the Secondary oscillator
            clock, return the configured primary oscillator frequency */
            systemClockHz = SYS_CLK_CONFIG_PRIMARY_XTAL;
            break;
        case SYS_CLK_SOURCE_FRC_SYSPLL:
            /* Source of system clock is internal fast RC with PLL and divisors */
            multiplier = _SYS_CLK_PLLMultiplierRead();
            divisor = _SYS_CLK_PLLOutputDividerRead();

            systemClockHz = ( SYS_CLK_FRC_CLOCK * multiplier ) /
                    ( divisor * inputDivisor );
            break;
        /* Source of system clock is internal fast RC */
        case SYS_CLK_SOURCE_FRC:
            /* If the System clock is directly using the fast RC clock,
            return the Fast RC clock */
            systemClockHz = SYS_CLK_FRC_CLOCK;
            break;
        default:
            /* Something wrong */
            systemClockHz = 0;
            break;
    }

    return systemClockHz;
}