关于时钟体系和各类时钟部件

    技术2026-06-19  12

    写在前面:觉得这章比较简单,没有花较大篇幅来讲,很多寄存器的相关用法可以参照S3C2440的官方手册,很容易看懂 1系统时钟 (1) FCLK:用于CPU核 HCLK:用于AHB总线上设备:CPU核、存储器控制器、中断控制器、LCD控制器、DMA和USB主机模块 PCLK:用于APB总线上设备:WATCHDOG、IIS、I2C、PWM定时器、MMC接口、ADC、UART、GPIO、RTC和SPI (2 )开发板时钟频率为12 MHZ,通过PLL提高系统时钟:MPLL和UPLL(S3C2440);UPLL用于USB设备,MPLL用于FCLK、HCLK、PLCK (3 )上电→FCLK=Fin(外部输入时钟)→设置MPLL(Lock Time:长短由寄存器LOCKTIME设定)→新的时钟输出正常 (4)几个重要寄存器 MPLLCON寄存器用于设置FCLK与Fin的倍数 CLKDIVN寄存器用于设置FCLK、HCLK、PCLK三者的比例 2 PWM定时器 (1)5个16位的定时器,其中定时器0、1、2、3有PWM功能,即它们都有一个输出引脚,可以通过定时器来控制引脚周期性的高、低电平变化;定时器4没有输出引脚 (2)PLCK→2个8位预分频器(定时器0、1共用第一个定时器2、3、4共用第二个;输出2分频,4分频,8分频,16分频或者外部时钟TCLK0/TCLK1) TCFG0:经过分频器出来的时钟频率:PLCK/(TCFG0或TCFG0+1) TCFG1设定相应定时器为经过分频器出来的时钟频率的几分频 定时器工作频率= PLCK/(TCFG0或TCFG0+1)/几分频 (3)TCMPn=TCMPBn,TCNTn=TCNTBn→while(TCNTn==TCMPn) ~TOUTn →while(TCNTn==0) ~TOUTn,并触发中断(若中断使能的话),且如果在TCON寄存器中将定时器设为“自动加载”,则TCMPn=TCMPBn,TCNTn=TCNTBn 输出管脚TOUTn默认为高电平,可以通过TCON改变,可能通过读取TCNTOn寄存器得知TCNTn的值 (4)TCON寄存器:使用参考S3C2440手册 在第一次使用定时器时,要设置“手动更新”位为1以使TCNTBn/TCMPBn的值装入内部寄存器TCNTn、TCMPn中,下一次如果还要设置这一位,需要先将其清0 3 WATCHDOG定时器 (1)PLCK→2个8位预分频器(输出16分频,32分频,64分频,128分频或者外部时钟TCLK0/TCLK1) 初始计数值写入 WTCNT→while(WTCNT==0)自动重新装载WTCNT=WTDAT,并可以产生中断信号,可以输出复位信号 (2)WATDOG定时器工作频率=PCLK/(WTCON+1)/几分频 大部分功能都在WTCON中设定 (3)在启动WATDOG定时器前,必须往这个寄存器定入初始计数值 4:MPLL和定时器操作实验:完整代码: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寄存器,为MDIV,为PDIV,为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 = 0x22011110; //BWSCON p = 0x00000700; //BANKCON0 p = 0x00000700; //BANKCON1 p = 0x00000700; //BANKCON2 p = 0x00000700; //BANKCON3 p = 0x00000700; //BANKCON4 p = 0x00000700; //BANKCON5 p = 0x00018005; //BANKCON6 p = 0x00018005; //BANKCON7 /* REFRESH, * HCLK=12MHz: 0x008C07A3, * HCLK=100MHz: 0x008C04F4 */ p = 0x008C04F4; /* REFRESH=0x008C0000+R_CNT R_CNT=2^11+1-SDRAM时钟频率(MHZ)*SDRAM刷新周期(uS) p = 0x000000B1; //BANKSIZE p = 0x00000030; //MRSRB6 p = 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)); }

    本文地址:http://baidianfeng.cqdb.net/66869330-1276010585 转载请注明出处

    最新回复(0)