- 前言
这篇主要介绍arm9时钟与定时器方面,根据s3c2440手册第七章的内容来看,涉及到不少的知识点,power管理、时钟、usb时钟、camera等,接下来只介绍时钟方面,其余部分以后再说 - 简介
系统时钟是整个电路的心脏,了解系统时钟结构对于后面学习定时器,UART等使用具有非常重要的作用,总体来说,与s3c2440处理器有关的时钟主要有4种: FIN, FCLK, HCLK和PCLK
1.FIN:外部输入晶振频率
2.FCLK: 主要用于CPU核
3.HCLK:主要用于与AHB总线互连的设备(如存储控制器, LCD控制器, 中断控制器及DMA等)上
4.PCLK:主要用于与APB总线互连的低速设备(如定时器, UART, ADB等)上 -
图解时钟
s3c2440处理器系统时钟分为两个部分, 外部有时钟输入引脚,内部用2个锁相环将外部输入时钟倍频到处理器工作说需要的时钟, 外部时钟频率太高容易受到外部的干扰,因此一般外部时钟频率比较低, 如下图:
上图*有三部分需要讲解:
1.时钟源选择
在第七章的开始部分,就介绍了2440选择时钟的配置,主要根据CPU的OM2,OM3输入引脚的电平决定:
在一般的开发板上,主时钟和USB时钟全部是由外部的12M晶体振荡器提供的。所以在定制硬件的时候,直接将OM3和OM2接于地上,以选择外部的晶振作为主时钟源和USB时钟源。
2.锁相环MPLL+分频比
锁相环可以理解为时钟频率放大电路,涉及到两个寄存器
■MPLLCON: 控制FCLK与FIN的比例关系
MPLLCON与UPLLCON寄存器是一样的,统称为PLLCON寄存器,那么,如何计算FCLK呢,根据手册可知:
上图中的Mpll即我们想要的FCLK,即MPLL(FCLK) = (2 * 100 * 12)/(6 * 2^1), 因为我们想把FCLK(Mpll)设置为200MHZ,经过计算可以得到, MDIV=92, PDIV=4, SDIV=1。
■CLKDIVN:用于控制FCLK, HCLK和PCLK之间的比例关系
即 CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
注意,手册上有这么一句话:
如果HDIVN为1的话,需要更改总线的模式,因为如果HDIVN为1,但是CPU bus mode为fast bus mode,那么它的频率将变为HCLK即100MHZ的频率(200MHz->100MHz,搞成节能了)
所以时钟初始化如下:// 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" /* 写入控制寄存器 */
);
MPLLCON = ((0x5c<<12)|(0x04<<4)|(0x01))上面代码注释中,关于LOCKTIME的赋值,这个又是怎么回事儿呢,还是根据手册
图中很清晰,刚开始上电, 在没有检测OM引脚电平之前,FCLK = 外部输入时钟OSC(FIN)
之后arm核检测到OM引脚电平后,根据我们设定的寄存器MPLLCON的值MPLL锁相环启作用,一点点开始倍频,后经过Lock Time时间后倍频到我们想要的值,所以在这里我们默认值即可(0xFFFFFFFF)
UCLK先不用考虑, USB1.0/2.0的正常工作频率为48MHZ
3.UPLL锁相环
将外部时钟倍频到USB设备正常工作所需要的时钟频率, 工作原理与上面类似
以上,最终效果如下图:
以上关于2440时钟的配置就讲完了,接下来讲下定时器 - 定时器
由上面可知,定时器是ABP总线设备,在PCLK的时钟频率下工作,s3c2440有5个16位定时器,定时器0,1,2,3有脉冲调制(PWM)功能, 因此这4个定时器也被称为PWM定时器,定时器4是一个内部定时器,无外部输出引脚,定时器的时钟源虽然是PCLK,但是还得通过内部的两个分频器分频后, 才能得到想要的工作频率,然后输出作为定时器的工作的时钟,定时器0,1公用一个分频器,其他3个定时器公用另一个分频器,如下图
虽然定时器比较多,但是工作原理相同,只需要理解一个定时器工作原理即可, 对于某一个定时器,其内部原理如图:
■TCON:用于控制定时器的开关等操作
■TCMPBn,TCNTBn:用于存储定时器的比较值与初始值(缓存)
■TCMPn, TCNTn:定时器内部寄存器,用户无需进行操作, 当TCON的“手动更新位置1”,即TCMPBn,TCNTBn的值就会加载到TCMPn, TCNTn
■TCNTOn:查看当前定时器的计数情况,即当前TCNTn的值 - 定时器的工作原理描述,以定时器0为例:
1.首先,将TCMPB0,TCNTB0附初值
2.然后,设置定时控制器TCON,将TCON的第1位置1(手动更新位), 这样TCMPB0,TCNTB0赋值给TCMPB0,TCNTB0
3.启动定时器–>设置TCON第3位为1(当TCNT0的值减到0时,TCMPB0的值会自动加载到寄存器TCMP0和TCNT0中), 第0位为1(开启定时器)
4.此时,定时器会减1计数, 即TCNT0进行减1计数, 当TCMP0与TCNT0相等时, TOUT0翻转
之后介绍一下相关的寄存器在手册中的定义:
■TCON:对于定时器0来讲:
其他的寄存器都是可以存储16位大小的值 -
定时器的分频
前面提到了定时器0的使用方法,但是没有提到其最终的工作所需要频率(1s中能记多少个数)
从上图中可以看到(以时钟0为例),定时器挂接如APB总线上,有两个分频器,一级分频器所对应的寄存器 TCFG0
由上图可知TCFG0不是一个定时器对应一个(不要误以为TCFG0对应定时器0),TCFG0控制2个一级的定时器分频器,其中的0-7位对应定时器0,1(与最上面定时器那个大图相吻合)的分频器,
我们还可以获取信息,最终的定时器的频率 Frequency = PCLK /{prescaler value + 1} / { divider value}
TCFG0的0-7位设置了prescaler value,即目前能得出f1 = PCLK /{prescaler value + 1}
接下来是2级分频器,通过上图由TCFG1控制
对于上面的分频参数是为了下面更好的举例,当然不是绝对要设置成这个值
例:我们想要定时器0的输入时钟为62.5kHz,即1s计数62500次
因为PCLK=50MHz, 则50MHz/62.5KHz = 800,即需要进行800的分频
所以一级分频系数为100,二级分频系数为8即可满足要求,
即 62500 = 50MHz/{99 + 1} /{ 8 }
所以如果想要定时器0,1s中产生一次中断,可以这么写void timer0_init(void)
{
TCFG0 = 99; // 预分频器0 = 99
TCFG1 = 0x02; // 选择8分频
TCNTB0 = 62500; // 1秒钟触发一次中断
TCMPB0 = 0;
TCON |= (1<<1); // 手动更新(将TCNTB0,TCMPB0更新入TCNT0, TCMP0)
TCON = 0x09; // 自动加载,清“手动更新”位,启动定时器0
} -
PWM功能
对于定时器0来讲,上面的例子中TCNT0 1s内减到0,则TOUT0反转(电平变化), 但是定时器0还有个特性,就是如果TCNT0减到与比较值TCMP0相等,则TOUT0也发生反转,也就是说上面的例子将 TCMPB0 改成31250后,则TCNT0从62500减到31250(与TCMP0相等)TOUT0发生一次反转(用时0.5s),TCNT0减到0又发生反转(用时0.5s),这样,1s内发生两次反转,如此循环,输出引脚0.5s反转一次,即占空比50%(波形0.5秒为高电平,0.5秒为低电平这样循环的波形)void timer0_init(void)
{
TCFG0 = 99; // 预分频器0 = 99
TCFG1 = 0x02; // 选择8分频
TCNTB0 = 62500; // 1秒钟触发一次中断
TCMPB0 = 31250;
TCON |= (1<<1); // 手动更新(将TCNTB0,TCMPB0更新入TCNT0, TCMP0)
TCON = 0x09; // 自动加载,清“手动更新”位,启动定时器0
}注意,如果将上面代码TCMPB0=31250,改为别的值,比如TCNTB0 /4,则输出的波形一定发生变化(比如0.25秒为高电平,0.75s为低电平这样循环的波形),即占空比也发生变化,这就是所谓的PWM功能
相关文章
- 云计算推进企业管理深化,私有云将会深入企业
- iOS开发——实用OC篇&多种定时器详细介绍
- 深入剖析 redis 事件驱动
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
- 《深入理解Nginx》阅读与实践(二):配置项的使用
- 【IScroll深入学习】解决IScroll疑难杂症
- JavaScript是如何工作的02:深入V8引擎&编写优化代码的5个技巧
- 《深入理解Java虚拟机》第三章读书笔记(三)——经典垃圾回收器
- Java并发基础02. 传统线程技术中的定时器技术
- js:定时器setInterval、clearInterval的使用