时钟和电源管理模块由3部分组成:时钟控制、USB控制、电源控制。
时钟控制部分产生3种时钟信号:CPU用的FCLK,AHB总线用的HCLK,APB总线用的PCLK。
有2个锁相环,一个用于FCLK HCLK PCLK,另一个用于48MHz的USB时钟。
s3c2440的clock & power management模块包含三个部分:
clock control
usb control
power control
现在关注点是clock control
s3c2410有两个pll。MPLL<~~>UPLL
MPLL,M即为main,用来产生三种时钟信号:
Fclk(给CPU核供给时钟信号)
Hclk(为AHB bus peripherals供给时钟信号,AHB为advanced high-performance bus)
Pclk(为APB bus peripherals供给时钟信号,APB为advanced peripherals bus)
AHB bus上的外设有LCD controller(CONT代表controller,控制器)、USB Host CONT、ExtMaster、Nand CONT和nand flash ,boot loader、bus CONT、interrupt CONT、power management、memory CONT(sram/nor/sdram等)。
APB bus上的外设有UART、USB device、SDI/MMC、Watch Dog Timer、bus CONT、spi、iic、iis、gpio、rtc、adc、timer/pwm。
主时钟源来自外部晶振或者外部时钟。复位后,MPLL虽然默认启动,但是如果不向MPLLCON中写入value,那么外部晶振直接作
为系统时钟。
写入MPLLCON寄存器值,然后等待LOCKTIME时间后,新的Fclk开始工作
1、上电几个ms后,晶振输出稳定。Fclk=晶振频率。
2、设置P M S divider control,也就是设置MPLLCON寄存器。
公式Mpll(Fclk)=(m×Fin)/(p×(2^s))【m=MDIV+8, p=PDIV+2,s=SDIV】
3、设置CLKDIVN---分频系数
即Fclk为cpu主频,Hclk由Fclk分频得到,Pclk由Hclk分频得到。
Fclk:Hclk:Pclk=1:4:8,如果主频FLCK是400MHz,那么HLCK是100MHz,PLCK是50MHz
4、CLKDIVN的补充设置
@ FCLK:HCLK=1:2
.macro MMU_SetAsyncBusMode
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(R1_iA | R1_nF)
mcr p15, 0, r0, c1, c0, 0
.endm
@ step3: set asynchronous bus mode
MMU_SetAsyncBusMode
5、第四步软件工作:等待locktime时间,让新的Fclk生效
6、对外设的影响
在这个实验中,主要是有两个需要改变,一个外设是UART,一个外设是SDRAM。
(1)UART,它是接在APB总线上,所以对应的时钟信号为Pclk,现在为50MHz。如果想要设置波特率为115200bps,那么根
据公式UBRDIV0=(int)(PCLK/(bps*16))-1计算,应该为26。如果放到程序中,那么应该注意形式。具体如下:
UBRDIV0 = ((int)(PCLK/16./UART_BAUD_RATE) -1);
(2)SDRAM,主要的影响因素为刷新频率。前面在SDRAM中没有具体分析,现在可以详细说明。使用了两片
HY57V561620CT-H,查看手册其刷新频率为8192 refresh cycles/64ms,所以刷新周期64ms/8192=7.8125us。看寄存器
REFRESH的各个位的设置情况:
·REFEN[23]:开启自动模式,设为1
·TREFMD[22]:设为Auto refresh模式,设为0
·Trp[21:20]:看看RAS precharge Time,查看SDRAM手册,发现-H系列此参数至少为20ns,现在Hclk对应的时钟周期为
10ns,所以至少应该为2个clock。可以设为00
·Tsrc: Semi Row Cycle Time,也就是RAS Cycle Time,至少65ms,所以至少得6.5clock,按照可选值,应该设置为11
·Refresh[10:0]:
公式refresh period = (2^11 - refresh_count +1)/Hclk,由此推导出refresh_count=2^11+1-refresh period*Hclk。
带入数值,计算得出1268=0x04f4,这个数值要用四舍五入,减少误差。
·其余的保留值,均设置为0
由此得出该寄存器的值应该为0x008c04f4。
UPLL是提供给USB时钟(48MHz)的,与MPLL一样,UPLL的产生也是通过UPLLCON寄存器设置分频因子得到,计算公式稍有不同:
UPLL=(m*FIN)/(p*2^s) where m=(MDIV+8), p=(PDIV+2), s="SDIV",同样,可以通过查表得到一个合适的值。
最后值得一提的是,在CLKDIVN的第三位DIVN_UPLL用来设置USB时钟UCLK和UPLL的关系,如果UPLL已经是48Mhz了,那么这一位
应该设置为0,表示1:1的关系,否则是1:2的关系
详见2440datasheet_第七章clock & power management
注意:UPLLCON的值只能是:0x38022,因为UCLK=48MHZ
#define MPLLCON 0x4C000004 //系统主频配置寄存器基地址
#define UPLLCON 0x4C000008 //USB时钟频率配置寄存器基地址
ldr r0, =CLKDIVN //设置分频系数FCLK:HCLK:PCLK = 1:4:8
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON //设置系统主频为405MHz
ldr r1, =0x7F021 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
ldr r0, =UPLLCON //设置USB时钟频率为48MHz
ldr r1, =0x38022 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
- //*************************[ PLL_]*******************************
- //总掉函数
- FIN=12MHZ
- 2440init.s中已经设置了
- FCLK=400MHZ,
- FCLK:HCLK:PCLK=1:4:8,
- UCLK=48MHZ
- 没有特殊需求这里可以不用设置的
- //*************************[ PLL_]*******************************
- void pll_(void)
- {
- U8 key = 14;
- U32 mpll_val = (92<<12)|(1<<4)|(1);
- ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);//FCLK=400MHZ
- ChangeClockDivider(key, 12);//FCLK:HCLK:PCLK=1:4:8
- ChangeUPllValue(56,2,2); //set UCLK=48MHZ
- cal_cpu_bus_clk(); //给FCLK,HCLK,PCLK,UCLK赋值,方便后面调用,可以省略的
- }
- //*************************[ PLL_]*******************************
- //设置MPLL,默认值为FCLK=MPLL,这里FCLK=400MHZ
- //*************************[ PLL_]*******************************
- void ChangeMPllValue(int mdiv,int pdiv,int sdiv)
- {
- rMPLLCON = (mdiv<<12) | (pdiv<<4) | sdiv;
- }
- //*************************[ PLL_]*******************************
- //改变分频比,这里设为:FCLK:HCLK:PCLK=1:4:8
- //*************************[ PLL_]*******************************
- void ChangeClockDivider(int hdivn_val,int pdivn_val)
- {
- int hdivn=2, pdivn=0;
- switch(hdivn_val) {
- case 11: hdivn=0; break;
- case 12: hdivn=1; break;
- case 13:
- case 16: hdivn=3; break;
- case 14:
- case 18: hdivn=2; break;
- }
-
- switch(pdivn_val) {
- case 11: pdivn=0; break;
- case 12: pdivn=1; break;
- }
-
- rCLKDIVN = (hdivn<<1) | pdivn; //101b,FCLK:HCLK:PCLK=1:4:8 CAMDIVN=0为默认
- switch(hdivn_val) {
- case 16: // when 1, HCLK=FCLK/8.
- rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<8);
- break;
- case 18: // when 1, HCLK=FCLK/6.
- rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<9);
- break;
- }
- if(hdivn!=0)
- MMU_SetAsyncBusMode(); //2440init.s中有定义
- else
- MMU_SetFastBusMode();
- }
- //*************************[ PLL_]*******************************
- //设置UPLL=PCLK=48MHZ
- //*************************[ PLL_]*******************************
- void ChangeUPllValue(int mdiv,int pdiv,int sdiv)
- {
- rUPLLCON = (mdiv<<12) | (pdiv<<4) | sdiv;
- }
- //*************************[ PLL_]*******************************
- //为FCLK,HCLK,PCLK,UCLK赋值,方便后面调用
- //*************************[ PLL_]*******************************
- static void cal_cpu_bus_clk(void)
- {
- U32 val;
- U8 m, p, s;
-
- val = rMPLLCON; //FCLK=400MHZ
- m = (val>>12)&0xff; //92
- p = (val>>4)&0x3f; //1
- s = val&3; //1
- //(m+8)*FIN*2 不要超出32位数!
- FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; //400MHZ
-
- val = rCLKDIVN; //FCLK:HCLK:PCLK=1:4:8
- m = (val>>1)&3; //0x2
- p = val&1; //0x1
- val = rCAMDIVN; //0x0
- s = val>>8; //0x0
-
- 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; //100MHZ
- break;
- case 3:
- if(s&1)
- HCLK = FCLK/6;
- else
- HCLK = FCLK/3;
- break;
- }
-
- if(p)
- PCLK = HCLK>>1; //50MHZ
- else
- PCLK = HCLK;
-
- if(s&0x10)
- cpu_freq = HCLK;
- else
- cpu_freq = FCLK; //400MHZ
-
- val = rUPLLCON;
- m = (val>>12)&0xff;
- p = (val>>4)&0x3f;
- s = val&3;
- UPLL = ((m+8)*FIN)/((p+2)*(1<<s)); //48MHZ
- UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;//48MHZ
- }