七、mini2440裸机程序之定时器中断(4)定时器实现

1.实验说明

        通过使用定时器0来实现1秒的定时功能 ,通过对定时器中断处理函数对灯光的状态进行取反来演示.

 

2.相关寄存器介绍

   

  定时器配置相关寄存器

    1)TCFG0

七、mini2440裸机程序之定时器中断(4)定时器实现_第1张图片

注:(PCLK =101.25MHz)

prescaler 0  =  249,divider value = 16

这样定时器输入时钟频率 = 101,250,000Hz/250/16  = 25,312Hz

综上所述 , 对于TCFG0的配置如下:

TCFG0 |= 249 =0xF9

 

    2)TCFG1

 七、mini2440裸机程序之定时器中断(4)定时器实现_第2张图片

注:

由TCFG0的讨论可以得知 , 这里MUX 0 = 0011b

所以对TCFG1的配置如下:

TCFG1 |= 3 ;

 

    3)TCON

七、mini2440裸机程序之定时器中断(4)定时器实现_第3张图片

注:

这个寄存器留在最后配置;

禁止dead zone操作 , 使能自动重载 , 关闭输出反相器 , 第一次要手动更新TCNTB0 ,开启定时器0功能 .

(定时器启动之后要把手动更新TCNTB0TCMPB0禁止掉)  .

综上所述对TCON的配置如下 :

启动定时器前 : TCON |=0x0B ;

启动定时器后 : TCON&= ~(1<<1) ;

 

    4)TCNTB0和TCMPB0

七、mini2440裸机程序之定时器中断(4)定时器实现_第4张图片

注:

    使计数1秒产生中断

TCNTB0 =  25312;

TCMPB0 = 0 ;

 

 

    5)TCNTO0

七、mini2440裸机程序之定时器中断(4)定时器实现_第5张图片

注:

通过读取这个寄存器可以获得当前计数器值.

 

  定时器中断相关介绍及寄存器

      1)相关仲裁器

七、mini2440裸机程序之定时器中断(4)定时器实现_第6张图片   

     2)SRCPND

七、mini2440裸机程序之定时器中断(4)定时器实现_第7张图片

注:

1清零 ,在中断服务子程序里 .

 

    3)INTPND

七、mini2440裸机程序之定时器中断(4)定时器实现_第8张图片

注:

1清零,在中断服务子程序里 ,并且要在对SRCPND清零之后.

 

    4)INTMOD


注:

INTMOD &= ~(1<<10) 直接采用复位默认值就行

 

    5)INTMSK


注:

INTMSK &= ~(1<<10)

 

    6)INTOFFSET


注:

在中断服务子程序里判断是否为定时器0中断 .

 

 

3.程序流程图设计

 

    1)主流程图:

 七、mini2440裸机程序之定时器中断(4)定时器实现_第9张图片

    2)中断服务程序流程图:

 七、mini2440裸机程序之定时器中断(4)定时器实现_第10张图片

    3)中断服务处理子函数流程图:

 



4.程序设计

 

    1)Makefile

timer.bin : head.o led_display.o
    arm-linux-ld -Ttimer.lds -o timer_elf $^
    arm-linux-objcopy -O binary -S timer_elf $@
    arm-linux-objdump -D -m arm timer_elf > timer.dis

%.o : %.S
    arm-linux-gcc -Wall  -O2 -c -o $@ $<

%.o : %.c
    arm-linux-gcc -Wall  -O2 -c -o $@ $<
clean:
    rm -f timer.dis timer.bin timer_elf *.o *.bak


    2)timer.lds

SECTIONS {
    first    0x00000000 : { head.o }
    second    0x30000000 : AT(2048) { led_display.o }
}


   3)head.S

@与内存相关
.equ    BWSCON   ,    0x48000000
.equ    BANKCON6 ,     0x4800001C
.equ    REFRESH  ,    0x48000024
.equ    BANKSIZE ,    0x48000028
.equ    MRSRB6     ,    0x4800002C

@与中断相关
.equ    INTMSK    ,    0x4A000008
.equ    SRCPND    ,    0x4A000000
.equ    INTPND    ,    0x4A000010

@与看门狗相关
.equ    WTCON    ,    0x53000000

@与灯光配置相关的
.equ    GPBCON    ,    0x56000010
.equ    GPBDAT    ,    0x56000014

@与定时器配置相关的
.equ    TCFG0    ,    0x51000000
.equ    TCFG1    ,    0x51000004
.equ    TCON    ,    0x51000008
.equ    TCNTB0    ,    0x5100000C
.equ    TCMPB0    ,    0x51000010
.equ    TCNTO0    ,    0x51000014    @read-only


@时钟相关寄存器
.equ    MPLLCON    ,    0x4C000004
.equ    UPLLCON    ,    0x4C000008
.equ    CLKDIVN    ,    0x4C000014
.equ    CAMDIVN ,    0x4C000018


.text
.global _start
_start:
/***********设置中断向量表*************/
    b    ResetInit    @复位异常入口
