欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

学习uboot前奏之hardware-clock[s3c2440]

程序员文章站 2024-03-22 20:04:28
...

本节我们来讲下嵌入式系统中时钟的概念,时钟为系统工作提供了基本的时间秩序。作为S3C2440可以直接使用外部晶振,或者直接通过内部电路产生时钟源。

关于时钟有三个名词我们需要理解:
FCLK:用于CPUC核的时钟
HCLK:用于AHB总线上的设备,比如CPU核、存储器控制器、中断控制器、DMA和USB主机模块
PCLK:用于APB总线上的设备 比如WATCHDOG、IIS、SPI等。

对于S3C2440主要有两个PLL:MPLL和UPLL,我们这里主要说明MPLL,MPLL主要用于设置FCLK、HCLK、PCLK。以下图开始来说下MPLL的设置过程:

学习uboot前奏之hardware-clock[s3c2440]

  • 上电伊始的时候,PLL还没有设置,FCLK还是等于外部输入的时钟,相等于上图中OSC,当nRESET信号恢复高电平后,CPU开始执行指令。

  • 当设置PLL后,需要等待一段时间后,MPLL的输出才稳定,这段等待时间成为LockTime,由LOCKTIME设定。

  • MPLLCON:用于设置FCLK与Fin的倍数,对于不同的芯片有不同的计算方式

  • CLKDIVN:用于设置FCLK、HCLK、PCLK。

主要通过设置MPLLCON和CLKDIVN寄存器来设置FCLK、HCLK、PCLK的频率。

下面来说下S3C2440的PWM定时器:

学习uboot前奏之hardware-clock[s3c2440]

从上图可以看出S3C2440共有5个16位定时器,其中定时0、1、2、3有PWM功能,即它们都有一个输出引脚,定时器4没有输出引脚。

定时器部件的时钟为PCLK,首先通过2个预分频器降低频率:定时器0、1共用第一个预分频器,定时器2、3、4共用第二份分频器。预分频器的输出将进入第二级分频器,它们输出5种频率的时钟:2分频、4分频,8分频,16分频或者外部时钟TCLK0\TCLK1,每个分频器的工作时钟可以从这5种频率种选择。具体如何设置和选择请参看2440的技术手册

下面来说下S3C2440的看门狗定时器:

WATCHDOG定时器可以像一般16定时器一样产生周期性中断,也可以用于发出复位信号以重启失常的系统。

学习uboot前奏之hardware-clock[s3c2440]

从上图可以PCLK经过8位预分频后,也是有4种分频可以选择的,都是WTCON寄存器来控制
WTCNT寄存器按照工作频率减1计数,到达0时,可以产生中断信号。第一次使用WATCHDOGD定时器时,需要往WTCNT寄存器中写入初始计数值,以后计数值到达0后时自动从WATDAT寄存器中装入,重新进入下一个周期。

下面以程序重点讲下MPLL的使用

#define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
/*
 * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
 * 有如下计算公式:
 *  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
 *  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
 *  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
 * 对于本开发板,Fin = 12MHz
 * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
 * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
 */
void clock_init(void)
{
    // LOCKTIME = 0x00ffffff;   // 使用默认值即可
    CLKDIVN  = 0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm__(
    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */ 
    "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */
    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */
    );

    /* 判断是S3C2410还是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
    }
    else
    {
        MPLLCON = S3C2440_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
    }       
}

设置完成时钟以后,就可以用新的HCLK来初始化SDRAM,初始化定时器了。