Chinaunix首页 | 论坛 | 博客
  • 博客访问: 63271
  • 博文数量: 9
  • 博客积分: 426
  • 博客等级: 下士
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-29 13:35
文章分类
文章存档

2015年(1)

2010年(6)

2009年(2)

我的朋友

分类: LINUX

2010-01-16 22:32:35

AT91RM9200 的时钟源有4个:

慢时钟(SLK)

主时钟(Main Clock)

PLLAPLLB

在这里需要区别一个概念:主时钟和主机时钟

主时钟(main clock)是指输入主振荡器的时钟

主机时钟(mck)指CPU的时钟频率。 

主机时钟可以在4个时钟源中选择(时钟选择器)一个作为本身的时钟

时钟设置流程

 

 

启动代码中一些预定义的值

;-----------------------------------------------------------------------------

;- ARM Core Mode and Status Bits       ARM内核模式和状态位

;------------------------------------------------------------------------------

 

ARM_MODE_USER          EQU     0x10

ARM_MODE_FIQ            EQU     0x11

ARM_MODE_IRQ            EQU     0x12

ARM_MODE_SVC            EQU     0x13

ARM_MODE_ABORT         EQU     0x17

ARM_MODE_UNDEF         EQU     0x1B

ARM_MODE_SYS            EQU     0x1F

 

I_BIT                   EQU     0x80

F_BIT                  EQU     0x40

T_BIT                  EQU     0x20

 

;------------------------------------------------------------------

;- Stack Area Definition 堆栈段区域定义

;------------------------------------------------------------------

IRQ_STACK_SIZE         EQU      0x04

FIQ_STACK_SIZE         EQU      0x04

ABT_STACK_SIZE        EQU      0x04

UND_STACK_SIZE        EQU      0x04

SVC_STACK_SIZE        EQU      0x04

USER_STACK_SIZE       EQU      0x100 

 

;----------------------------------------------------------------------------

9200启动后时钟变化

由于系统复位后进入慢时钟状态,由慢时钟提供主机时钟源,但由于内置boot程序可能已经启动,需要在启动时重新设置慢时钟为主机时钟源。但主机时钟寄存器要求写入的值不能和当前值相同,所以要分成两步,代码如下:

//第一步,将PMC_MCKR 修改一下,这里使其选择PLLB作为主机时钟源

ldr              r1, = AT91C_BASE_PMC         ;取得PMC的基地址

ldr              r0, = AT91C_PMC_CSS_PLLB_CLK               

