打印
[DemoCode下载]

PLL频率的输出方法

[复制链接]
3252|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
PLL, ck, TE, se, TI


/****************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
* $Revision: 3 $
* $Date: 14/12/25 10:24a $
* @brief
*           Change system clock to different PLL frequency and output system clock from CLKO pin.
*           
* @note
* Copyright (C) 2011 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "M0518.h"


#define PLL_CLOCK   50000000

#define SIGNATURE       0x125ab234
#define FLAG_ADDR       0x20000FFC


/*---------------------------------------------------------------------------------------------------------*/
/* Define functions prototype                                                                              */
/*---------------------------------------------------------------------------------------------------------*/
int32_t pi(void);
void Delay(uint32_t x);
void SYS_PLL_Test(void);
void SYS_Init(void);
void UART0_Init(void);
int32_t main(void);


/*---------------------------------------------------------------------------------------------------------*/
/*  Simple calculation test function                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
#define PI_NUM  256
int32_t f[PI_NUM + 1];
uint32_t piTbl[19] =
{
    3141,
    5926,
    5358,
    9793,
    2384,
    6264,
    3383,
    2795,
    288,
    4197,
    1693,
    9937,
    5105,
    8209,
    7494,
    4592,
    3078,
    1640,
    6284
};

int32_t piResult[19];

int32_t pi(void)
{
    int32_t i, i32Err;
    int32_t a = 10000, b = 0, c = PI_NUM, d = 0, e = 0, g = 0;

    for(; b - c;)
        f[b++] = a / 5;

    i = 0;
    for(; d = 0, g = c * 2; c -= 14,/*printf("%.4d\n",e+d/a),*/ piResult[i++] = e + d / a, e = d % a)
    {
        if(i == 19)
            break;

        for(b = c; d += f[b] * a, f[b] = d % --g, d /= g--, --b; d *= b);
    }
    i32Err = 0;
    for(i = 0; i < 19; i++)
    {
        if(piTbl[i] != piResult[i])
            i32Err = -1;
    }

    return i32Err;
}

void Delay(uint32_t x)
{
    int32_t i;

    for(i = 0; i < x; i++)
    {
        __NOP();
        __NOP();
    }
}

uint32_t g_au32PllSetting[] =
{
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(25) | CLK_PLLCON_NO_4,  /* PLL = 25MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(29) | CLK_PLLCON_NO_4,  /* PLL = 29MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(33) | CLK_PLLCON_NO_4,  /* PLL = 33MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(37) | CLK_PLLCON_NO_4,  /* PLL = 37MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(41) | CLK_PLLCON_NO_4,  /* PLL = 41MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(45) | CLK_PLLCON_NO_4,  /* PLL = 45MHz */
    CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF(49) | CLK_PLLCON_NO_4   /* PLL = 49MHz */
};

void SYS_PLL_Test(void)
{
    int32_t  i;

    /*---------------------------------------------------------------------------------------------------------*/
    /* PLL clock configuration test                                                                             */
    /*---------------------------------------------------------------------------------------------------------*/

    printf("\n-------------------------[ Test PLL ]-----------------------------\n");

    for(i = 0; i < sizeof(g_au32PllSetting) / sizeof(g_au32PllSetting[0]) ; i++)
    {
        /* Switch HCLK clock source to HXT and HCLK source divide 1 */
        CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HXT, CLK_CLKDIV_HCLK(1));

        /* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware. */
        CLK_DisablePLL();

        /* Set PLL frequency */
        CLK->PLLCON = g_au32PllSetting[i];

        /* Waiting for PLL clock ready */
        CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);

        /* Switch HCLK clock source to PLL */
        CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_PLL, CLK_CLKDIV_HCLK(1));

        printf("  Change system clock to %d Hz ...................... ", SystemCoreClock);

        /* Output selected clock to CKO, CKO Clock = HCLK / 2^(1 + 1) */
        CLK_EnableCKO(CLK_CLKSEL2_FRQDIV_S_HCLK, 1, 0);

        /* The delay loop is used to check if the CPU speed is increasing */
        Delay(0x400000);

        if(pi())
        {
            printf("[FAIL]\n");
        }
        else
        {
            printf("[OK]\n");
        }

        /* Disable CKO clock */
        CLK_DisableCKO();
    }
}

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Enable Internal RC 22.1184MHz clock */
    CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);

    /* Waiting for Internal RC clock ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);

    /* Switch HCLK clock source to Internal RC and HCLK source divide 1 */
    CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));

    /* Enable external XTAL 12MHz clock */
    CLK_EnableXtalRC(CLK_PWRCON_XTL12M_EN_Msk);

    /* Waiting for external XTAL clock ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_XTL12M_STB_Msk);

    /* Set core clock as PLL_CLOCK from PLL */
    CLK_SetCoreClock(PLL_CLOCK);

    /* Enable UART module clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Select UART module clock source */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_CLKDIV_UART(1));


    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Set GPB multi-function pins for UART0 RXD(PB.0), TXD(PB.1) and Clock Output(PB.8) */
    SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB0_Msk | SYS_GPB_MFP_PB1_Msk | SYS_GPB_MFP_PB8_Msk);
    SYS->ALT_MFP &= ~SYS_ALT_MFP_PB8_Msk;
    SYS->ALT_MFP3 &= ~SYS_ALT_MFP3_PB8_Msk;
    SYS->GPB_MFP |= (SYS_GPB_MFP_PB0_UART0_RXD | SYS_GPB_MFP_PB1_UART0_TXD | SYS_GPB_MFP_PB8_CLKO);
    SYS->ALT_MFP |=  SYS_ALT_MFP_PB8_CLKO;
    SYS->ALT_MFP3 |= SYS_ALT_MFP3_PB8_CLKO;

}