HandlerUndef:
    b    HandlerUndef    @未定义异常入口
HandlerSWI:
    b    HandlerSWI    @软中断异常入口
HandlerPabort:
    b    HandlerPabort    @取指中止异常入口
HandlerDabort:
    b    HandlerDabort    @数据中止异常入口
HandlerNotUsed:
    b    HandlerNotUsed    @保留

    b    HandlerIRQ    @中断异常入口
HandlerFIQ:
    b    HandlerFIQ    @快中断异常入口
/************END设置中断向量表***********/

ResetInit:
/*************关闭看门狗****************/
    ldr    r0 , =WTCON
    mov    r1 , #0x0
    str    r1 , [r0]
/************END关闭看门狗**************/


/**********初始化LED灯管脚************/
    @把LED1-4管脚置为输出
    ldr    r0 , =GPBCON
    ldr    r1 , [r0]        @把GPBCON里的内容加载到r1里
    ldr    r2 , =(0xFF<<10)
    bic    r1 , r1 ,r2    @操作数取反码或上r1,用于清零工作
    ldr    r2 , =(0x55<<10)
    orr    r1 , r1 , r2
    str    r1 , [r0]    
/***********END***************/    

    
/***********配置内存相关寄存器***********/
    ldr    lr , =InitSystemSp
    ldr    pc , =MemConfigure
/**********END配置内存相关寄存器*********/


/***********设置系统模式下的sp***********/
InitSystemSp:
    @复位默认进入系统模式
    ldr    sp , =0x34000000
/********END设置系统模式下的sp***********/


/********配置定时器0中断相关寄存器*******/
    ldr    r0 , =INTMSK
    ldr    r1 , [r0]
    bic    r1 , r1 , #(0x01<<10)
    str    r1 , [r0]
/******END配置定时器0中断相关寄存器******/


/*进入中断模式设置中断模式下的sp退出到系统模式
*使能IRQ中断*/    
    msr    cpsr_c , 0xd2        @进入中断模式,禁止中断,其中cpsr后的_c表示cpsr[7:0]
    ldr    sp , =0x33500000    @设置sp
    msr    cpsr_c , 0x5f        @退出到系统模式,使能IRQ中断
/*END进入中断模式设置中断模式下的sp退出到系统模式*/


/***********配置时钟相关寄存器***********/
    ldr    lr , =CopyToSdram
    ldr    pc , =ClkConfigure
/**********END配置时钟相关寄存器*********/



/************拷贝中断处理子函数到内存****/
CopyToSdram:
    ldr    lr , =InitTimer0
    ldr    pc , =copy_bootsram_to_sdram
/*******************END******************/




/*配置定时器0相关寄存器使定时1秒进入中断*/
InitTimer0:
    ldr    lr , =halt_loop
    ldr    pc , =Timer0Configure
/*******************END******************/

/*************等待中断******************/
halt_loop:
    b    halt_loop
/*********************END****************/    
    
    
    
    
    
/*************IRQ中断服务子程序**********/
HandlerIRQ:

    @因为在产生中断异常时,lr存的是当前指令的下一条指令,所以要减四
    sub    lr , lr , #4
    
    @把相关寄存器压入中断模式下的栈
    @db表示sp每次传送内容前减1
    stmdb    sp! , {r0-r12 , lr}
    
    @禁止IRQ中断
    mrs    r1 , cpsr_all
    orr    r1 , r1 , #(1<<7)
    msr    cpsr_all , r1
    
    @调用中断服务处理函数
    ldr    lr , =IRQ_Return
    ldr    pc , =main
    
IRQ_Return:
    @把栈里面的内容推出到相应寄存器里,并把lr推到pc寄存器实现跳转
    @ia表示每次传送后加1 , 当寄存器列表中包含了pc寄存器,选用^为后缀,就会把spsr拷贝到cpsr
    ldmia    sp! , {r0-r12 , pc}^

        
/********END IRQ中断服务子程序***********/



/***********配置时钟相关寄存器***********/
ClkConfigure:
    @UPLL选择MDIV=0x38,PDIV=2,SDIV=1.得UPLL clock=96MHz
    @这里先设置UPLL是为了与设置MPLL隔开至少7个NOP的时间间隔
    ldr    r0 , =UPLLCON
    ldr    r1 , =(0x38<<12)|(0x02<<4)|(0x01<<0)
    str    r1 , [r0]
    
    @分频比FCLK:HCLK:PCLK=1:4:4 , UCLK=UPLL_clock/2=48MHz
    ldr    r0 , =CLKDIVN
    mov    r1 , #(0x01<<3)|(0x02<<1)|(0x00<<0)
    str    r1 , [r0]    
    ldr    r0 , =CAMDIVN
    ldr    r1 , [r0]
    bic    r1 , r1 , #(0x03<<8)
    str    r1 , [r0]
    
    @因为HDIVN不是0 , 所以CPU总线模式要从高速总线模式改变
    @为异步总线模式
    mrc    p15 , 0 , r1 , c1 , c0 , 0
    orr    r0 , r0 , #0xC0000000
    mcr    p15 , 0 , r0 , c1 , c0 , 0

    @MPLL选择MDIV=0x7f,PDIV=2,SDIV=1,得MPLL clock=405MHz
    ldr    r0 , =MPLLCON
    ldr    r1 , =(0x7f<<12)|(0x02<<4)|(0x01<<0)
    str    r1 , [r0]
    
    bx    lr
