首页 > 代码库 > 实验七--时钟

实验七--时钟

一。平台

  系统:ubuntu12.04

  开发板:jz2440

  编译器:gcc

二。时钟系统

     后补上

三。代码

Makefile:

 1 objs := head.o init.o interrupt.o main.o 2  3 timer.bin: $(objs) 4     arm-linux-ld -Ttimer.lds -o timer_linux $^ 5     arm-linux-objcopy -O binary -S timer_linux $@ 6     arm-linux-objdump -D -m arm timer_linux > timer.dis 7      8 %.o:%.c 9     arm-linux-gcc -Wall -O2 -c -o $@ $<10 11 %.o:%.S12     arm-linux-gcc -Wall -O2 -c -o $@ $<13 14 clean:15     rm -f timer.bin timer_linux timer.dis *.o        16     

head.S

 1 @****************************************************************************** 2 @ File:head.S 3 @ 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数 4 @******************************************************************************        5     6 .extern     main 7 .text  8 .global _start  9 _start:10 @******************************************************************************       11 @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用12 @******************************************************************************       13     b   Reset14 15 @ 0x04: 未定义指令中止模式的向量地址16 HandleUndef:17     b   HandleUndef 18  19 @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式20 HandleSWI:21     b   HandleSWI22 23 @ 0x0c: 指令预取终止导致的异常的向量地址24 HandlePrefetchAbort:25     b   HandlePrefetchAbort26 27 @ 0x10: 数据访问终止导致的异常的向量地址28 HandleDataAbort:29     b   HandleDataAbort30 31 @ 0x14: 保留32 HandleNotUsed:33     b   HandleNotUsed34 35 @ 0x18: 中断模式的向量地址36     b   HandleIRQ37 38 @ 0x1c: 快中断模式的向量地址39 HandleFIQ:40     b   HandleFIQ41 42 Reset:                  43     ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈44     bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启45     bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK46     bl  memsetup            @ 设置存储控制器以使用SDRAM47     bl  copy_steppingstone_to_sdram     @ 复制代码到SDRAM中48     ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行49 on_sdram:50     msr cpsr_c, #0xd2       @ 进入中断模式51     ldr sp, =4096           @ 设置中断模式栈指针52 53     msr cpsr_c, #0xdf       @ 进入系统模式54     ldr sp, =0x34000000     @ 设置系统模式栈指针,55 56     bl  init_led            @ 初始化LED的GPIO管脚57     bl  timer0_init         @ 初始化定时器0   58     bl  init_irq            @ 调用中断初始化函数,在init.c中59     msr cpsr_c, #0x5f       @ 设置I-bit=0,开IRQ中断60     61     ldr lr, =halt_loop      @ 设置返回地址62     ldr pc, =main           @ 调用main函数63 halt_loop:64     b   halt_loop65 66 HandleIRQ:67     sub lr, lr, #4                  @ 计算返回地址68     stmdb   sp!,    { r0-r12,lr }   @ 保存使用到的寄存器69                                     @ 注意,此时的sp是中断模式的sp70                                     @ 初始值是上面设置的409671     72     ldr lr, =int_return             @ 设置调用ISR即EINT_Handle函数后的返回地址  73     ldr pc, =Timer0_Handle          @ 调用中断服务函数,在interrupt.c中74 int_return:75     ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr76     

 

