Chinaunix首页 | 论坛 | 博客
  • 博客访问: 45753
  • 博文数量: 11
  • 博客积分: 490
  • 博客等级: 下士
  • 技术积分: 140
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-24 11:23
文章分类
文章存档

2011年(1)

2009年(10)

我的朋友

分类: LINUX

2009-08-12 13:20:14

S3C2440中断体系结构:外部中断实验

写在前面:觉得这章比较简单,没有花较大篇幅来讲,很多寄存器的相关用法可以参照S3C2440的官方手册,很容易看懂

1系统时钟

(1) FCLK:用于CPU

   HCLK:用于AHB总线上设备:CPU核、存储器控制器、中断控制器、LCD控制器、DMAUSB主机模块

   PCLK:用于APB总线上设备:WATCHDOGIISI2CPWM定时器、MMC接口、ADCUARTGPIORTCSPI

(2 )开发板时钟频率为12 MHZ,通过PLL提高系统时钟:MPLLUPLLS3C2440);UPLL用于USB设备,MPLL用于FCLKHCLKPLCK

(3 )上电→FCLK=Fin(外部输入时钟)→设置MPLLLock Time:长短由寄存器LOCKTIME设定)→新的时钟输出正常

(4)几个重要寄存器

 MPLLCON寄存器用于设置FCLKFin的倍数

 CLKDIVN寄存器用于设置FCLKHCLKPCLK三者的比例

2 PWM定时器

 (1)516位的定时器,其中定时器0123PWM功能,即它们都有一个输出引脚,可以通过定时器来控制引脚周期性的高、低电平变化;定时器4没有输出引脚

2PLCK28位预分频器(定时器01共用第一个定时器234共用第二个;输出2分频,4分频,8分频,16分频或者外部时钟TCLK0/TCLK1

TCFG0:经过分频器出来的时钟频率:PLCK/TCFG0[70]TCFG0[158]+1

TCFG1设定相应定时器为经过分频器出来的时钟频率的几分频

定时器工作频率= PLCK/TCFG0[70]TCFG0[158]+1/几分频

3TCMPn=TCMPBn,TCNTn=TCNTBnwhile(TCNTn==TCMPn)  ~TOUTn while(TCNTn==0) ~TOUTn,并触发中断(若中断使能的话),且如果在TCON寄存器中将定时器设为“自动加载”,则TCMPn=TCMPBn,TCNTn=TCNTBn

  输出管脚TOUTn默认为高电平,可以通过TCON改变,可能通过读取TCNTOn寄存器得知TCNTn的值

 4TCON寄存器:使用参考S3C2440手册

      在第一次使用定时器时,要设置“手动更新”位为1以使TCNTBn/TCMPBn的值装入内部寄存器TCNTnTCMPn中,下一次如果还要设置这一位,需要先将其清0

3 WATCHDOG定时器

1PLCK28位预分频器(输出16分频,32分频,64分频,128分频或者外部时钟TCLK0/TCLK1

   初始计数值写入 WTCNTwhile(WTCNT==0)自动重新装载WTCNT=WTDAT,并可以产生中断信号,可以输出复位信号

2WATDOG定时器工作频率=PCLK/WTCON[158]+1/几分频

 大部分功能都在WTCON中设定

3)在启动WATDOG定时器前,必须往这个寄存器定入初始计数值

4MPLL和定时器操作实验:完整代码:timer.tar.gz     timernoMPLL.tar.gz(使用系统默认的时钟)

(1)       设置/启动MPLL

#define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))

/*

 * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV

 * 有如下计算公式:

 *  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)

 *  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)

 *  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV

 * 对于本开发板,Fin = 12MHz

 * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,

 * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz

 */

void clock_init(void)

{

    // LOCKTIME = 0x00ffffff;   // 使用默认值即可

    CLKDIVN  = 0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

 

    /* 如果HDIVN非0,CPU的总线模式应该从fast bus mode变为asynchronous bus mode */

__asm__(

    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */

    "orr    r1, r1, #0xc0000000\n"          /* 设置为asynchronous bus mode */

    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */

    );

 

    /* 判断是S3C2410还是S3C2440 */

    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

    {

        MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */

    }

    else

    {

        MPLLCON = S3C2440_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */

    }      

}

(2)       设置存储控制器

void memsetup(void)

{

    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

 

    /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

     * 写在数组中,是因为要生成位置无关的代码,使得这个函数可以在被复制到

     * SDRAM之前就可以在steppingstone中运行

     */

    /* 存储控制器13个寄存器的值 */

    p[0] = 0x22011110;     //BWSCON

    p[1] = 0x00000700;     //BANKCON0

    p[2] = 0x00000700;     //BANKCON1

    p[3] = 0x00000700;     //BANKCON2

    p[4] = 0x00000700;     //BANKCON3 

    p[5] = 0x00000700;     //BANKCON4

    p[6] = 0x00000700;     //BANKCON5

    p[7] = 0x00018005;     //BANKCON6

    p[8] = 0x00018005;     //BANKCON7

   

    /* REFRESH,

     * HCLK=12MHz:  0x008C07A3,

     * HCLK=100MHz: 0x008C04F4

     */

p[9]  = 0x008C04F4;

/* REFRESH=0x008C0000+R_CNT

R_CNT=2^11+1-SDRAM时钟频率(MHZ)*SDRAM刷新周期(uS)

    p[10] = 0x000000B1;     //BANKSIZE

    p[11] = 0x00000030;     //MRSRB6

    p[12] = 0x00000030;     //MRSRB7

}

(3)初始化定时器0

/*

 * Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}

 * {prescaler value} = 0~255

 * {divider value} = 2, 4, 8, 16

 * 本实验的Timer0的时钟频率=100MHz/(99+1)/(16)=62500Hz

 * 设置Timer0 0.5秒钟触发一次中断:

 */

void timer0_init(void)

{

    TCFG0  = 99;        // 预分频器0 = 99       

    TCFG1  = 0x03;      // 选择16分频

    TCNTB0 = 31250;     // 0.5秒钟触发一次中断

    TCON   |= (1<<1);   // 手动更新

    TCON   = 0x09;      // 自动加载,清手动更新位,启动定时器0

}

 

4)定时器中断使能

/*

 * 定时器0中断使能

 */

void init_irq(void)

{       

    // 定时器0中断使能

    INTMSK   &= (~(1<<10));

}

 

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

chinaunix网友2009-11-30 20:52:34

看了你写的程序,很精简!不错! 有个问题,不明白,为什么要讲代码运行在SRAM空间,该不会是与运行速度相关吧,而且片内的4kb够用啊。 我参考你的程序,相同的设置,只不过我没用到片外的SRAM存储器,下载没反应,不清楚是什么问题,恳请指教一下。

chinaunix网友2009-08-13 14:52:30

TCON |= (1<<1); // 手动更新 TCON = 0x09; // 自动加载,清“手动更新”位,启动定时器0 请问一下这两句是不是重复了啊? 如果没TCON |= (1<<1);会有问题吗?