zoukankan      html  css  js  c++  java
  • [smart210] 通过PLL设置各时钟频率的方法以及代码注释

    平台:smart210(tiny210v2)

    CPU:S5PV210

    目标:

    设置APLL (提供MSYS domain 与DSYS domain 下各时钟的来源,最高1Ghz)

    设置MPLL(提供MSYS domain 与DSYS domain 下各时钟的来源,最高2Ghz)

    设置EPLL(Audio相关时钟)

    设置VPLL(Video相关时钟,54Mhz)

    知识储备:

    1.   MSYS主要为CPU,DRAM控制器,3D,IRAM,IROM,中断控制器等提供时钟

          DSYS主要为显示相关部件FIMC,FIMD,JPEG,Multimedia IPs提供时钟

          PSYS为外设I2S,SPI,I2C,UART等提供时钟

    2.  官方文档有时钟domain的【时钟继承图】(自造词。。)

           从图上我们能发现,MSYS domain包含有ARMCLK、HCLK_MSYS、PCLK_MSYS、HCLK_IMEM、SCLK_DMC0 这几个时钟信号,追本溯源,这些时钟信号主要都源于APLL或者MPLL经过各种分频倍频环节得到的,而其他的CLOCK domain下的子时钟也如此,换句话说,只要先把外置时钟源FIN=24Mhz转换成我们需要的APLL,MPLL这两个主要的PLL时钟,其余大部分的时钟我们就能轻松设置了。

    3    官方还给出了直观的各子时钟的设置来源与推荐值:

    4   同样的,官方P364给出了从FIN到设置最终子时钟的整个流程:

    ①打开APLL:APLL_CON0[31]=1;这里能看到bit31是使能控制端

    ②等待PLL锁定

    ③在锁定时钟稳定后,令APLL输出:CLK_SRC0[0]=1;这里能看到bit0(APLL_SEL)控制MUX_APLL的时钟输出,同时bit16(MUX_MSYS_SEL)控制了MUX_MSYS的输出

    ④改变分频值,设置PMS,其实就是PDIV,MDIV,SDIV的值,相关寄存器仍是APLL_CON0,参考步骤①的附图,而设置的PMS有什么用呢?我们最终要得到的是APLL的时钟,这个时钟通过FIN与PMS三个分频系数计算得到,使用的是下面这条公式  FOUT=MDIV*FIN/(PDIV*2^(SDIV-1))  。下面附图给出了公式以及PMS的取值范围:

    ⑤设置各CLOCK domain下的子时钟的分频比,从而确定了最终的MSYS domain、PSYS domain与DSYS domain各子时钟的频率,相关寄存器CLK_DIV0、CLK_DIV1、CLK_DIV2,这里贴出主要的CLK_DIV0

    5.好了,现在整理一下那5个步骤,其实顺序可以打乱,只要设置得当就行,这5个步骤中,有几个关键点要注意的:

    ①初始输入频率FIN为24Mhz,通过设置APLL_CON来控制PLL使能,以及设置PMS的值,设置完这些,我们基本上得到了APLL的FOUT,一般都是先想好需要多快的FOUT,再去设置PMS的值的。

    ②获取到FOUT APLL之后,通过设置CLK_SRC0的相关位把FOUT APLL作为MUX APLL的输出(从最上面那个【时钟继承图】上可以看出MUX APLL可以选择FIN或者FOUT APLL作为输出,输出的时钟名为SCLK_APLL  )同时,我们还要通过设置CLK_SRC0的相关位如MUX_MSYS_SEL(【时钟继承图】上的又一个多路复用器)将SCLK_APLL作为该MUX的输出,输出的时钟名为MOUT_MSYS

    ③最后就是通过设置CLK_DIV0来设置各子时钟的分频比了,可以发现,只要有了MOUT_MSYS,MSYS domain里面的子时钟都能通过设置这个寄存器而得到!

    6.下面再不厌其烦地给出直观的讲解图

    终于到了代码阶段了,有了上面的知识储备,程序的事也是手到擒来是吧!

    1.首先start.s关好看门狗,设置堆栈后,进入clock_init

    .global _start
    _start:
        ldr    r0, =0xE2700000            
        mov    r1, #0
        str    r1, [r0]
        ldr    sp, =0x40000000                        
        bl clock_init                        
        bl main                            
    halt:
        b halt

    2.clock.c中,有写好的clock_init函数

    // 时钟相关寄存器
    #define APLL_LOCK             ( *((volatile unsigned long *)0xE0100000) )        
    #define MPLL_LOCK             ( *((volatile unsigned long *)0xE0100008) )
    
    #define APLL_CON0             ( *((volatile unsigned long *)0xE0100100) )
    #define APLL_CON1             ( *((volatile unsigned long *)0xE0100104) )
    #define MPLL_CON             ( *((volatile unsigned long *)0xE0100108) )
    
    #define CLK_SRC0             ( *((volatile unsigned long *)0xE0100200) )
    #define CLK_SRC1             ( *((volatile unsigned long *)0xE0100204) )
    #define CLK_SRC2             ( *((volatile unsigned long *)0xE0100208) )
    #define CLK_SRC3             ( *((volatile unsigned long *)0xE010020c) )
    #define CLK_SRC4             ( *((volatile unsigned long *)0xE0100210) )
    #define CLK_SRC5             ( *((volatile unsigned long *)0xE0100214) )
    #define CLK_SRC6             ( *((volatile unsigned long *)0xE0100218) )
    #define CLK_SRC_MASK0         ( *((volatile unsigned long *)0xE0100280) )
    #define CLK_SRC_MASK1         ( *((volatile unsigned long *)0xE0100284) )
    
    #define CLK_DIV0             ( *((volatile unsigned long *)0xE0100300) )
    #define CLK_DIV1             ( *((volatile unsigned long *)0xE0100304) )
    #define CLK_DIV2             ( *((volatile unsigned long *)0xE0100308) )
    #define CLK_DIV3             ( *((volatile unsigned long *)0xE010030c) )
    #define CLK_DIV4             ( *((volatile unsigned long *)0xE0100310) )
    #define CLK_DIV5             ( *((volatile unsigned long *)0xE0100314) )
    #define CLK_DIV6             ( *((volatile unsigned long *)0xE0100318) )
    #define CLK_DIV7             ( *((volatile unsigned long *)0xE010031c) )
    
    #define CLK_DIV0_MASK        0x7fffffff
    
    #define APLL_MDIV           0x7d
    #define APLL_PDIV           0x3
    #define APLL_SDIV               0x1
    #define MPLL_MDIV            0x29b
    #define MPLL_PDIV            0xc
    #define MPLL_SDIV            0x1
    
    #define set_pll(mdiv, pdiv, sdiv)    (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
    #define APLL_VAL        set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
    #define MPLL_VAL        set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)
    
    //#define PLL_OFF        //屏蔽此句才能顺利启用PLL设置
    
    void clock_init()
    {
        // 1 设置各种时钟开关,暂时不使用PLL
        CLK_SRC0 = 0x0;    //根据手册显示,0代表使用FINPLL即默认外置时钟源(此时FIN=24Mhz)
        //CLK_SRC0寄存器中控制位:[0]->APLL_SEL,[4]->MPLL_SEL,[8]->EPLL_SEL,[12]->VPLL_SEL
    #ifndef PLL_OFF
    
        // 2 设置锁定时间,使用默认值即可
        // 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间             
        APLL_LOCK = 0x0000FFFF;              
        MPLL_LOCK = 0x0000FFFF;
                            
        // 3 设置分频
        CLK_DIV0 = 0x14131440;
    
    
    
    
        //以APLL为例,这里CLK_DIV0设置了APLL_RATIO的值为0,则根据公式 ARMCLK=MOUT_MSYS/(APLL_RATIO + 1)=MOUT_MSYS
    
        // 4 设置PLL
        //解析为APLL_CON0=APLL_VAL=(1<<31|0x7d<<16|0x3<<8|0x1)意思就是APLL_CON0寄存器[31]位使能,允许PLL控制
        //[25:16]位为MDIV(倍频因子)值,[13:8]为PDIV(分频因子)值,[2:0]为SDIV值,FOUT计算公式如下
        // FOUT= MDIV * FIN / (PDIV*2^(SDIV-1)) = 0x7d*24/(0x3*2^(1-1))=1000 MHz
        //上式采用MDIV=0x7d(125),PDIV=0x3(3),SDIV=0x1(1)
        APLL_CON0 = APLL_VAL;
        // FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
        MPLL_CON  = MPLL_VAL;
                        
        // 5 设置各种时钟开关,使用PLL
        CLK_SRC0 = 0x10001111;
    #endif
    }
  • 相关阅读:
    CSP 命令行选项(201403-3)
    ElasticSearch7.10的查询数据-简单查询
    ElasticSearch 种映射参数详解-理论学习02
    Elasticsearch7.10 -理论学习01
    ElasticSearch7.10索引
    ElasticSearch7.10的分词器
    ElasticSearch-7.10安装-2
    ElasticSearch第一天
    Idea的注释配置
    深圳第一站被骗消费3960元
  • 原文地址:https://www.cnblogs.com/tinyfeather/p/3260471.html
Copyright © 2011-2022 走看看