JZ2440开发板:修改ARM芯片时钟(学习笔记)

  想要修改ARM芯片的时钟,须要去查询芯片手册和原理图,获取相关的信息(见下方图片)html

首先来看时钟的结构图linux


 

根据结构图能够看出,时钟源有两种选择:1. XTIpll和XTOpll所链接的晶振 异步

                   2. EXTCLK引脚外接一个时钟源函数


 

OM[3:2]用来选择到底使用哪一个时钟源ui


 

再查看原理图,能够发现:OM3和OM2硬件上都是接GND,因此能够知道:采用12MHz晶振做为时钟源spa


 

阅读芯片手册,还能够查询到其余寄存器的相关信息,见下图:.net

 

JZ2440内部使用三种时钟:3d

            FCLK: 用于ARM920T芯片,即CPUunix

            HCLK:经过AHB总线,提供给ARM920T芯片、内存控制器,中断控制器,LCD控制器等等code

            PCLK:   经过APB总线,提供给一些外围设备使用,如WDT,IIS,I2C等等


 

FCLK经过HDIVN分频获得HCLK,经过PDIVN分频获得PCLK,这里设置FCLK:HCLK:PCLK=400MHz : 100MHz : 50Hz

   一、修改MPLLCON寄存器中MDIV ,PDIV ,SDIV的值为92 ,1 ,1,能够获得FCLK为400MHz

   二、修改CLKDIVN中,HDIVN和PDIVN分别为0b10和1,使得HCLK=FCLK/4 , PCLK=HCLK/2

 


 

阅读芯片手册中,晶振做为时钟源的时序图,能够发现,当配置PLL时,会有一个LOCKTIME时间,用来等待输出的FCLK频率稳定


在这里,不对LOCKTIME进行修改,仍然使用它的默认值0xFFFFFFFF


继续阅读芯片手册,有一个备注信息:

    当HDIVN不是0且CPU工做于快速总线模式的时候,CPU会采用HCLK做为它的时钟频率,

    所以若是想让HDIVN修改后,CPU采用FCLK,必须添加下方代码,让CPU工做于异步模式 

      mrc p15,0,r0,c1,c0,0
      orr r0,r0,#R1_nF:OR:R1_iA                      
      mcr p15,0,r0,c1,c0,0

【代码  #R1_nF:OR:R1_iA 的意思】———— 点我

对时钟修改的分析就大体差很少了,接下来写汇编文件实现要求

.text .global _start _start: /* 关闭看门狗,若是不关闭,系统会自动重启 */ ldr r0,=0x53000000 ldr r1,=0 str r1,[r0] /* 修改时钟,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
    
    /* 设置配置MPLL时的LOCKTIME时间为默认值 */ ldr r0,=0x4c000000 ldr r1,=0xFFFFFFFF str r1,[r0] /* 设置FCLK:HCLK:PCLK=8:2:1 */ ldr r0,=0x4c000014 ldr r1,=0x5 str r1,[r0] /* 设置CPU工做于异步模式 ** 若是不做此设置,当HDIVN不是0时,CPU会采用HCLK的频率而不是采用FCLK的频率 */ mrc p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000    // #R1_nF:OR:R1_iA等价于#0xc0000000
    mcr p15,0,r0,c1,c0,0

    /* 设置MPLL的PMS,使得FCLK=400MHz ** m = MDIV+8 = 92+8=100 ** p = PDIV+2 = 1+2 = 3 ** s = SDIV = 1 ** FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400MHz */ ldr r0,=0x4C000004 ldr r1,=(92<<12)|(1<<4)|(1<<0) str r1,[r0] /* 设置好PLL以后,就会锁定lock time,直到PLL稳定输出 */
    /* cpu会工做于新的频率FCLK /* 判断是nor启动仍是nand启动 ** 先把0地址原来的值读取出来,保存到r0寄存器中 ** 再把0写入0地址对应的内存单元,以后读取0地址内存单元的值 ** 若是读取出来的值与原来的值不一致,说明是nor启动 ** 若是读取出来的值与原来的值一致,说明是nand启动,此时须要修改栈的地址 */ mov r1,#0 ldr r0,[r1] // 读取原来的值,备份一下
    str r1,[r1]  // 把0写入0地址
    ldr r2,[r1]  // 读取0地址新的值
    cmp r2,r0    // 若是r0和r2的值同样,说明是nand启动,此时修改sp的值
    
    /* 设置栈:sp */ ldr sp,=0x40000000+4096 // 先默认nor启动//     moveq sp,#4096    // 若是r2=r1,把4096传给sp,改成nand启动
    streq r0,[r1]    // 若是r2=r1,恢复0地址原来的值
    bl main          // 跳转到main函数
halt: b halt // 不停的跳转到halt,至关于死循环,方便观察效果

另外再附上JZ2440开发板3盏LED灯循环点亮的C程序(和按键点亮LED灯须要知道的知识差很少,这里再也不做分析),用来观察时钟修改后的效果

#include "s3c2440_soc.h"
void delay(volatile int d)                           //延时函数 
{ while(d--); } int main(void) { /*设置GPFCON的GPF4/5/6,让它们变成输出引脚*/ GPFCON &=~((3<<8)|(3<<10)|(3<<12));                        //先让GPFCON的GPF4/5/6清零
    GPFCON |=((1<<8)|(1<<10)|(1<<12));                        //配置好GPFCON的GPF4/5/6,让它们变成输出引脚

    /*循环点亮3盏灯*/
    int val=0,tmp;                                  //val取值范围0b000~0b111,恰好三盏灯
    while(1) { tmp=~val;                                    //由于val为0的时候,灯会由亮到灭,因此这里须要取反,才能让灯从灭到亮
        tmp &=7;                                     //只须要三位的值就行了
        GPFDAT &=~(7<<4);                            //GPFDAT寄存器先清零,由于是4,5,6位,因此这里7左移4位就能够
        GPFDAT |=(tmp<<4); delay(100000);                            //加上一个延时,否则灯切换太快了,看不出来
        val++; if(val==8) { val=0; } } return 0; }

上传到 linux,编译获得 led.bin文件,烧写到开发板以后,发现LED灯切换得比之前快多了,由于CPU是400MHz了,ARM芯片时钟修改为功。

相关文章
相关标签/搜索