void UART0_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Reset UART0 module */
    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 Baudrate */
    UART_Open(UART0, 115200);
}

/*---------------------------------------------------------------------------------------------------------*/
/* MAIN function                                                                                           */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
    uint32_t u32data;

    /* In end of main function, program issued CPU reset and write-protection will be disabled. */
    if(SYS_IsRegLocked() == 0)
        SYS_LockReg();

    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Init System, peripheral clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS_LockReg();

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %dHz\n", SystemCoreClock);

    /*
        This sample code will show some function about system manager controller and clock controller:
        1. Read PDID
        2. Get and clear reset source
        3. Setting about BOD
        4. Change system clock depended on different PLL settings
        5. Output system clock from CKO pin, and the output frequency = system clock / 4
    */

    printf("+----------------------------------------+\n");
    printf("|    M0518 System Driver Sample Code    |\n");
    printf("+----------------------------------------+\n");

    if(M32(FLAG_ADDR) == SIGNATURE)
    {
        printf("  CPU Reset success!\n");
        M32(FLAG_ADDR) = 0;
        printf("  Press any key to continue ...\n");
        getchar();
    }

    /*---------------------------------------------------------------------------------------------------------*/
    /* Misc system function test                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Read Part Device ID */
    printf("Product ID 0x%x\n", SYS_ReadPDID());

    /* Get reset source from last operation */
    u32data = SYS_GetResetSrc();
    printf("Reset Source 0x%x\n", u32data);

    /* Clear reset source */
    SYS_ClearResetSrc(u32data);

    /* Unlock protected registers for Brown-Out Detector settings */
    SYS_UnlockReg();

    /* Check if the write-protected registers are unlocked before BOD setting and CPU Reset */
    if(SYS_IsRegLocked() == 0)
    {
        printf("Protected Address is Unlocked\n");
    }

    /* Enable Brown-Out Detector, and set Brown-Out Detector voltage 2.7V */
    SYS_EnableBOD(SYS_BODCR_BOD_INTERRUPT_EN, SYS_BODCR_BOD_VL_2_7V);

    /* Enable BOD IRQ */
    NVIC_EnableIRQ(BOD_IRQn);

    /* Enable Low Voltage Reset function */
    SYS_ENABLE_LVR();

    /* Run PLL Test */
    SYS_PLL_Test();

    /* Write a signature work to SRAM to check if it is reset by software */
    M32(FLAG_ADDR) = SIGNATURE;
    printf("\n\n  >>> Reset CPU <<<\n");

    /* Waiting for message send out */
    UART_WAIT_TX_EMPTY(UART0);

    /* Switch HCLK clock source to Internal RC 22.1184MHz clock and HCLK source divide 1 */
    CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));

    /* Set PLL to Power down mode and HW will also clear PLL_STB bit in CLKSTATUS register */
    CLK_DisablePLL();

    /* Reset CPU */
    SYS_ResetCPU();

}


