Exynos4412裸机程序,时钟操作

发布者:谁与争锋1最新更新时间:2018-10-14 来源: eefocus关键字:Exynos4412  裸机程序  时钟操作 手机看文章 扫描二维码
随时随地手机看文章

有了上一节《Exynos4412时钟体系分析》的基础,这一节我们来做几个和时钟有关的实验。

其实,Exynos 4412的 IROM代码已经设置了PLL,我们可以通过串口把IROM设置的PLL寄存器值打印出来,这些值打印出来是这样的(摘自韦东山老师的《嵌入式Linux系统开发完全手册_基于4412__上册》):

CLK_SRC_CPU = 0x01000001

CLK_DIV_DMC0 = 0x00111713

CLK_DIV_DMC1 = 0x01011171

CLK_SRC_TOP0 = 0x01110000

CLK_SRC_TOP1 = 0x00001000

CLK_DIV_TOP = 0x00015470

CLK_SRC_LEFTBUS = 0x00000001

CLK_DIV_LEFTBUS = 0x00000013

CLK_SRC_RIGHTBUS = 0x00000001

CLK_DIV_RIGHTBUS = 0x00000013

APLL_LOCK = 0x00000960

MPLL_LOCK = 0x00000000

EPLL_LOCK = 0x00000FFF

VPLL_LOCK = 0x00000FFF

CLK_DIV_CPU0 = 0x00773730

CLK_DIV_CPU1 = 0x00000077

APLL_CON1 = 0x00003800

APLL_CON0 = 0xA0640301

MPLL_CON1 = 0x00003800

MPLL_CON0 = 0xA0640301

EPLL_CON2 = 0x00000080

EPLL_CON1 = 0x66010000

EPLL_CON0 = 0x00600302

VPLL_CON2 = 0x00000080

VPLL_CON1 = 0x66016000

VPLL_CON0 = 0x006F0302

CLK_SRC_CPU = 0x01000001

CLK_SRC_DMC = 0x00111000

CLK_SRC_TOP0 = 0x01110000

CLK_SRC_TOP1 = 0x00001000

现在来计算 ARMCLK的时钟频率:

由上一节《Exynos4412时钟体系分析》的介绍我们知道,ARMCLK 有如下计算公式:

如下图所示:

CLK_DIV_CPU0

由上边打印的寄存器CLK_SRC_CPU 的值为:

十六进制:0x01000001

二进制:0000 0001 0000 0000 0000 0000 0000 0001

① BIT[0] 控制第1个MUX (即 MUXAPLL) ,该位值为1.

② BIT[16]控制 第2个 MUX( 即MUXCORE) ,该位值为0.

所以由此看出ARMCLK时钟走的是如下的路线:

ARM CLK

所以:ARMCLK = MUXCORE的输出 / DIVCORE / DIVCORE2

ARMCLK = MDIV x FIN / (PDIV x 2 ^ SDIV) / (CORE_RATIO + 1) / (CORE2_RATIO + 1)

= 0x64 x 24MHz / (3 x 2 ^ 1) / (0 + 1) / (0 + 1)

= 400 MHz

 

本次实验涉及3个小实验:

① 4.system_clock_disable_apll:不使用 APLL,让CPU运行于 24MHz 频率,观察 LED 闪烁是否变慢

② 5.system_clock_apll:重新设置APLL,让 CPU 运行于1.4GHz频率,观察 LED 闪烁是否变快

③ 6.system_clock_plls:参考厂家提供的u-boot代码,设置所有PLL供后续章节使用

第一个小实验

实现的目标:不使用 APLL,让CPU运行于 24MHz 频率,观察 LED 闪烁是否变慢

一、程序说明

我们在前一个实验,《Tiny4412之C语言实现流水灯》的基础上修改。

start.S大部分相同,只是增加一条函数调用语句:

bl system_clock_init // 调用时钟初始化函数

如下图所示:

启动文件

启动文件

链接脚本system_clock.lds的内容和上一个实验key.lds完全相同,只把名字改了改;Makefile的内容也大部分一样,也只是改了改里边文件的名字,led.c文件和LED实验时完全相同,新增加了文件system_clock.c,代码如下:

// CMU_CPU

#define CLK_SRC_CPU (*(volatile unsigned int *)0x10044200)

