【说明】
前面原理已经很清楚了,现在分析代码,放在2个博文中是方便大家同时打开2个博文,原理图和代码对应看
【源代码】
工程文件如下,其中clock.S 用来初始化时钟,main.c 测试用的,依旧是LED灯,start.S 是程序最前面那一段
1】 main.c
// 功能:流水灯
void delay()
{
volatile int i = 0x10000;
while (i--);
}
int main()
{
int i = 0;
volatile unsigned long *gpkcon0 = (volatile unsigned long *)0x7F008800;
volatile unsigned long *gpkdat = (volatile unsigned long *)0x7F008808;
*gpkcon0 = (*gpkcon0 & ~(0xffff<<16)) | (0x1111<<16);
while (1)
{
*gpkdat = (*gpkdat & ~(0xf<<4)) | (i<<4);
i++;
if (i == 16)
i = 0;
delay(0x10000);
}
return 0;
}
2】 clock.S
// 功能:汇编初始化时钟
.global clock_init
clock_init:
// 1. 设置各PLL的LOCK_TIME,使用默认值
ldr r0, =0x7E00F000 // APLL_LOCK,供cpu使用
ldr r1, =0x0000FFFF
str r1, [r0]
str r1, [r0, #4] // MPLL_LOCK,供AHB(存储/中断/lcd等控制器)/APB(看门狗,定时器,SD等)总线上的设备使用
str r1, [r0, #8] // EPLL_LOCK,供UART,IIS,IIC使用
// 2. 设置为异步模式(Asynchronous mode)
ldr r0, =0x7E00F900 // OTHERS
// 《linux installation for u-boot》3.7中:用MPLL作为HCLK和PCLK的Source是异步(ASYNC)模式
// 用APLL是同步(SYNC)模式
ldr r1, [r0]
bic r1, r1, #0xc0 // bit[6:7]清0,即SYNCMODE=0/SYNCMUXSEL=0
str r1, [r0]
loop:
ldr r0, =0x7E00F900
ldr r1, [r0]
and r1, r1, #0xf00
cmp r1, #0
bne loop
// 3. 设置分频系数
#define ARM_RATIO 0 // ARMCLK = DOUTAPLL / (ARM_RATIO + 1) = 532/(0+1) = 532 MHz
#define MPLL_RATIO 0 // DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) = 532/(0+1) = 532 MHz
#define HCLKX2_RATIO 1 // HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) = 532/(1+1) = 266 MHz
#define HCLK_RATIO 1 // HCLK = HCLKX2 / (HCLK_RATIO + 1) = 266/(1+1) = 133 MHz
#define PCLK_RATIO 3 // PCLK = HCLKX2 / (PCLK_RATIO + 1) = 266/(3+1) = 66.5 MHz
ldr r0, =0x7E00F020 // CLK_DIV0
ldr r1, =(ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)
str r1, [r0]
// 4. 设置PLL,放大时钟
// 4.1 配置APLL
#define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F00C // APLL_CON
ldr r1, =APLL_CON_VAL // FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHz
str r1, [r0]
// 4.2 配置MPLL
#define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F010 // MPLL_CON
ldr r1, =MPLL_CON_VAL // FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHz
str r1, [r0]
#define MPLL_SEL 1
#define APLL_SEL 1
// 5.选择PLL的输出作为时钟源
ldr r0, =0x7E00F01C // CLK_SRC
ldr r1, =(MPLL_SEL<<1) | (APLL_SEL<<0)
str r1, [r0]
mov pc, lr
3】 start.S
// 启动代码
.global _start
_start:
// 把外设的基地址告诉CPU
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4
// 关看门狗
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
// 设置栈
ldr sp, =0x0C002000
// 开启icaches
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
#else
orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
#endif
mcr p15, 0, r0, c1, c0, 0
// 设置时钟
bl clock_init
// 调用C函数点灯
bl main
halt:
b halt
4】 Makefile
clock.bin: start.o clock.o main.o
arm-linux-ld -Ttext 0 -o clock.elf start.o clock.o main.o
arm-linux-objcopy -O binary clock.elf clock.bin
arm-linux-objdump -D clock.elf > clock.dis
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis
【烧写】
同LED
【实验现象】
LED闪得非常快,因为CPU时钟现在比以前快多了