沙发
dongnanxibei|  楼主 | 2016-11-27 17:30 | 只看该作者
对于单片机一般都会有个晶振接口电路的,有输入接口有输出接口,这个就是利用时钟的输出接口来输出频率,可以给外部电路使用,通过PLL可以获取较高频率的时钟信号。

使用特权

评论回复
板凳
baiyunpiapia| | 2016-11-27 17:37 | 只看该作者
虽然不懂PLL频率输出,但是看楼主这代码写的就感觉很牛X

使用特权

评论回复
地板
heisexingqisi| | 2016-11-27 17:39 | 只看该作者
楼主这代码应该是官方提供的测试代码,都是库函数写的,所以看着很牛X,其实如果学会了,都那样。

使用特权

评论回复
5
734774645| | 2016-11-27 19:20 | 只看该作者

使用内部 PLL 进行频率变换,要学会 PLL 的初始化过程,第一步确定 PLL 使用的时钟源,通过图 7.2.3 可以知道,PLL 既可以
选择内部高速 RC 作为时钟输入源也可以使用外部晶振。


若然选择 PLL作为内核时钟的时钟源,必须设置 CLK_PWRCTL寄存器和CLK_PLLCTL 寄存器,调用库函数 CLK_EnableXtalRC
和 CLK_SetCoreClock,为了以后实验配置更加方便,我们使用 12MHz 外部晶振,不使用带有小数点的 22.1184MHz 内部高速 RC
振荡电路

使用特权

评论回复
6
734774645| | 2016-11-27 19:20 | 只看该作者
/* 使能外部晶振时钟(12MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);
/* 设置内核时钟为 72MHz */
CLK_SetCoreClock(72000000);

为了验证不同频率下(12MHz、24MHz、48MHz、72MHz)的 Led 的闪烁速度,软件函数必须统一,主体代码如下:


使用特权

评论回复
7
734774645| | 2016-11-27 19:21 | 只看该作者
/****************************************
*函数名称:Delay
*输 入:无
*输 出:无
*功 能:软件延时
******************************************/
VOID Delay(VOID)
{
UINT32 i=0x100000;
while(i--);
}
/****************************************
*函数名称:main
*输 入:无
*输 出:无
*功 能:函数主体
******************************************/
int32_t main(void)
{
UINT32 i,j;
UINT32 unPllTbl[4]={12000000,24000000,48000000,72000000};
PROTECT_REG
(
/* 使能外部晶振时钟(12MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);
/* 等待外部晶振时钟(12MHz) */
CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);
)
/* PB8 引脚初始化为推挽输出模式 */
GPIO_SetMode(PB,BIT8,GPIO_MODE_OUTPUT);
while(1)
{
for(i=0; i<4; i++)
{
/* 设置当前内核时钟的频率 */
PROTECT_REG
(
CLK_SetCoreClock(unPllTbl[i]);
)
/* Led 灯闪烁一会儿 */
for(j=0; j<5; j++)
{
PB8=1;Delay();
PB8=0;Delay();
}
}
}
}


使用特权

评论回复
8
734774645| | 2016-11-27 19:22 | 只看该作者
代码分析
a. 由于使用 PLL 倍频后的频率都是整数,需要调用 CLK_EnableXtalRC 函数使能芯片的输入时钟源为外部 12MHz 高速晶振。
b. CLK_SetCoreClock 函数用于设置内核的时钟,传入的参数为频率值,变换的频率为 12MHz、24MHz、48MHz、72MHz。
c. 当切换频率后,观察 Led 灯的闪烁速度。

使用特权

评论回复
9
dongnanxibei|  楼主 | 2016-12-6 18:40 | 只看该作者
原来可以这样,这样外部需要始终的外设就好弄了。

使用特权

评论回复
10
zhuomuniao110| | 2016-12-6 22:17 | 只看该作者
可提供给外部震荡信号,或时钟信号。

使用特权

评论回复
11
dongnanxibei|  楼主 | 2016-12-7 21:56 | 只看该作者
在PLL带宽之内,频率合成器输出端上的相位噪声主要是相位检波器相位噪声;而在PLL带宽之外,输出相位噪声则主要源自VCO相位噪声

使用特权

评论回复
12
gejigeji521| | 2016-12-8 11:29 | 只看该作者
输出的频率可以用于检测系统是不是按配置在运行

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

207

主题

3628

帖子

16

粉丝