#define CLK_DIV_CPU0 (*(volatile unsigned int *)0x10044500)

#define CLK_DIV_CPU1 (*(volatile unsigned int *)0x10044504)

// CMU_DMC

#define CLK_SRC_DMC (*(volatile unsigned int *)0x10040200)

#define CLK_DIV_DMC0 (*(volatile unsigned int *)0x10040500)

#define CLK_DIV_DMC1 (*(volatile unsigned int *)0x10040504)

// CMU_TOP

#define CLK_SRC_TOP0 (*(volatile unsigned int *)0x1003C210)

#define CLK_SRC_TOP1 (*(volatile unsigned int *)0x1003C214)

#define CLK_DIV_TOP (*(volatile unsigned int *)0x1003C510)

// CMU_LEFTBUS

#define CLK_SRC_LEFTBUS (*(volatile unsigned int *)0x10034200)

#define CLK_DIV_LEFTBUS (*(volatile unsigned int *)0x10034500)

// CMU_RIGHTBUS

#define CLK_SRC_RIGHTBUS (*(volatile unsigned int *)0x10038200)

#define CLK_DIV_RIGHTBUS (*(volatile unsigned int *)0x10038500)

// locktime

#define APLL_LOCK (*(volatile unsigned int *)0x10044000)

#define MPLL_LOCK (*(volatile unsigned int *)0x10044008)

#define EPLL_LOCK (*(volatile unsigned int *)0x1003C010)

#define VPLL_LOCK (*(volatile unsigned int *)0x1003C020)

// APLL

#define APLL_CON1 (*(volatile unsigned int *)0x10044104)

#define APLL_CON0 (*(volatile unsigned int *)0x10044100)

// MPLL

#define MPLL_CON0 (*(volatile unsigned int *)0x10040108)

#define MPLL_CON1 (*(volatile unsigned int *)0x1004010c)

// EPLL

#define EPLL_CON2 (*(volatile unsigned int *)0x1003C118)

#define EPLL_CON1 (*(volatile unsigned int *)0x1003C114)

#define EPLL_CON0 (*(volatile unsigned int *)0x1003C110)

// VPLL

#define VPLL_CON0 (*(volatile unsigned int *)0x1003C120)

#define VPLL_CON1 (*(volatile unsigned int *)0x1003C124)

#define VPLL_CON2 (*(volatile unsigned int *)0x1003C128)

 

//函数名:

//system_clock_init

//功能: 初始化4412的系统时钟

void system_clock_init(void)

{

  // IROM或BL1设置了APLL,

  //本程序设置不启动APLL,

  //而是使在晶振时钟, 以体验一下LED闪灯变慢

  CLK_SRC_CPU = 0x0;

}

没什么可说的,很简单,前部分是后期会用到的一些寄存器地址的定义,主要的是下边system_clock_init这个函数,在这个函数中将CLK_SRC_CPU寄存器的值设为0,这样ARMCLK的频率将走下面这条路径,设置为24MHZ:

ARM CLK_SETD

二、编译、烧写实验

按照前几节介绍的方法,将程序上传到服务器编译,并烧写到SD卡上,给开发板上电,可以明显感觉到LED闪烁的频率大大降低,说明我们设置的时钟起作用了,这里就不上图了(上了图大家也看不出来)。

第二个小实验

实现的目标:重新设置APLL,让 CPU 运行于1.4GHz频率,观察 LED 闪烁是否变快

一、程序说明

文件同第一个小实验,只是在它的基础上对system_clock.c文件中的system_clock_init函数进行修改:

//函数名: system_clock_init

//功 能: 初始化4412的系统时钟

//最终结果: APLL=1.4GHz

void system_clock_init(void)