init.c

  1 /*  2  * init.c: 进行一些初始化  3  */   4   5 #include "s3c24xx.h"  6    7 void disable_watch_dog(void);  8 void clock_init(void);  9 void memsetup(void); 10 void copy_steppingstone_to_sdram(void); 11 void init_led(void); 12 void timer0_init(void); 13 void init_irq(void); 14  15 /* 16  * 关闭WATCHDOG,否则CPU会不断重启 17  */ 18 void disable_watch_dog(void) 19 { 20     WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可 21 } 22  23 #define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00)) 24 #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02)) 25 /* 26  * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV 27  * 有如下计算公式: 28  *  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s) 29  *  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) 30  *  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV 31  * 对于本开发板,Fin = 12MHz 32  * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4, 33  * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz 34  */ 35 void clock_init(void) 36 { 37     // LOCKTIME = 0x00ffffff;   // 使用默认值即可 38     CLKDIVN  = 0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 39  40     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */ 41 __asm__( 42     "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */  43     "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */ 44     "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */ 45     ); 46  47     /* 判断是S3C2410还是S3C2440 */ 48     if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002)) 49     { 50         MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */ 51     } 52     else 53     { 54         MPLLCON = S3C2440_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */ 55     }        56 } 57  58 /* 59  * 设置存储控制器以使用SDRAM 60  */ 61 void memsetup(void) 62 { 63     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE; 64  65     /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值 66      * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到 67      * SDRAM之前就可以在steppingstone中运行 68      */ 69     /* 存储控制器13个寄存器的值 */ 70     p[0] = 0x22011110;     //BWSCON 71     p[1] = 0x00000700;     //BANKCON0 72     p[2] = 0x00000700;     //BANKCON1 73     p[3] = 0x00000700;     //BANKCON2 74     p[4] = 0x00000700;     //BANKCON3   75     p[5] = 0x00000700;     //BANKCON4 76     p[6] = 0x00000700;     //BANKCON5 77     p[7] = 0x00018005;     //BANKCON6 78     p[8] = 0x00018005;     //BANKCON7 79      80     /* REFRESH, 81      * HCLK=12MHz:  0x008C07A3, 82      * HCLK=100MHz: 0x008C04F4 83      */  84     p[9]  = 0x008C04F4; 85     p[10] = 0x000000B1;     //BANKSIZE 86     p[11] = 0x00000030;     //MRSRB6 87     p[12] = 0x00000030;     //MRSRB7 88 } 89  90 void copy_steppingstone_to_sdram(void) 91 { 92     unsigned int *pdwSrc  = http://www.mamicode.com/(unsigned int *)0; 93     unsigned int *pdwDest = (unsigned int *)0x30000000; 94      95     while (pdwSrc < (unsigned int *)4096) 96     { 97         *pdwDest = *pdwSrc; 98         pdwDest++; 99         pdwSrc++;100     }101 }102 103 /*104  * LED1-4对应GPB5、GPB6、GPB7、GPB8105  */106 #define GPB5_out        (1<<(5*2))      // LED1107 #define GPB6_out        (1<<(6*2))      // LED2108 #define GPB7_out        (1<<(7*2))      // LED3109 #define GPB8_out        (1<<(8*2))      // LED4110 111 #define GPFCON              (*(volatile unsigned long *)0x56000050)112 113 #define    GPF4_out    (1<<(4*2))114 #define    GPF5_out    (1<<(5*2))115 #define    GPF6_out    (1<<(6*2))116 117 118 /*119  * K1-K4对应GPG11、GPG3、GPF2、GPF3120  */121 #define GPG11_eint      (2<<(11*2))     // K1,EINT19122 #define GPG3_eint       (2<<(3*2))      // K2,EINT11123 #define GPF3_eint       (2<<(3*2))      // K3,EINT3124 #define GPF2_eint       (2<<(2*2))      // K4,EINT2125  126 void init_led(void)127 {128     GPFCON = GPF4_out|GPF5_out|GPF6_out;        // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出129 }130 131 /*132  * Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}133  * {prescaler value} = 0~255134  * {divider value} = 2, 4, 8, 16135  * 本实验的Timer0的时钟频率=100MHz/(99+1)/(16)=62500Hz136  * 设置Timer0 0.5秒钟触发一次中断:137  */138 void timer0_init(void)139 {140     TCFG0  = 99;        // 预分频器0 = 99        141     TCFG1  = 0x03;      // 选择16分频142     TCNTB0 = 31250;     // 0.5秒钟触发一次中断143     TCON   |= (1<<1);   // 手动更新144     TCON   = 0x09;      // 自动加载,清“手动更新”位,启动定时器0145 }146 147 /*148  * 定时器0中断使能149  */ 150 void init_irq(void)151 {        152     // 定时器0中断使能153     INTMSK   &= (~(1<<10));154 }

interrupt.h

1 void EINT_Handle();

interrupt.c

 1 #include "s3c24xx.h" 2  3 void Timer0_Handle(void) 4 { 5     /* 6      * 每次中断令4个LED改变状态 7      */ 8     if(INTOFFSET == 10) 9     {10         GPFDAT = ~(GPFDAT & (0x7 << 4));11     }12     //清中断13     SRCPND = 1 << INTOFFSET;14     INTPND = INTPND;     15 }

链接脚本:

1 SECTIONS {2     . = 0x30000000;3     .text          :   { *(.text) }4     .rodata ALIGN(4) : {*(.rodata)} 5     .data ALIGN(4) : { *(.data) }6     .bss ALIGN(4)  : { *(.bss)  *(COMMON) }7 }

main.c  和 s3c24xx.h上面都有,这里省去

 

实验七--时钟