时钟是同步工作系统的同步信号,SOC内部有很多控制器,例如CPU,串口等外设,这些外设需要协同工作,互相通信,就需要同步的时钟系统来指挥。这个就是Soc的时钟系统。
时钟设置编码实现
查手册和系统时钟图算出各位置应该配置的值: 计算分频器每部分应该设置的值 之前的各时钟是由uboot程序设置好的,现在我们在跳转到C语言的main函数之前自己重新设置相应的时钟。 start.s:
.global _start
_start:
b reset
b undef
b swi
b abt_pre
b abt_dat
b reserved
b irq
b fiq
reset:
@重新映射异常向量表到0x40008000
ldr r0, =0x40008000
mcr p15, 0, r0, c12, c0, 0
@打开中断的总开关
mrs r0, cpsr
bic r0, r0, #(0x1 << 7)
msr cpsr, r0
bl clock_init
bl main
undef:
swi:
abt_pre:
abt_dat:
reserved:
irq:
ldr sp, =0x420000000 @初始化栈指针
stmfd sp!, {r0-r12,lr}
bl irq_handler @跳到中断函数
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
fiq:
clock.s:
.global clock_init
clock_init:
@先关闭所有PLL
@CLK_SRC0
ldr r0, =0xE0100200
ldr r1, =0x0
str r1, [r0]
@设置PLL
@APLL_LOCK
ldr r0, =0xE0100000
ldr r1, =30*24
str r1, [r0]
@MPLL_LOCK
ldr r0, =0xE0100008
ldr r1, =200*24
str r1, [r0]
@EPLL_LOCK
ldr r0, =0xE0100010
ldr r1, =375*24
str r1, [r0]
@VPLL_LOCK
ldr r0, =0xE0100020
ldr r1, =100*24
str r1, [r0]
@设置倍频因子
@APLL_CON0
ldr r0, =0xE0100100
ldr r1, =(1<<31)|(125<<16)|(3<<8)|(1<<0)
str r1, [r0]
@MPLL_CON
ldr r0, =0xE0100108
ldr r1, =(1<<31)|(667<<16)|(12<<8)|(1<<0)
str r1, [r0]
@配置分频器
@CLK_DIV0
ldr r0, =0xE0100300
ldr r1, =(1<<28)|(4<<20)|(1<<20)|(3<<16)|(1<<12)|(4<<8)|(4<<4)|0
str r1, [r0]
@选择使用PLL
@CLK_SRC0
ldr r0, =0xE0100200
ldr r1, =0x1111
str r1, [r0]
delay:
mov r0, 0x100000
d:
subs r0, r0, #1
bne d
mov pc, lr
main.c
#define WTCON (*(volatile unsigned int *)0xE2700000))
#define WTDAT (*(volatile unsigned int *)0xE2700004))
#define WTCNT (*(volatile unsigned int *)0xE2700008))
#define WTCLRINT (*(volatile unsigned int *)0xE270000C))
void key1_handler(void)
{
int (*printf)(char *format,...)=(void *)0x3ff13e54;
printf("hello wdt..\n");
WTCLRINT = 1;
}
void wdt_init()
{
WTCON = (65<<8)|(0x1<<5)|(0x1<<3)|(0x1<<2)|0;
WTCNT = 1000*1000/32;
WTDAT = 1000*1000/32;
}
int main()
{
wdt_init();
request_irq(27,wdt_handler);
while(1)
{
;
}
return 0;
}
irq.c:
#define VICOINTSELECT (*(volatile unsigned int *)0xF200000C)
#define VIC1INTSELECT (*(volatile unsigned int *)0xF210000C)
#define VIC2INTSELECT (*(volatile unsigned int *)0xF220000C)
#define VIC3INTSELECT (*(volatile unsigned int *)0xF230000C)
#define VIC0VECTADDR (volatile unsigned int *)0xF2000100
#define VIC1VECTADDR (volatile unsigned int *)0xF2100100
#define VIC2VECTADDR (volatile unsigned int *)0xF2200100
#define VIC3VECTADDR (volatile unsigned int *)0xF2300100
#define VIC0INTENABLE (*(volatile unsigned int *)0xF2000010)
#define VIC1INTENABLE (*(volatile unsigned int *)0xF2100010)
#define VIC2INTENABLE (*(volatile unsigned int *)0xF2200010)
#define VIC3INTENABLE (*(volatile unsigned int *)0xF2300010)
#define VIC0ADDRESS (*(volatile unsigned int *)0xF2000F00)
#define VIC1ADDRESS (*(volatile unsigned int *)0xF2100F00)
#define VIC2ADDRESS (*(volatile unsigned int *)0xF2200F00)
#define VIC3ADDRESS (*(volatile unsigned int *)0xF2300F00)
int request_irq(int irq, void(*handler)())
{
if(irq>=0 && irq <= 31)
{
VICOINTSELECT = 0;
VIC0VECTADDR[irq] = (unsigned int)handler;
VIC0INTENABLE |= 0x1<<irq;
}
else if(irq>=32 && irq<=63)
{
irq-=32;
VIC1INTSELECT = 0;
VIC1VECTADDR[irq] = (unsigned int)handler;
VIC1INTENABLE |= 0x1<<irq;
}
else if(irq>=64 && irq <=95)
{
irq-=64;
VIC2INTSELECT = 0;
VIC2VECTADDR[irq] = (unsigned int)handler;
VIC2INTENABLE |= 0x1<<irq;
}
else if(irq>=96 && irq <=128)
{
irq-=96;
VIC3INTSELECT = 0;
VIC3VECTADDR[irq] = (unsigned int)handler;
VIC3INTENABLE |= 0x1<<irq;
}
}
void irq_handler()
{
void(*handler)();
if(VIC0ADDRESS !=0 )
handler=(void *)VIC0ADDRESS;
else if(VIC1ADDRESS !=0)
handler=(void *)VIC1ADDRESS;
else if(VIC2ADDRESS !=0)
handler=(void *)VIC2ADDRESS;
else if(VIC3ADDRESS !=0)
handler=(void *)VIC3ADDRESS;
handler();
VIC0ADDRESS=0;
VIC1ADDRESS=0;
VIC2ADDRESS=0;
VIC3ADDRESS=0;
}
编译和测试
因为串口用的是PCLK,如果按手册设置正确,则打印正常。 修改clock.s:
ldr r1, =(0<<28)|(4<<20)|(1<<20)|(3<<16)|(1<<12)|(4<<8)|(4<<4)|0
再次编译运行: 因为时钟变快了,则看门狗触发中断速度变快,而串口波特率也变了,所以是乱码。
|