{

    // 1. 在设置APLL之前, 先设置时钟源为晶振

    CLK_SRC_CPU = 0x0;

    // 2. 设置APLL

    

    // 2.1 设置锁定时间: APLL_CON0中PDIV=3, 所以APLL_LOCK = 270x3 

    APLL_LOCK = 270 * 3;

     

    // 2.2 设置分频参数 

    // CORE2_RATIO = 0;

    // APLL_RATIO = 2;

    // PCLK_DBG_RATIO = 1;

    // ATB_RATIO = 6;

    // PERIPH_RATIO = 7;

    // COREM1_RATIO = 7;

    // COREM0_RATIO = 3;

    // CORE_RATIO = 0;

    CLK_DIV_CPU0 = ((0<<28) | (2<<24) | (1<<20) | (6<<16) | (7<<12) | (7<<8) | (3<<4) | 0);

     

    // CORES_RATIO = 5;

    // HPM_RATIO = 0;

    // COPY_RATIO = 6;

    CLK_DIV_CPU1 = ((5 << 8) |(0 << 4) | (6));

     

    // 2.3 设置控制参数并使能PLL 

    // 默认值 

    APLL_CON1 = 0x00803800;

     

    // 设置APLL的M,P,S值, APLL输出 = 0xAF x 24MHz / (3 x 2 ^ 0) = 1.4GHz

    // 使能APLL

    APLL_CON0 = (1<<31 | 0xAF<<16 | 3<<8 | 0x0);

     

    // 3. 设置MUX, 使用APLL的输出 

    CLK_SRC_CPU = 0x01000001;

}

注释的已经很清楚了,需要注意的就是:上电之后 IROM设置了APLL ,CPU工作于APLL提供的时钟;当我们要改变 APLL时,要先使得CPU工作于另一个时钟源,即晶振。设置完APLL后,再让CPU重新工作于APLL提供的时钟。

二、编译、烧写实验

按照前几节介绍的方法,将程序上传到服务器编译,并烧写到SD卡上,给开发板上电,可以明显感觉到LED闪烁的频率大大提高(比《Tiny4412之C语言实现流水灯》时闪烁的还要快,因为当时CPU运行在400MHZ,现在运行在1.4GHZ),说明我们设置的时钟起作用了,这里就不上图了(上了图大家也看不出来)。

第三个小实验

实现的目标:参考厂家提供的u-boot代码,设置所有PLL供后续章节使用

一、程序说明

文件同第一个小实验,只是在它的基础上对system_clock.c文件中的system_clock_init函数进行修改:

// 函数名:

// system_clock_init

// 功能:

// 初始化4412的系统时钟

// 最终结果:

// A=1400000000, M=800000000, E=96000000 V=350000000

// ARMCLK=1500000000, DMC=400000000, ACLK200=160000000

// ACLK100=100000000, ACLK160=160000000, ACLK133=133333333

void system_clock_init(void)