str              r0, [r1, #PMC_MCKR]       ;PMC_MCKR寄存器写入数值    

//通过测试状态寄存器 PMC_SR的第3位来判断时钟设置是否成功

mov          r4, #0x8

MCKR_Loop

         ldr               r3, [r1, #PMC_SR]

         and            r3, r4, r3   

         cmp     r3, #0x8

         bne             MCKR_Loop

 

//第二步,修改PMC_MCKR使其选择慢时钟SCK作为主机时钟源

ldr              r0, = AT91C_PMC_CSS_SLOW_CLK :OR:AT91C_PMC_PRES_CLK

str              r0, [r1, #PMC_MCKR]

mov          r4, #0x8

MCKR_Loop2

         ldr               r3, [r1, #PMC_SR]

         and            r3, r4, r3

         cmp     r3, #0x8

         bne             MCKR_Loop2

 

//为了节省功耗关闭PLLs

//实际上,在机器复位后PLLs 是被默认关闭的,但是在以前有一个boot程序已经运行过的情况//下,PLLs可能已经被打开,所以要在这个boot程序开始的时候要先关闭PLLs

ldr          r1, = AT91C_BASE_CKGR          ; 取得CKGR 的基地址

 

ldr          r0, = AT91C_CKGR_DIVA_0

str           r0, [r1, #CKGR_PLLAR]            : 关闭 PLLA

 

ldr          r0, = AT91C_CKGR_DIVB_0

str           r0, [r1, #CKGR_PLLBR]            : 关闭 PLLB

 

以上动作完成之后,系统的主机时钟源就是慢时钟。但是,系统正常运行时不可能用慢时钟作为时钟源,(比如此时用plla作为时钟源),就需要进一步的设置。

对于PLL时钟,它的时钟源是主振荡器时钟(即主时钟 main clock),所以要先将主时钟打开,代码如下:

//打开主时钟

//MOSCEN 主时钟使能位;OSCOUNT 指定慢时钟周期数作为主振荡器启动时间

ldr              r0, = AT91C_CKGR_MOSCEN:OR:AT91C_CKGR_OSCOUNT

str              r0, [r1, #CKGR_MOR]

选择主时钟作为主机时钟,设置时钟频率等工作等到后面用C语言来完成。这里将继续用汇编进行其余的初始化动作,直到运行至AT91F_LowLevelInit函数。

//为各种处理器模式设置堆栈

; 加载堆栈基地址

add     r0, pc,#-(8+.-StackData)  ; r0 = pc – 8 - . + StackData ,让r0指向StackData

ldmia   r0, {r1-r6}            ;r0指向的地址单元加载数据到r1~r6

 

;- Set up Supervisor Mode and set SVC Mode Stack

msr     cpsr_c, #ARM_MODE_SVC : OR : I_BIT : OR : F_BIT

bic      r1, r1, #3                  ; Insure word alignement

mov     sp, r1                      ; Init stack SYS

 

;- Set up Interrupt Mode and set IRQ Mode Stack

msr     CPSR_c, #ARM_MODE_IRQ : OR : I_BIT : OR : F_BIT

bic      r2, r2, #3                  ; 确保字对齐

mov     sp, r2                     ; 设置IRQ模式堆栈指针

 

;- Set up Fast Interrupt Mode and set FIQ Mode Stack

msr     CPSR_c, #ARM_MODE_FIQ : OR : I_BIT : OR : F_BIT

bic     r3, r3, #3                  ; Insure word alignement

mov    sp, r3                     ; Init stack FIQ

 

;- Set up Abort Mode and set Abort Mode Stack

msr     CPSR_c, #ARM_MODE_ABORT : OR : I_BIT : OR : F_BIT

bic      r4, r4, #3                 ; Insure word alignement

mov     sp, r4                    ; Init stack Abort

 

;- Set up Undefined Instruction Mode and set Undef Mode Stack

msr     CPSR_c, #ARM_MODE_UNDEF : OR : I_BIT : OR : F_BIT

bic      r5, r5, #3                 ; Insure word alignement

mov     sp, r5                    ; Init stack Undef

 

;- Set up user Mode and set Undef Mode Stack

msr     CPSR_c, #ARM_MODE_SYS : OR : I_BIT : OR : F_BIT

bic      r6, r6, #3                  ; Insure word alignement

mov     sp, r6                     ; Init stack Undef

 

b       EndInitStack

 

StackData

         DCD     AT91_SVC_Stack_Begin

         DCD     AT91_IRQ_Stack_Begin

         DCD     AT91_FIQ_Stack_Begin

         DCD     AT91_ABT_Stack_Begin

         DCD     AT91_UND_Stack_Begin

         DCD     AT91_USER_Stack_Begin

EndInitStack

 

; 补偿主振荡器启动时间

         ldr    r0, =0x00000010

LoopOsc

         subs    r0, r0, #1

         bhi     LoopOsc

 

; 调用C函数 AT91F_LowLevelInit()

         IMPORT    AT91F_LowLevelInit

 

         ldr       r0, = AT91F_LowLevelInit

         mov      lr, pc

         bx        r0

;-----------------------------------------------------

;       // CP15 控制寄存器

;-----------------------------------------------------

    MRC     p15, 0, r0, c1, c0,0    ; read cp15 control register (cp15 r1) in r0

    ldr           r3, =0xC0000080       ; Reset bit :Little Endian end fast bus mode

    ldr          r4, =0xC0000000       ; Set bit :Asynchronous clock mode, Not Fast Bus

    BIC      r0, r0, r3

    ORR     r0, r0, r4

    MCR     p15, 0, r0, c1, c0,0    ; write r0 in cp15 control registre (cp15 r1)

 

;-----------------------------------------------------

;       初始化C变量

;-----------------------------------------------------

 

         add        r2, pc,#-(8+.-CInitData)         ; @ where to read values (relative)

         ldmia        r2, {r0, r1, r3, r4}

 

         cmp       r0, r1                  ; Check that they are different

         beq       EndRW

LoopRW

         cmp       r1, r3                ; Copy init data

         ldrcc       r2, [r0], #4                        ;r0指向的地址加载数据到r2后,r2+4

         strcc       r2, [r1], #4                        ;r2中数据存储到r1指向的地址后,r1+4

         bcc        LoopRW

EndRW

 

         mov       r2, #0

LoopZI

         cmp       r3, r4                  ; Zero init

         strcc       r2, [r3], #4

         bcc        LoopZI

 

         b          EndInitC

 

CInitData

        IMPORT      |Image$$RO$$Limit|      ; ROM 代码结束处 (=ROM 数据开始处)

         IMPORT      |Image$$RW$$Base|      ; Base of RAM to initialise

         IMPORT      |Image$$ZI$$Base|       ; Base and limit of area

         IMPORT      |Image$$ZI$$Limit|       ; Top of zero init segment

 

         DCD     |Image$$RO$$Limit|      ; End of ROM code (=start of ROM data)

        DCD     |Image$$RW$$Base|      ; Base of RAM to initialise

        DCD     |Image$$ZI$$Base|       ; Base and limit of area

        DCD     |Image$$ZI$$Limit|       ; Top of zero init segment

EndInitC

 

;------------------------------------------------------------------------------

;- Branch on C code Main function (with interworking)

;----------------------------------------------------

;- Branch must be performed by an interworking call as either an ARM or Thumb

;- main C function must be supported. This makes the code not position-

;- independant. A Branch with link would generate errors

;------------------------------------------------------------------------------

         IMPORT      main

_main

__main

         EXPORT    _main

         EXPORT    __main

         ldr       r0, =main

         mov       lr, pc

         bx        r0                      ; 跳到mian() 函数中

 

;------------------------------------------------------------------------------

;- Loop for ever

;---------------

;- End of application. Normally, never occur.

;- Could jump on Software Reset ( B 0x0 ).

;------------------------------------------------------------------------------

End

         b           End

      END

由于之前打开了主时钟,但没有判断打开是否成功,所以AT91F_LowLevelInit首先通过AT91F_WaitForMainClockFrequency函数判断主时钟是否打开。代码略

 

主时钟打开之后,就可以进行真正的PLL时钟源设置,代码主体为AT91F_InitClocks函数。

由于时钟设置要求在一定的范围条件下,所以要首先判断是否满足时钟要求。主要分成4步:

1.先计算主时钟的频率,算法见datasheet

2.通过MainClock和预设值(见函数的输入参数)来判断频率是否满足要求。

3.如果满足要求则把预设值写入到PLL控制寄存器。

4.最后一步当然是修改主机时钟源为需要的PLL,同样,需要分成两步。

阅读(1540) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~