/***************END*************************/


    
/*配置定时器0相关寄存器使定时1秒进入中断*/
Timer0Configure:
    ldr    r0 , =TCFG0
    ldr    r1 , =0xF9
    str    r1 , [r0]
    
    ldr    r0 , =TCFG1
    ldr    r1 , =0x03
    str    r1 , [r0]

    ldr    r0 , =TCNTB0
    ldr    r1 , =0x62E0
    str    r1 , [r0]
    
    ldr    r0 , =TCMPB0
    mov    r1 , #0x0
    str    r1 , [r0]    
    
    @第一次手动更新TCNTB0和TCMPB0
    ldr    r0 , =TCON
    mov    r1 , #(0x01<<1)
    str    r1 , [r0]
    
    @手动更新TCNTB0和TCMPB0禁止,使能自动重载,启动定时器0
    mov    r1 , #0x09
    str    r1 , [r0]
    
    bx    lr
    
/******************END******************/



/*******内存初始化子程序*********/
MemConfigure:
    @BWSCON[27:24] = 0 0 10B
    ldr    r0 , =BWSCON
    ldr    r1 , [r0]
    ldr    r2 , =(0x0F<<24)
    bic    r1 , r1 , r2
    ldr    r2 , =(0x02<<24)
    orr    r1 , r1 , r2
    str    r1 , [r0]    

    @BANKCON6[16:15]=11B;BANKCON6[3:0]=00 01B
    ldr    r0 , =BANKCON6
    ldr    r1 , [r0]
    ldr    r2 , =(0x03<<15)
    bic    r1 , r1 , r2
    orr    r1 , r1 , r2
    ldr    r2 , =0x0F
    bic    r1 , r1 , r2
    ldr    r2 , = 0x01
    orr    r1 , r1 , r2
    str    r1 , [r0]

    @这里的Trp要大于20ns , Trc要大于70ns,HCLK=101.25MHz
    @故时钟周期=1s/HCLK=9.8ns,Trp*9.8>20ns ==> Trp>=3 ==> Trp域=01b
    @Trp*9.8+Tsrc*9.8>70ns ==> Tsrc>=5 ==> Tsrc域=01b
    @REFRESH[23:18] = 1 0 01 01B;REFRESH[10:0] = 0x4E8

    ldr    r0 , =REFRESH
    ldr    r1 , [r0]
    ldr    r2 , =(0x3F<<18)
    bic    r1 , r1 , r2
    ldr    r2 , =(0x25<<18)
    orr    r1 , r1 , r2
    ldr    r2 , =0x7FF
    bic    r1 , r1 , r2
    ldr    r2 , =0x4E9
    orr    r1 , r1 , r2
    str    r1 , [r0]

    @BANKSIZE[7:0] = 1 0 1 1 0 001 B
    ldr    r0 , =BANKSIZE
    ldr    r1 , [r0]
    ldr    r2 , =0xFF
    bic    r1 , r1 , r2
    ldr    r2 , =0xB1
    orr    r1 , r1 , r2
    str    r1 , [r0]    

    @MRSRB6[11:0] = 0 00 011 0 000 B
    ldr    r0 , =MRSRB6
    ldr    r1 , [r0]
    ldr    r2 , =0x3FF
    bic    r1 , r1 , r2
    ldr    r2 , =0x030
    orr    r1 , r1 , r2
    str    r1 , [r0]    

    bx    lr    @函数返回
/******END内存初始化子程序*******/



/******拷贝后2048到4096之间的代码到sdram*******/
copy_bootsram_to_sdram:
    ldr    r0 , =0x800
    ldr    r1 , =0x30000000
    ldr    r2 , =0x1000
copy:
    ldr    r3 , [r0] , #4
    str    r3 , [r1] , #4
    cmp    r0 , r2
    bne    copy
    bx    lr
/*****END拷贝前4K代码到sdram*****/


     4)led_display.c
#define    GPBCON    (*(volatile unsigned long *)0x56000010)
#define    GPBDAT    (*(volatile unsigned long *)0x56000014)

#define  INTOFFSET    (*(volatile unsigned long *)0x4A000014)
#define SRCPND        (*(volatile unsigned long *)0x4A000000)
#define INTPND        (*(volatile unsigned long *)0x4A000010)

int main()
{
    if(INTOFFSET == 10){
        GPBDAT ^= (0xF<<5);    //LED灯状态取反            
    }
    SRCPND = SRCPND;
    INTPND = INTPND;
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


你可能感兴趣的:(七、mini2440裸机程序之定时器中断(4)定时器实现)