{

    // 1.设置CMU_CPU相关 

    CLK_SRC_CPU = 0x0; // 设置CMU_CPU部分中所有的MUX的源

     

    // 2.设置CMU_DMC相关 

    //

    CORE_TIMERS_RATIO = 0x0;

    COPY2_RATIO = 0x0;

    DMCP_RATIO = 0x1;

    DMCD_RATIO = 0x1;

    DMC_RATIO = 0x1;

    DPHY_RATIO = 0x1;

    ACP_PCLK_RATIO = 0x1;

    ACP_RATIO = 0x3;

    

    CLK_DIV_DMC0 = ((0x0 << 28) | (0x0 << 24) | (0x1 << 20) | (0x1 << 16) | (0x1 << 12) | (0x1 << 8) | (0x1 << 4) | (0x3));

    CLK_DIV_DMC1 = 0x07071713;

     

    // 3.设置CMU_TOP相关 

    //

    MUX_ONENAND_SEL = 0x0;

    MUX_ACLK_133_SEL = 0x0;

    MUX_ACLK_160_SEL = 0x0;

    MUX_ACLK_100_SEL = 0x0;

    MUX_ACLK_200_SEL = 0x0;

    MUX_VPLL_SEL = 0x1;

    MUX_EPLL_SEL = 0x1;

    

    CLK_SRC_TOP0 = ((0x0 << 28) | (0x0 << 24) | (0x0 << 20) | (0x0 << 16) | (0x0 << 12) | (0x1 << 8) | (0x1 << 4));

    CLK_SRC_TOP1 = 0x01111000;

     

    //

    ACLK_400_MCUISP_RATIO = 0x1;

    ACLK_266_GPS_RATIO = 0x2;

    ONENAND_RATIO = 0x1;

    ACLK_133_RATIO = 0x5;

    ACLK_160_RATIO = 0x4;

    ACLK_100_RATIO = 0x7;

    ACLK_200_RATIO = 0x4;

    

    CLK_DIV_TOP = ((0x1 << 24) | (0x2 << 20) | (0x1 << 16) | (0x5 << 12) | (0x4 << 8) | (0x7 << 4) | (0x4));

     

    // 3.设置CMU_LEFTBUS相关 

    CLK_SRC_LEFTBUS = 0x10;

     

    //

    GPL_RATIO = 0x1;

    GDL_RATIO = 0x3;

    

    CLK_DIV_LEFTBUS = ((0x1 << 4) | (0x3));

     

    // 4.设置CMU_RIGHTBUS相关 

    CLK_SRC_RIGHTBUS = 0x10;

     

    //

    GPR_RATIO = 0x1;

    GDR_RATIO = 0x3;

    

    CLK_DIV_RIGHTBUS = ((0x1 << 4) | (0x3));

     

    // 5.设置各个锁相环(PLL)的locktime 

    APLL_LOCK = (0x3 * 270);

    MPLL_LOCK = (0x3 * 270);

    EPLL_LOCK = (0x2 * 3000);

    VPLL_LOCK = (0x2 * 3000);

    //

    APLL_RATIO = 0x2;

    CORE_RATIO = 0x0;

    CORE2_RATIO = 0x0;

    COREM0_RATIO = 0x3;

    COREM1_RATIO = 0x7;

    PERIPH_RATIO = 0x7;

    ATB_RATIO = 0x6;

    PCLK_DBG_RATIO = 0x1;

    

    CLK_DIV_CPU0 = ((0x0 << 28) | (0x2 << 24) | (0x1 << 20) | (0x6 << 16) | (0x7 <<12) | (0x7 << 8) | (0x3 << 4) | (0x0));

    //

    CORES_RATIO = 0x5;

    HPM_RATIO = 0x0;

    COPY_RATIO = 0x6;

    

    CLK_DIV_CPU1 = ((0x5 << 8) |(0x0 << 4) | (0x6));

     

    // 6.设置APLL = 1400000000 

    APLL_CON1 = 0x00803800;

    APLL_CON0 = (1<<31 | 0xAF<<16 | 0x3<<8 | 0x0);

     

    // 7.设置MPLL = 800000000 

    MPLL_CON1 = 0x00803800;

    MPLL_CON0 = (1<<31 | 0x64<<16 | 0x3<<8 | 0x0);

     

    // 8.设置EPLL = 96000000 

    EPLL_CON2 = 0x00000080;

    EPLL_CON1 = 0x66010000;

    EPLL_CON0 = (1<<31 | 0x40<<16 | 0x2<<8 | 0x3);

     

    // 9.设置VPLL = 350000000 

    VPLL_CON2 = 0x00000080;

    VPLL_CON1 = 0x66010000;

    VPLL_CON0 = (1<<31 | 0x48<<16 | 0x2<<8 | 0x3);

     

    //10.修改源

    CLK_SRC_CPU = 0x01000001;

    CLK_SRC_DMC = 0x00011000;

    CLK_SRC_TOP0 = 0x00000110;

    CLK_SRC_TOP1 = 0x01111000;

}

二、编译、烧写实验

按照前几节介绍的方法,将程序上传到服务器编译,并烧写到SD卡上,给开发板上电,现象和第二个小实验完全相同。


关键字:Exynos4412  裸机程序  时钟操作 引用地址:Exynos4412裸机程序,时钟操作

上一篇:Exynos4412裸机程序之操作ICache
下一篇:Exynos4412时钟体系分析

推荐阅读最新更新时间:2024-03-16 16:16

