`
jsntghf
  • 浏览: 2532485 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

S5PV210之时钟系统

阅读更多

本文使用的开发板是九鼎创展的X210 iNand版本。

 

一、S5PV210的时钟系统简介

 

1、时钟域:MSYS、DSYS、PSYS

 

 

因为S5PV210的时钟体系比较复杂,内部外设模块太多,因此把整个内部的时钟划分为三大块,叫做三个时钟域,分别是MSYS、DSYS、PSYS。

因为S5PV210内部的这些模块彼此工作的时钟速率差异太大,因此把高速的放在一起,相对低速的放在一起。

 

(1)MSYS:CPU(Cortex-A8内核)、DRAM控制器(DMC0和DMC1)、IRAM & IROM等

(2)DSYS:和视频显示、编解码等有关的模块

(3)PSYS:和内部的各种外设时钟有关,例如:串口、SD接口、I2C、AC97、USB等

 

2、时钟来源:晶振 + 时钟发生器 + PLL + 分频电路

 

S5PV210外部有四个晶振接口,设计板子硬件时可以根据需要来决定在哪里接晶振。接了晶振之后,上电相应的模块就能产生振荡,产生原始时钟。原始时钟再经过一系列的筛选开关进入相应的PLL电路生成倍频后的高频时钟。高频时钟再经过分频到达芯片内部的各个模块上。

 

有些模块(串口)内部还有进一步的分频器进行再次分频使用。

 

3、PLL:APLL、MPLL、EPLL、VPLL

 

 

(1)APLL:MSYS域

(2)MPLL:DSYS域

(3)EPLL:PSYS域

(4)VPLL:视频相关模块 

 

4、时钟域和时钟的关系

 

 

(1)MSYS域

       ARMCLK:给CPU内核工作的时钟,也就是所谓的主频

HCLK_MSYS:MSYS域的高频时钟,给DMC0和DMC1使用

PCLK_MSYS:MSYS域的低频时钟

HCLK_IMEM:给IRAM和IROM(合称IMEM)使用

 

(2)DSYS域

HCLK_DSYS:DSYS域的高频时钟

PCLK_DSYS:DSYS域的低频时钟

 

(3)PSYS域

HCLK_PSYS:PSYS域的高频时钟

PCLK_PSYS:PSYS域的低频时钟

SCLK_ONENAND

 

S5PV210内部的各个外设都是接在内部AMBA总线上面的,AMBA总线有一条高频分支叫AHB,有一条低频分支叫APB。上面的各个域都有各自对应的HCLK_XXXX和PCLK_XXXX,其中HCLK_XXXX就是XXXX域中AHB总线的工作频率,PCLK_XXXX就是XXXX域中APB总线的工作频率。

 

SoC内部的各个外设其实是挂在总线上工作的,也就是说这个外设的时钟来自于它挂在的总线。例如串口UART挂在PSYS域下的APB总线上,因此串口的时钟来源是PCLK_PSYS。

 

我们可以通过记住和分析上面的这些时钟域和总线的数值,来确定各个外设的具体时钟频率。

 

5、各时钟的典型值(IROM中设置的值)

 

 

(1)当X210刚上电时,默认是外部晶振 + 内部时钟发生器产生的24MHz频率的时钟直接给ARMCLK的,这时系统的主频就是24MHz。

(2)IROM代码执行时,第六步中初始化了时钟系统,这时给了系统一个默认推荐的运行频率,这个时钟频率是三星推荐的S5PV210工作性能和稳定性最佳的频率。

 

二、S5PV210的时钟体系框图

 

 

(1)两张图之间是渐进的关系。第一张图从左到右依次完成了:原始时钟的生成-->PLL倍频得到高频时钟-->初次分频得到各总线时钟,第二张图是从各个中间时钟(第一张图中某个步骤生成的时钟)到各外设自己使用的时钟(实际就是个别外设自己再额外分频的设置)。

(2)第一张图是理解整个时钟体系的关键,第二张图是进一步分析各外设时钟来源的关键。

(3)要看懂时钟体系框图,两个符号很重要:一个是MUX开关,另一个是DIV分频器。

         1)MUX开关就是一个或门,实际对应某个寄存器的某几个bit位的设置,设置值决定了哪条通道是通                    的。分析这个可以知道右边的时钟是从左边哪条路过来的,从而知道右边的时钟是多少。

         2)DIV分频器是一个硬件设备,可以对左边的频率进行分频,分频后的低频时钟输出到右边。分频器在                编程时实际对应某个寄存器中的某几个bit位。我们可以通过设置这个寄存器的对应bit位来设置分频                器的分频系数。

(4)寄存器中的Clock Source Control Register就是用来设置MUX开关的,Clock Divider Control Register就是用来设置DIV分频器的分频系数的。

 

三、时钟设置的关键性寄存器

 

(1)xPLL_LOCK

         主要控制PLL的锁定周期

(2)xPLL_CON、xPLL_CON0、xPLL_CON1

         主要用来打开 / 关闭PLL电路,设置PLL的倍频参数,查看PLL的锁定状态等

(3)CLK_SRCn(n取值为0~6)

         主要用来设置时钟来源,对应时钟体系框图中的MUX开关

(4)CLK_SRC_MASKn

         主要用来决定MUX开关n选1后是否能继续通过

(5)CLK_DIVn

         主要用来设置各模块的分频器参数

(6)CLK_GATE_n

         类似于CLK_SRC_MASKn,对时钟进行开关控制

(7)CLK_DIV_STATn、CLK_MUX_STATn

         主要用来查看DIV和MUX的状态是否已经完成还是在进行中

 

其中最重要的寄存器有三类:CON、SRC、DIV。CON决定PLL倍频到多少,SRC决定MUX走哪一条路,DIV决定分频多少。

 

四、时钟设置的步骤

 

1、步骤分析

 

(1)先选择不使用PLL。让外部的24MHz原始时钟直接过去,绕过APLL那条路

(2)设置锁定时间。

(3)设置分频系数。决定由PLL倍频出来的最高时钟如何分频得到各个分时钟

(4)设置PLL。主要是设置PLL的倍频系数,决定由24MHz的原始时钟可以得到多大的输出频率

(5)打开PLL。前四步已经设置好了所有的开关和分频系数,本步骤打开PLL后,PLL开始工作,锁定频率后输出,然后经过分频得到各个频率。

 

2、CLK_SRC寄存器的设置分析

 

 

CLK_SRC寄存器主要是用来设置MUX开关的,可以先将该寄存器设置为全0,主要是bit0和bit4要设置为0,表示APLL和MPLL暂时都不启用。

 

3、xPLL_LOCK寄存器的设置分析

 

 

xPLL_LOCK寄存器主要是用来设置PLL的锁定周期的,官方的推荐值为0x0FFF。

 

4、CLK_DIV寄存器的设置分析

 

 

我们设置的值是0x14131440,含义分析如下:

 

PCLK_PSYS = HCLK_PSYS / 2

HCLK_PSYS = MOUT_PSYS / 5

PCLK_DSYS = HCLK_DSYS / 2

HCLK_DSYS = MOUT_DSYS / 4

PCLK_MSYS = HCLK_MSYS / 2

HCLK_MSYS = ARMCLK / 5

SCLKA2M = SCLKAPLL / 5

ARMCLK = MOUT_MSYS / 1

 

5、APLL和MPLL设置的关键

 

 

APLL和MPLL设置的关键都是P、M、S这三个值,我们设置的值都来自于官方数据手册的推荐值。

 

五、代码实现

 

1、Makefile

 

led.bin: start.o led.o clock.o
	arm-linux-ld -Ttext 0x0 -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 led.bin 210.bin
	
%.o : %.S
	arm-linux-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-linux-gcc -o $@ $< -c -nostdlib

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f

 

2、start.S

 

#define SVC_STACK	0xD0037D80

.global _start					
_start:
	// 初始化时钟
	bl clock_init
	
	ldr sp, =SVC_STACK

	bl led_blink					
	
	b .

 

3、led.c

 

#define GPJ0CON	 0xE0200240
#define GPJ0DAT	 0xE0200244

#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)

void delay(void);

void led_blink(void) {
	rGPJ0CON = 0x11111111;
	
	while(1) {
		// led亮
		rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
		// 延时
		delay();
		// led灭
		rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
		// 延时
		delay();
	}
}

void delay(void) {
	volatile unsigned int i = 900000;		
	while (i--);							
}

 

4、clock.S

 

// 时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE		0xE0100000	

// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#define APLL_LOCK_OFFSET		0x00		
#define MPLL_LOCK_OFFSET		0x08

#define APLL_CON0_OFFSET		0x100
#define APLL_CON1_OFFSET		0x104
#define MPLL_CON_OFFSET			0x108

#define CLK_SRC0_OFFSET			0x200
#define CLK_SRC1_OFFSET			0x204
#define CLK_SRC2_OFFSET			0x208
#define CLK_SRC3_OFFSET			0x20c
#define CLK_SRC4_OFFSET			0x210
#define CLK_SRC5_OFFSET			0x214
#define CLK_SRC6_OFFSET			0x218
#define CLK_SRC_MASK0_OFFSET	0x280
#define CLK_SRC_MASK1_OFFSET	0x284

#define CLK_DIV0_OFFSET			0x300
#define CLK_DIV1_OFFSET			0x304
#define CLK_DIV2_OFFSET			0x308
#define CLK_DIV3_OFFSET			0x30c
#define CLK_DIV4_OFFSET			0x310
#define CLK_DIV5_OFFSET			0x314
#define CLK_DIV6_OFFSET			0x318
#define CLK_DIV7_OFFSET			0x31c

#define CLK_DIV0_MASK			0x7fffffff

#define APLL_MDIV      	 		0x7d		// 125
#define APLL_PDIV       		0x3         // 3
#define APLL_SDIV       		0x1         // 1

#define MPLL_MDIV				0x29b		// 667
#define MPLL_PDIV				0xc         // 12
#define MPLL_SDIV				0x1         // 1

#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)


.global clock_init
clock_init:
	ldr	r0, =ELFIN_CLOCK_POWER_BASE
	
	// 设置各种时钟开关,暂时不使用PLL
	ldr	r1, =0x0

	str	r1, [r0, #CLK_SRC0_OFFSET]				

	// 设置锁定时间
	ldr	r1,	=0x0000FFFF					
	str	r1,	[r0, #APLL_LOCK_OFFSET]				
	str r1, [r0, #MPLL_LOCK_OFFSET]	 				

	// 设置分频
	// 清bit[0~31]
	ldr r1, [r0, #CLK_DIV0_OFFSET]					
	ldr	r2, =CLK_DIV0_MASK					
	bic	r1, r1, r2
	ldr	r2, =0x14131440						
	orr	r1, r1, r2
	str	r1, [r0, #CLK_DIV0_OFFSET]

	// 设置PLL
	// FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1)) = 0x7d * 24 / (0x3 * 2^(1-1)) = 1000MHz
	ldr	r1, =APLL_VAL						
	str	r1, [r0, #APLL_CON0_OFFSET]
	// FOUT = MDIV * FIN / (PDIV * 2^SDIV) = 0x29b * 24 / (0xc * 2^1) = 667MHz
	ldr	r1, =MPLL_VAL						
	str	r1, [r0, #MPLL_CON_OFFSET]

	// 设置各种时钟开关,使用PLL
	ldr	r1, [r0, #CLK_SRC0_OFFSET]
	ldr	r2, =0x10001111
	orr	r1, r1, r2
	str	r1, [r0, #CLK_SRC0_OFFSET]

	mov	pc, lr

 

以下为时钟初始化的C语言实现,只需将时钟初始化的相关代码(clock.S)改为C语言实现(clock.c)即可。

 

// 时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE      0xE0100000  
 
// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#define APLL_LOCK_OFFSET        0x00        
#define MPLL_LOCK_OFFSET        0x08
 
#define APLL_CON0_OFFSET        0x100
#define APLL_CON1_OFFSET        0x104
#define MPLL_CON_OFFSET         0x108
 
#define CLK_SRC0_OFFSET         0x200
#define CLK_SRC1_OFFSET         0x204
#define CLK_SRC2_OFFSET         0x208
#define CLK_SRC3_OFFSET         0x20c
#define CLK_SRC4_OFFSET         0x210
#define CLK_SRC5_OFFSET         0x214
#define CLK_SRC6_OFFSET         0x218
#define CLK_SRC_MASK0_OFFSET    0x280
#define CLK_SRC_MASK1_OFFSET    0x284
 
#define CLK_DIV0_OFFSET         0x300
#define CLK_DIV1_OFFSET         0x304
#define CLK_DIV2_OFFSET         0x308
#define CLK_DIV3_OFFSET         0x30c
#define CLK_DIV4_OFFSET         0x310
#define CLK_DIV5_OFFSET         0x314
#define CLK_DIV6_OFFSET         0x318
#define CLK_DIV7_OFFSET         0x31c
 
#define CLK_DIV0_MASK           0x7fffffff
 
#define APLL_MDIV               0x7d        // 125
#define APLL_PDIV               0x3         // 3
#define APLL_SDIV               0x1         // 1
 
#define MPLL_MDIV               0x29b       // 667
#define MPLL_PDIV               0xc         // 12
#define MPLL_SDIV               0x1         // 1
 
#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 REG_CLK_SRC0    (ELFIN_CLOCK_POWER_BASE + CLK_SRC0_OFFSET)
#define REG_APLL_LOCK   (ELFIN_CLOCK_POWER_BASE + APLL_LOCK_OFFSET)
#define REG_MPLL_LOCK   (ELFIN_CLOCK_POWER_BASE + MPLL_LOCK_OFFSET)
#define REG_CLK_DIV0    (ELFIN_CLOCK_POWER_BASE + CLK_DIV0_OFFSET)
#define REG_APLL_CON0   (ELFIN_CLOCK_POWER_BASE + APLL_CON0_OFFSET)
#define REG_MPLL_CON    (ELFIN_CLOCK_POWER_BASE + MPLL_CON_OFFSET)
 
#define rREG_CLK_SRC0   (*(volatile unsigned int *)REG_CLK_SRC0)
#define rREG_APLL_LOCK  (*(volatile unsigned int *)REG_APLL_LOCK)
#define rREG_MPLL_LOCK  (*(volatile unsigned int *)REG_MPLL_LOCK)
#define rREG_CLK_DIV0   (*(volatile unsigned int *)REG_CLK_DIV0)
#define rREG_APLL_CON0  (*(volatile unsigned int *)REG_APLL_CON0)
#define rREG_MPLL_CON   (*(volatile unsigned int *)REG_MPLL_CON)
 
void clock_init(void) {
    // 设置各种时钟开关,暂时不使用PLL
    rREG_CLK_SRC0 = 0x0;
     
    // 设置锁定时间
    rREG_APLL_LOCK = 0x0000ffff;
    rREG_MPLL_LOCK = 0x0000ffff;
     
    // 设置分频
    rREG_CLK_DIV0 = 0x14131440;
     
    // 设置PLL
    // FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1)) = 0x7d * 24 / (0x3 * 2^(1-1)) = 1000MHz
    rREG_APLL_CON0 = APLL_VAL;
    // FOUT = MDIV * FIN / (PDIV * 2^SDIV) = 0x29b * 24 / (0xc * 2^1) = 667MHz
    rREG_MPLL_CON = MPLL_VAL;
     
    // 设置各种时钟开关,使用PLL
    rREG_CLK_SRC0 = 0x10001111;
}

 

分享到:
评论

相关推荐

    S5PV210初始化系统时钟

    以下是关于"S5PV210初始化系统时钟"的详细知识讲解。 首先,我们要理解S5PV210的时钟架构。S5PV210有一个复杂的时钟管理系统,它由多个振荡器、锁相环(PLL)、分频器和倍频器组成。系统时钟通常来自外部晶体振荡器...

    s5pv210-clock_init_s.zip_bl1_s5pv210_时钟初始化_汇编程序

    在本文中,我们将深入探讨如何使用汇编语言对三星S5PV210处理器进行时钟初始化,这是嵌入式系统开发中的一个关键步骤。三星S5PV210是一款基于ARM Cortex-A8架构的高性能微处理器,广泛应用于智能手机、平板电脑和...

    s5pv210中断系统

    中断系统是S5PV210处理器中非常重要的组成部分,它负责处理处理器内部以及外部的各种事件通知,确保处理器能够及时响应这些事件。 在S5PV210中断系统中,共有93个中断源,这些中断源被组织成4组。每个中断源对应一...

    S5PV210芯片数据手册 cortex-A8内核

    在S5PV210数据手册中,我们能找到关于Cortex-A8内核的详细信息,如CPU时钟频率、内存接口、电源管理、中断控制器等关键模块的描述。这些信息对于理解和配置芯片至关重要。例如,手册会详细介绍如何通过配置寄存器来...

    S5PV210源码

    S5PV210是一款由三星公司推出的高性能、低功耗的ARM Cortex-A8处理器,广泛应用于嵌入式系统、移动设备以及智能硬件等领域。对于学习和开发基于S5PV210的系统,理解其源码是至关重要的一步。这篇笔记将深入探讨S5PV...

    S5PV210 PWM定时器

    【S5PV210 PWM定时器】是三星公司推出的一款基于ARM Cortex-A8处理器的SoC(系统级芯片)中的重要硬件模块。PWM(Pulse Width Modulation,脉宽调制)定时器在嵌入式系统中广泛用于电机控制、LED亮度调节、模拟信号...

    基于s5pv210的是时钟程序

    【基于s5pv210的时钟程序】是一个针对特定硬件平台的系统级软件开发项目,主要目标是实现和管理设备的时钟系统。s5pv210是一款由Samsung公司推出的高性能ARM Cortex-A8处理器,常用于嵌入式系统,如智能设备和消费...

    clk-s5pv210.rar_s5pv210

    描述中提到"S5PC110 S5PV210 clock controller register offsets"表明内容着重于S5PV210时钟控制器的寄存器偏移量,这对于理解处理器内部时钟系统的工作原理至关重要。 S5PV210是一款由三星(Samsung)推出的高性能...

    S5PV210 u-boot移植详细教程及移植好工程

    S5PV210是一款由Samsung开发的高性能ARM Cortex-A8核心的系统级芯片(SoC),广泛应用于嵌入式系统和开发板中。u-boot作为开源的引导加载程序,对于这类硬件平台至关重要,它负责初始化硬件、加载操作系统内核,以及...

    s5pv210 timer0 pwm输出

    在嵌入式系统领域,S5PV210是一款由Samsung公司推出的高性能ARMCortex-A8处理器,广泛应用于各种嵌入式设备,如智能手机、平板电脑等。在本主题中,我们将深入探讨如何利用S5PV210的Timer0模块来输出PWM信号,进而...

    S5PV210 SPI通讯

    S5PV210是三星公司开发的一款基于ARM Cortex-A8内核的系统级芯片(SoC),它集成了多种接口,包括SPI,用于与其他设备进行数据交换。STM32则是意法半导体(STMicroelectronics)生产的一系列基于ARM Cortex-M内核的...

    S5PV210内存配置代码(TQ210)

    3. **C语言实现**:在描述中提到的博客文章中,作者使用C语言编写了内存初始化代码,这涉及到对S5PV210的系统寄存器操作。例如,通过设置`MPLLCON`寄存器来调整内存总线的频率,通过`DRAMCON`寄存器设定DDR的时序...

    S5PV210数据手册

    - **移动设备**: 智能手机和平板电脑是S5PV210的主要应用场景之一,其高性能和低功耗特性非常适合这类设备。 - **车载信息系统**: 由于具备强大的多媒体处理能力,S5PV210也被广泛应用于汽车娱乐系统。 - **数字标牌...

    s5pv210-spi.rar_s5pv210 spi_s5pv210-spi_s5pv210裸机SPI

    S5PV210是一款由三星公司开发的高性能、低功耗的应用处理器,广泛应用于嵌入式系统,如智能手机和平板电脑。SPI(Serial Peripheral Interface)是一种常见的串行通信协议,用于连接微控制器和其他外围设备。在S5PV...

    S5PV210应用原理图

    标题"S5PV210应用原理图"和描述"SMDK_S5PV210_CPU B'd (S5PV210 Evaluation Board) Schematics"指出我们关注的是S5PV210评估板的原理图。S5PV210是三星电子生产的一款具有高性能的多媒体处理器,广泛应用于平板电脑...

    S5PV210 UBOOT源码 bsp

    `arch/arm/mach-s5pv210` 文件夹下则是与S5PV210架构相关的代码,包括处理器初始化、时钟管理等。 在进行 BSP(Board Support Package)开发时,开发者需要根据实际硬件调整UBOOT源码中的配置,比如设置正确的内存...

    S5PV210三星原厂wince BSP

    总之,S5PV210三星原厂Windows CE BSP是开发者构建基于S5PV210平台的Windows CE系统的重要工具,它提供了全面的硬件支持,优化了系统性能,简化了开发流程。理解并熟练运用BSP中的各个组件,是成功开发和调试嵌入式...

    s5pv210 datasheet

    S5PV210是一款高性能的ARM Cortex-A8处理器,由三星电子研发,广泛应用于智能手机、平板电脑和嵌入式系统等设备中。这款处理器以其强大的处理能力、低功耗设计以及丰富的接口选项而受到业界的青睐。在深入理解S5PV...

Global site tag (gtag.js) - Google Analytics