前面分析了 4412 时钟体系,本文来简单测试一下,参考韦东山老师的 Linux 应用完全开发手册4412 (上)
第一实验:
三星公司的BL1会将ARMCLK初始化为400MHz,我们关闭APLL,让 ARMCLK 工作在 24MHz,查看LED闪烁是否缓慢
start.S
- .text
- .globl _start
- _start:
- ldr sp, =0x02027800
- // 调用C函数之前必须设置栈,栈用于保存运行环境,给局部变量分配空间
- // 参考ROM手册P14, 我们把栈指向BL2上方1K处(1K已经够用),
- // 即:0x02020000 (iRAM基地址) + 5K(iROM代码用) + 8K(BL1用) + 16K(BL2用) + 1K(用作栈))
- bl main // 调用main函数(main这个名称不是固定的,可以随意改)
- halt_loop:
- b halt_loop
.text
.globl _start
_start:
ldr sp, =0x02027800
// 调用C函数之前必须设置栈,栈用于保存运行环境,给局部变量分配空间
// 参考ROM手册P14, 我们把栈指向BL2上方1K处(1K已经够用),
// 即:0x02020000 (iRAM基地址) + 5K(iROM代码用) + 8K(BL1用) + 16K(BL2用) + 1K(用作栈))
bl main // 调用main函数(main这个名称不是固定的,可以随意改)
halt_loop:
b halt_loop</pre><span style="font-family:SimSun; font-size:18px">led.c</span><div class="dp-highlighter bg_cpp"><div class="bar" style="display: block;"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 395px; top: 1166px; width: 21px; height: 11px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="21" height="11" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=21&height=11" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><span class="tracking-ad" data-mod="popu_167"><a href="https://code.csdn.net/snippets/1935944" target="_blank" title="在CODE上查看代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/CODE_ico.png" width="12" height="12" alt="在CODE上查看代码片" style="position:relative;top:1px;left:2px;"></a></span><span class="tracking-ad" data-mod="popu_170"><a href="https://code.csdn.net/snippets/1935944/fork" target="_blank" title="派生到我的代码片" style="text-indent:0;"><img src="https://code.csdn.net/assets/ico_fork.svg" width="12" height="12" alt="派生到我的代码片" style="position:relative;top:2px;left:2px;"></a></span></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="preprocessor">#define GPM4CON (*(volatile unsigned int *)0x110002E0)</span><span> </span></span></li><li class=""><span><span class="preprocessor">#define GPM4DAT (*(volatile unsigned int *)0x110002E4)</span><span> </span></span></li><li class="alt"><span><span class="keyword">void</span><span> delay(</span><span class="keyword">volatile</span><span> </span><span class="datatypes">int</span><span> time) </span></span></li><li class=""><span>{ </span></li><li class="alt"><span> <span class="keyword">for</span><span>(; time > 0; time-- ) </span></span></li><li class=""><span> ; </span></li><li class="alt"><span>} </span></li><li class=""><span><span class="datatypes">int</span><span> main(</span><span class="keyword">void</span><span>) </span></span></li><li class="alt"><span>{ </span></li><li class=""><span> unsigned <span class="datatypes">long</span><span> tmp = 0; </span></span></li><li class="alt"><span> <span class="datatypes">int</span><span> i = 0; </span></span></li><li class=""><span><span class="comment">/*</span> </span></li><li class="alt"><span><span class="comment"> * GPM4_0-GPM4_3 设置为输出功能</span> </span></li><li class=""><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> tmp = GPM4CON; </span></li><li class=""><span> tmp &= ~0xffff; </span></li><li class="alt"><span> tmp |= 0x1111; </span></li><li class=""><span> GPM4CON = tmp; </span></li><li class="alt"><span><span class="comment">/*</span> </span></li><li class=""><span><span class="comment"> * 实现流水灯</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> system_clock_init(); </span></li><li class="alt"><span> <span class="keyword">while</span><span>(1) </span></span></li><li class=""><span> { </span></li><li class="alt"><span> GPM4DAT = i; </span></li><li class=""><span> <span class="keyword">if</span><span> (++i == 16) </span></span></li><li class="alt"><span> i = 0; </span></li><li class=""><span> delay(9999999); </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> 0; </span></span></li><li class="alt"><span>} </span></li></ol><div class="save_code tracking-ad" data-mod="popu_249" style="display: none;"><a href="javascript:;" target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png"></a></div></div><pre code_snippet_id="1935944" snippet_file_name="blog_20161018_2_8445105" name="code" class="cpp" style="display: none;">#define GPM4CON (*(volatile unsigned int *)0x110002E0)
#define GPM4DAT (*(volatile unsigned int *)0x110002E4) void delay(volatile int time) { for(; time > 0; time-- ) ; } int main(void) { unsigned long tmp = 0; int i = 0; /* * GPM4_0-GPM4_3 设置为输出功能 */ tmp = GPM4CON; tmp &= ~0xffff; tmp |= 0x1111; GPM4CON = tmp; /* * 实现流水灯 */ system_clock_init(); while(1) { GPM4DAT = i; if (++i == 16) i = 0; delay(9999999); } return 0; }
clock_init.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;
- }
// 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; }
Makfile
- objs := start.o led.o clock_init.o
- led.bin : (objs) </span></li><li class="alt"><span> arm-linux-ld -Tled.lds -N -o led.elf ^
- arm-linux-objcopy -O binary -S led.elf @ </span></li><li class="alt"><span> arm-linux-objdump -D -m arm led.elf > led.dis </span></li><li class=""><span>%.o:%.c </span></li><li class="alt"><span> arm-linux-gcc -Wall -marm -c -O2 -o @ < </span></li><li class=""><span>%.o:%.S </span></li><li class="alt"><span> arm-linux-gcc -Wall -marm -c -O2 -o @ $
- clean:
- rm -f *.dis *.bin *.elf *.o
objs := start.o led.o clock_init.o
led.bin : $(objs)
arm-linux-ld -Tled.lds -N -o led.elf $^
arm-linux-objcopy -O binary -S led.elf $@
arm-linux-objdump -D -m arm led.elf > led.dis
%.o:%.c
arm-linux-gcc -Wall -marm -c -O2 -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -marm -c -O2 -o $@ $
clean:
rm -f *.dis *.bin *.elf *.o
led.lds
- SECTIONS {
- . = 0x02023400;
- .text : { *(.text) }
- .rodata ALIGN(4) : {*(.rodata*)}
- .data ALIGN(4) : { *(.data*) }
- .bss ALIGN(4) : { *(.bss) *(COMMON) }
- }
SECTIONS {
. = 0x02023400;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data*) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
实验现象应该是相比 led.c 中不加 system_clock_init() 的时候,LED闪烁的非常缓慢。
第二个实验:
将 ARMCLK 提升到1400MHz ,观察LED闪烁是否变快。只更改 clock_init.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)
- {
- /* 1. 在设置APLL之前, 先设置时钟源为晶振 */
- CLK_SRC_CPU = 0x0;
- /* 2. 设置APLL */
- /* 2.1 设置锁定时间: APLL_CON0中PDIV=3, 所以APLL_LOCK = 270x3 */
- APLL_LOCK = 270 * 3;
- /* 2.2 设置分频参数 */
- CLK_DIV_CPU0 = 0x00160760;
- CLK_DIV_CPU1 = 0x00000106;
- /* 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;
- }
// 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) { /* 1. 在设置APLL之前, 先设置时钟源为晶振 */ CLK_SRC_CPU = 0x0; /* 2. 设置APLL */ /* 2.1 设置锁定时间: APLL_CON0中PDIV=3, 所以APLL_LOCK = 270x3 */ APLL_LOCK = 270 * 3; /* 2.2 设置分频参数 */ CLK_DIV_CPU0 = 0x00160760; CLK_DIV_CPU1 = 0x00000106; /* 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; }
三星给出了 high-performance 状态下的频率值,我将 cpu 部分的频率配置到该表推荐值以下,程序就正常运行了。