首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM时钟

ARM时钟

时钟作用:系统中的设备需要时间进行同步。
时钟的产生:PLL(锁相环),利用外部晶体加上一些电路,对晶体产生的特定频率进行分频或加倍。晶振相对来说结构简单,但是受频率受到晶体制约,得到很高的频率的晶振价格高,用锁相环难度价格低些。
外部晶振作为时钟源,S3c2440有两个锁相环:MPLL和UPLL,UPLL用于USB设备。MPLL用于CPU及其 外围器件,通过MPLL会产生三个时钟频率:FCLK,HCLK,PCLK,FCLK最高533MHz用于CPU核(CPU频率),HCLK用于高速总线,PCLK用于低俗的外围设备。

一旦上电之后,CPU频率等于外部晶振频率12Mz,CPU工作后配置PLL,在A点完成配置,完成后CPU频率降成0,这段时间为lock time,在这段时间CPU未工作,lock time结束后CPU频率提高,,因为配置PLL时,提高输出频率400Mz,这就是时钟启动流程。
PLL配置涉及3个寄存器,LOCKTIME,MOLLCON,CLKDIVN。
1:LOCKTIME:确定启动时LOCKTIME时间。

2:MPLLCON:用于设置FCLK和FIN(输入时钟频率晶振)。计算关系:
MPLL(FCLK) = (2 * m * Fin) / (p*2^s) 其中m=MDIV+8,p=PDIV+2,s=SDIV。
通过MPLLCON的设置就可以设置MDIV、PDIV、SDIV。
3:CLKDIVN:用于设置FCLK,PCLK,HCLK三这个关系。
设计定时器:s3c2440有5个16位寄存器,其中定时器1,2,3有PWM功能,都有一个输出引脚,控制引脚上电压的变化,定时器4没有输出引脚,定时器的时钟源为PCLK,经过两次分频。
定时器初始化,让它在一定时间后超时,超时后产生中断,就可以执行中断处理函数。
1:设置定时器时钟频率,比如为50,表示每一秒把初始值减50,
2:设置定时器计数值。比如为100,频率50,则在2s后超时。
3:设置中断处理函数。
定时器输出时钟频率=PCLK/{prescaler + 1}/{divider value}
prescaler :TCFG0中设置。divider value:TCFG1设置。
计数值初始化:TCMPB0  TCNTB0 存放初始值,启动定时器后,初始值导入TCMP0,TCNT0,每次时钟频率TCNT0减一,直到与TCMP0相等,产生中断,有Timer n auto reload on打开可以再一次重新计数,TCON启动寄存器。

定时器程序(每隔0.5s闪烁一次):
[cpp] view plaincopy

void Timer0_init(void);  
static void __irq IRQ_Timer0_Handle(void);  
void Set_Clk(void);  
static void cal_cpu_bus_clk(void);  
void Led1_init(void);  
void Led1_run(void);  
void delay(int times) {  
    int i,j;  
    for(i=0;i<times;i++)  
       for(j=0;j<400;j++);  
}  
void Main(void) {     
     
  Set_Clk();  
  //系统时钟设置,通过几个寄存器选定CPU、外部总线频率,FCLK,PCLK,HCLK  
    MMU_Init();  
    Led1_init();  
    Timer0_init();  
    while(1);     
}     
      
void Timer0_init(void) {  
   //Timer 0 init,设置两个寄存器  
  rTCFG0 = 49;              //pclk/(49+1),第一次分频  
  rTCFG1 = 0x03;            //16分频=62500HZ 第二次分频  
  rTCNTB0 = 62500/2;          //设置计数值,TCNTB0[15:0]=计数值   
  rTCMPB0 = 0;  
  rTCON |=(1<<1);           //将计数值装入TCNTB0、TCMPB0  
   
  rTCON =0x09;  
   
  rPRIORITY = 0x00000000;     // 默认优先级  
  rINTMOD = 0x00000000;       // 默认优先级  
   
  ClearPending(BIT_TIMER0);  
  pISR_TIMER0 = (U32)IRQ_Timer0_Handle;  
  EnableIrq(BIT_TIMER0);   
}  
static void __irq IRQ_Timer0_Handle(void) {  
      
    Led1_run();  
    ClearPending(BIT_TIMER0);  
      
}  
  
void Set_Clk(void) {  
    int i;  
    U8 key;  
    U32 mpll_val = 0 ;  
    i = 2 ;              //don't use 100M!  
                         //boot_params.cpu_clk.val = 3;  
    switch ( i ) {  
    case 0: //200  
        key = 12;  
        mpll_val = (92<<12)|(4<<4)|(1);  
        break;  
    case 1: //300  
        key = 13;  
        mpll_val = (67<<12)|(1<<4)|(1);  
        break;  
    case 2: //400  
        key = 14;  
        mpll_val = (92<<12)|(1<<4)|(1);  
        break;  
    case 3: //440!!!  
        key = 14;  
        mpll_val = (102<<12)|(1<<4)|(1);  
        break;  
    default:  
        key = 14;  
        mpll_val = (92<<12)|(1<<4)|(1);  
        break;  
    }  
      
    //init FCLK=400M, so change MPLL first  
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON  
    ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit  
    cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M  
}  
  
static void cal_cpu_bus_clk(void) {  
    static U32 cpu_freq;  
    static U32 UPLL;  
      
    U32 val;  
    U8 m, p, s;  
      
    val = rMPLLCON;  
    m = (val>>12)&0xff;  
    p = (val>>4)&0x3f;  
    s = val&3;  
  
    //(m+8)*FIN*2 不要超出32位数!  
    FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000  
      
    val = rCLKDIVN;  
    m = (val>>1)&3;  
    p = val&1;   
    val = rCAMDIVN;  
    s = val>>8;  
      
    switch (m) {  
    case 0:  
        HCLK = FCLK;  
        break;  
    case 1:  
        HCLK = FCLK>>1;  
        break;  
    case 2:  
        if(s&2)  
            HCLK = FCLK>>3;  
        else  
            HCLK = FCLK>>2;  
        break;  
    case 3:  
        if(s&1)  
            HCLK = FCLK/6;  
        else  
            HCLK = FCLK/3;  
        break;  
    }  
    if(p)  
        PCLK = HCLK>>1;  
    else  
        PCLK = HCLK;  
      
    if(s&0x10)  
        cpu_freq = HCLK;  
    else  
        cpu_freq = FCLK;  
         
    val = rUPLLCON;  
    m = (val>>12)&0xff;  
    p = (val>>4)&0x3f;  
    s = val&3;  
    UPLL = ((m+8)*FIN)/((p+2)*(1<<s));  
    UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;  
}  
  
void Led1_init(void) {  
    rGPBCON &= ~(0x3<<10);  
    rGPBCON |=  (0x1<<10);  
}  
  
void Led1_run(void) {  
    //rGPBDAT = rGPBDAT^(0x1<<5);  
     
    if(rGPBDAT &(1<<5))  
       rGPBDAT &=~(1<<5);  
    else  
       rGPBDAT |=(1<<5);  
}
继承事业,薪火相传
返回列表