Exynos4412启动过程分析
学习Exynos4412启动流程前,我们先看看三星4412芯片启动框图: 我们从图中可以看到4412内部有64K的ROM和256K SRAM,在ROM中已经固化好了一段代码,当硬件上电后首先运行的就是这段代码,这段代码三星起名为BLO(iROM BOOT 代码)。其作用是初始化SRAM,并将eMMC中256k代码拷贝到SRAM中,进行初始化DRAM。在图中我们很清楚看到这一个运行过程。 1、在芯片的iROM中已经固化一个代码,当硬件上电后就读取OM电平从而确定硬件设置的启动模式:0110为从eMMC启动,1000位SD卡启动; 2、把已经设置启动存储单元代码复制到内部RAM中并跳转到RAM运行; 3、运行OS;
[单片机]
<font color='red'>Exynos4412</font>启动过程分析
[ARM裸机程序][6]ARM GNU汇编程序示例
ARM GNU汇编程序框架 .section .data 初始化的数据 .section .bss 未初始化的数据 .section .text .global _start _start: 汇编代码 入口地址 汇编程序的示例 //start.s .bass .text .global _start _start: mov r1,#1 mov r2,#2 add r3,r1,r2 _loop: b _loop //Makefile all:start.o arm-linux-ld -Ttext 0x30000000 -o start.elf start.o start.o:star
[单片机]
51单片机操作DS1302时钟芯片
#define uint unsigned int #define uchar unsigned char sbit lcdrs = P1^0; sbit lcdrw = P1^1; sbit lcden = P1^2; sbit key0 = P2^0;//功能键,选择时分秒 sbit key1 = P2^1;//加1键 sbit key2 = P2^2;//减1键 sbit key4 = P2^4; sbit clk_1302 = P1^5; //1302芯片位定义 sbit io_1302 = P1^6; sbit rst_1302 = P1^7; uchar bdata dat; sbit dat0 = dat^0; sb
[单片机]
Exynos4412 内核移植(七)—— 内核相关知识补充
一、内核调试方法简单分析 1、addr2line: 解决oops错误 a -- oops消息 oops(也称 panic),称程序运行崩溃,程序崩溃后会产生oops消息。应用程序或内核线程的崩溃都会产生oops消息,通常发生oops时,系统不会发生死机,而在终端或日志中打印oops信息。 当使用NULL指针或不正确的指针值时,通常会引发一个 oops 消息,这是因为当引用一个非法指针时,页面映射机制无法将虚拟地址映像到物理地址,处理器就会向操作系统发出一个 页面失效 的信号。内核无法 换页 到并不存在的地址上,系统就会产生一个 oops 。 oops 显示发生错误时处理器的状态,包括 CPU 寄
[单片机]
S3C2440运行裸机程序需烧录到NAND Flash
对于韦东山的S3C2440开发板,当运行LED等简单的小程序时,必须烧录到NAND Flash,原因如下: (1)NOR Flash虽然可以向内存一样进行读操作,但不可以像内存一样进行写操作,所以假如要从NOR Flash启动,一般先在代码的开始部分使用汇编指令初始化外接的内存器件(外部RAM),然后将代码复制到外存中,最后跳转到外存中继续执行。(这段初始化代码比较复杂,需要后面再学习)。 (2)S3C2440中有称为“Steppingstone”的4KB内存RAM,当选择从NAND Flash启动CPU时,CPU会通过内部的硬件将NAND Flash开始的4KB字节数据复制到这4KB的内部RAM中(此时内部RAM的起始地址为
[单片机]
eclipse调试arm裸机程序
一、集成开发环境 软件部分:eclipse , GDB Server , Jlink软件 硬件部分:Jlink硬件 准备工作1:从SD/NOR Flash启动,格式化nand flash 准备工作2:硬件连接 1. Jlink连接 2. 串口连接 3. nand启动 二、安装GDB Server 解压:tar xvzf arm-linux-gdb-7.5.tar.gz 进入目录:cd arm-linux-gdb-7.5 编译安装:./build-all 上面执行好后,gdb工具就安装好了,安装在/opt/arm-linux-gdb 为了方便使用,需要添加环境变量:
[单片机]
eclipse调试arm<font color='red'>裸机</font><font color='red'>程序</font>
Exynos4412 内核移植(五)—— 驱动的移植
以移植自己制作的驱动,学习内核移植中的驱动移植,及 驱动程序的动态编译和静态编译 硬件环境: Linux 内核版本:Linux 3.14 主机:Ubuntu 12.04发行版 目标机:FS4412平台 交叉编译工具:arm-none-linux-gnueabi-gcc 一、静态编译 1、添加驱动文件 将写好的实验代码fs4412_led_drv.c 拷贝到 drivers/char 下 fs4412_led_drv.c 如下: #include linux/kernel.h #include linux/module.h #include linux/fs.h #include linux
[单片机]
<font color='red'>Exynos4412</font> 内核移植(五)—— 驱动的移植
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved