(1)定时器与计数器。计数器是用来计数的(每隔一个固定时间会计一个数);因为计数器的计数时间周期是固定的,因此到了一定时间只要用计数值×计数时间周期,就能得到一个时间段,这个时间段就是我们定的时间(这就是定时器了)。
(1)定时器可以让SoC在执行主程序的同时,可以(通过定时器)具有计时功能,到了一定时间(计时结束)后,定时器会产生中断提醒CPU,CPU会去处理中断并执行定时器中断的ISR。从而去执行预先设定好的事件。
(1)定时器计时其实是通过计数来实现的。定时器内部有一个计数器,这个计数器根据一个时钟(这个时钟源来自于ARM的APB总线,然后经过时钟模块内部的分频器来分频得到)来工作。每隔一个时钟周期,计数器就计数一次,定时器的时间就是计数器计数值×时钟周期。
(2)定时器内部有1个寄存器TCNT,计时开始时我们会把一个总的计数值(譬如说300)放入TCNT寄存器中,然后每隔一个时钟周期(假设为1ms)TCNT中的值会自动减1(硬件自动完成,不需要CPU软件去干预),直到TCNT中减为0的时候,TCNT就会触发定时器中断。
(1)这几个东西都是和时间有关的部件。
(2)看门狗其实就是一个定时器,只不过定时时间到了之后不只是中断,还可以复位CPU
(3)RTC是实时时钟,它和定时器的差别就好象闹钟(定时器)和钟表(RTC)的差别一样。
(4)蜂鸣器是一个发声设备,在ARM里面蜂鸣器是用定时器模块来驱动的。
(2)为什么叫PWM定时器,因为一般SoC中产生PWM信号都是靠这个定时器模块的。
(2)产生systick作为操作系统的时间片(time slice)的。
(3)一般做操作系统移植的时候,这里不会由我们自己来做,一般原厂提供的基础移植部分就已经包含了,所以这里我也从来没有研究过。
(2)看门狗定时器可以设置在时间到了的时候产生中断,也可以选择发出复位信号复位CPU。
(3)看门狗定时器在实践中应用很多,尤其是工业领域(环境复杂、干扰多)机器容易出问题,而且出问题后后果很严重,此时一般都会用看门狗来进行系统复位。本章节会用2节课来对210中的看门狗进行讲解和编程。
(2)定时器关注的是时间段(而不是时间点),定时器计时从开启定时器的那一刻开始,到定的时间段结束为止产生中断;RTC中工作用的是时间点(xx年x月x日x时x分x秒星期x)。
(3)RTC和定时器的区别,就相当于是钟表和闹钟的区别。
+
(2)叫PWM定时器,是因为这个定时器天然是用来产生PWM波形的。
(2)S5PV210的5个PWM定时器的时钟源为PCLK_PSYS,timer0和timer1共同使用一个预分频器、timer2、3、4共同使用一个预分频器;每个timer有一个专用的独立的分频器;预分频器和分频器构成了2级分频系统,将PCLK_PSYS两级分频后生成的时钟供给timer模块作为时钟周期。
(3)剩下的介绍内容我就不逐句带读,大家自己读,读的时候结合后面的内容和翻译。
Each timer has its own 32-bit down-counter which is driven by the timer clock
每一个定时器有独自的32位递减计数器被定时器时钟所驱动
The down-counter is initially loaded from the Timer Count Buffer register (TCNTBn)
down-counter的初始值是从定时计数缓冲区寄存器(TCNTBn)下载的
If the down-counter reaches zero, the timer interrupt request is generated to inform the CPU
that the timer operation is complete
如果down-counter达到0,生成定时器中断请求去通知CPU定时器操作已经完成
If the timer down-counter reaches zero, the value of corresponding TCNTBn
automatically reloads into the down-counter to start a next cycle
如果定时器down-counter达到0,相应的TCNTBn的值会自动的下载到down-counter继续下一个周期
However, if the timer stops, for example, by clearing the timer enable bit of TCONn
during the timer running mode, the value of TCNTBn is not reloaded into the counter.
然而,如果定时器停止,例如,在定时器运行模式期间通过清除TCONn定时器使能位,
TCNTBn的值没有下载到counter.
The PWM function uses the value of the TCMPBn register
PWM功能使用TCMPBn寄存器的值
The timer control logic changes the output level
if down-counter value matches the value of the compare register in timer control logic
定时器控制逻辑会改变输出电平,如果down-counter的值在定时器控制逻辑与比较寄存器的值相匹配
Therefore, the compare register determines the turn-on time (or turn-off time) of a PWM output
因此比较寄存器决定了打开时间(或者关闭时间)来决定一个PWM输出
The TCNTBn and TCMPBn registers are double buffered to allow the timer parameters to be updated in the
middle of a cycle.
TCNTBn和TCMPBn寄存器是双缓冲,允许定时器参数可以在一个周期中更新.
The new values do not take effect until the current timer cycle completes.
一个新的值不生效直到当前定时器周期完成
(1)两级分频是串联(级联)的,所以两级分频的分频数是相乘的。
(2)两级分频的分频系数分别在TCFG0和TCFG1两个寄存器中设置。
(3)预分频器有2个,prescaler0为timer0&timer1共用;prescaler1为timer2、3、4共用;两个prescaler都是8个bit位,因此prescaler value范围为0~255;所以预分频器的分频值范围为1~256(注意实际分频值为prescaler value + 1)。
(4)分频器实质上是一个MUX开关,多选一开关决定了走哪个分频系数路线。可以选择的有1/1,1/2,1/4,1/8,1/16等。
(5)计算一下,两级分频下来,分频最小为1/1(也可能是1/2),最大分频为1/256×16(1/4096).
(1)TCNT和TCNTB是相对应的,TCNTB是有地址的寄存器,供程序员操作;TCNT在内部和TCNTB相对应,它没有寄存器地址,程序员不能编程访问这个寄存器。
(2)TCNT寄存器功能就是用来减1的,它是内部的不能读写;我们向TCNT中写要通过TCNTB往进写;读取TCNT寄存器中的值要通过读取相对应的TCNTO寄存器。
(3)工作流程就是:我们事先算好TCNT寄存器中开始减的那个数(譬如300),然后将之写入TCNTB寄存器中,在启动timer前,将TCNTB中的值刷到TCNT寄存器中(有一位寄存器专门用来操作刷数据过去的),刷过去后就可以启动定时器开始计时;在计时过程中如果想知道TCNT寄存器中的值减到多少了,可以读取相应的TCNTO寄存器来得知。
(1)定时器工作的时候,一次定时算一个工作循环。定时器默认是单个循环工作的,也就是说定时一次,计时一次,到期中断一次就完了。下次如果还要再定时中断,需要另外设置。
(2)但是现实中用定时器来做的时候往往是循环的,最简单最笨的方法就是写代码反复重置定时器寄存器的值(在每次中断处理的isr中再次给TCNTB中赋值,再次刷到TCNT中再次启动定时器),早期的单片机定时器就是这样的;但是现在的高级SoC中的定时器已经默认内置了这种循环定时工作模式,就叫自动装载(auto-reload)机制。
(3)自动装载机制就是当定时器初始化好开始计时后再不用管了,他一个周期到了后会自己从TCNTB中再次装载值到TCNT中,再次启动定时器开始下个循环。
(2)PWM波形是一个周期性波形,周期为T,在每个周期内波形是完全相同的。每个周期内由一个高电平和一个低电平组成。
(3)PWM波形有2个重要参数:一个是周期T,另一个是占空比duty(占空比就是一个周期内高电平的时间除以周期时间的商)。
(4)对于一个PWM波形,知道了周期T和占空比duty,就可以算出这个波形的所有细节。譬如高电平时间为T*duty,低电平时间为T*(1-duty)。
(5)PWM波形有很多用处,譬如通信上用PWM来进行脉宽调制对基波进行载波调制;在发光二极管LED照明领域可以用PWM波形来调制电流进行调光;用来驱动蜂鸣器等设备。
(2)早期的简单单片机里(譬如51单片机)是没有专用的PWM定时器的,那时候我们需要自己结合GPIO和定时器模块来手工生产PWM波形(流程是这样:先将GPIO引脚电平拉高、同时启动定时器定T*duty时间,时间到了在isr中将电平拉低,然后定时T*(1-duty)后再次启动定时器,然后时间到了后在isr中将电平拉高,然后再定时T*duty时间再次启动定时器····如此循环即可得到周期为T,占空比为duty的PWM波形)。
(3)后来因为定时器经常和PWM产生纠结一起,所以设计SoC的时候就直接把定时器和一个GPIO引脚内部绑定起来了,然后在定时器内部给我们设置了PWM产生的机制,可以更方便的利用定时器产生PWM波形。此时我们利用PWM定时器来产生PWM波形再不用中断了。绑定了之后坏处就是GPIO引脚是固定的、死板的、不能随便换的;好处是不用进入中断isr中,直接可以生成PWM。
(4)在S5PV210中,PWM波形产生有2个寄存器很关键,一个是TCNTB、一个是TCMPB。其中,TCNTB决定了PWM波形的周期,TCMPB决定了PWM波形的占空比。
(5)最终生成的PWM波形的周期是:TCNTB×时钟周期(PCLK_PSYS经过两极分频后得到的时钟周期)。注意这个周期是PWM中高电平+低电平的总时间,不是其中之一。
(6)最终生成的PWM波形的占空比是:TCMPB/TCNTB
(2)基于上面讲的,当duty从30%变到70%时,我们TCMPB寄存器中的值就要改(譬如TCNTB中是300时,TCMPB就要从210变化到90)。这样的改变可以满足需要,但是计算有点麻烦。于是乎210的PWM定时器帮我们提供了一个友好的工具叫做电平翻转器。
(3)电平翻转器在电路上的实质就是一个电平取反的部件,在编程上反映为一个寄存器位。写0就关闭输出电平反转,写1就开启输出电平反转。开启后和开启前输出电平刚好高低反转。(输出电平一反转30%的duty就变成70%了)
(4)实战中到底是TCNT和TCMPB谁大谁小时高电平还是低电平,一般不用理论分析,只要写个代码然后用示波器实际看一下出来的波形就知道了;如果反了就直接开启电平翻转器即可。
(1)PWM有一个应用就是用在功率电路中用来对交流电压进行整流。整流时2路整流分别在正电平和负电平时导通工作,不能同时导通(同时导通会直接短路,瞬间的同时导通都会导致电路烧毁)。大功率的开关电源、逆变器等设备广泛使用了整流技术。特别是逆变器,用SoC的GPIO输出的PWM波形来分别驱动2路整流的IGBT。
(2)PWM波形用来做整理时要求不能同时高或低,因为会短路。但是实际电路是不理想的,不可能同时上升/下降沿,所以比较安全的做法是留死区。
(3)死区这东西离不了也多不了。死区少了容易短路,死区多了控制精度低了不利于产品性能的提升。
(4)S5PV210给大家提供了自带的死区生成器,只要开启死区生成器,生产出来的PWM波形就自带了死区控制功能,用户不用再自己去操心死区问题。
(5)大部分人工作是用不到这个的,直接关掉死区生成器即可。
(2)我们只要以快速的频率给蜂鸣器的正负极:供电、断电。进行这样的循环,蜂鸣器的两个弹簧片就会挨着分开挨着分开···形成敲击,发出声音。
(3)因为人的耳朵能听见的声音频率有限制(20Hz-20000Hz),我们做实验时一般给个2KHz的频率,大部分人都能听到(听不到的就就近医院处理)。
(4)频率高低会影响声音的音频,一般是音频越低声音听起来越低沉、音频越高听起来越尖锐。
(5)根据以上的分析,可以看出,只要用PWM波形的电压信号来驱动蜂鸣器,把PWM波形的周期T设置为要发出的声音信号的1/频率即可;PWM的占空比只要确保能驱动蜂鸣器即可(驱动能力问题,一般引脚驱动能力都不够,所以蜂鸣器会额外用三极管来放大流来供电)。
(2)GPD0_2引脚通过限流电阻接在三极管基极上,引脚有电蜂鸣器就会有电(三极管导通);引脚没电蜂鸣器就会没电(三极管关闭)。这些都是硬件问题,软件工程师不用管,软件工程师只要写程序控制GPD0_2引脚的电平产生PWM波形即可。
(3)GPD0CON(0xE02000A0),要把bit8~bit11设置为0b0010(功能选择为TOUT_2,就是把这个引脚设置为PWM输出功能)
(4)从GPD0_2引脚可以反推出使用的是timer2这个PWM定时器。
注意:PWM定时器来产生PWM波形时是不需要中断干预的。
(1)看门狗定时器和普通的定时器并无本质区别。定时器可以设定一个时间,在这个时间完成之前定时器不断计时,时间到的时候定时器会复位CPU(重启系统)。
(2)系统正常工作的时候当然不希望被重启,但是系统受到干扰、极端环境等可能会产生异常工作或者不工作,这种状态可能会造成不良影响(至少是不工作),此时解决方案就是重启系统。
(3)普通设备重启不是问题,但是有些设备人工重启存在困难。这时候我们希望系统能够自己检验自己是否已经跑飞,并且在意识到自己跑飞的时候,可以很快的(几个ms或者更短)自我重启。这个功能就要靠看门狗定时器来实现。
(4)典型应用的情景是:我们在应用程序中打开看门狗设备,初始化好给它一个时间,然后应用程序使用一个线程来喂狗,这个线程的执行时间安全短于看门狗的复位时间。当系统(或者应用程序)异常后,喂狗线程自然就不工作了,然后到时候看门狗就会复位。
(1)PCLK_PSYS经过两级分频后生成WDT(watchdog timer)的时钟周期,然后把要定的时间写到WTDAT寄存器中,刷到WTCNT寄存器中去减1,减到0时(定时时间到)产生复位信号或中断信号。
WTCON WTDAT WTCNT WTCLRINT
(2)RTC是SoC中一个内部外设,RTC有自己独立的晶振提供RTC时钟源(32.768KHz),内部有一些寄存器用来记录时间(年月日时分秒星期)。一般情况下为了在系统关机时时间仍然在走,还会给RTC提供一个电池供电。
(2)闹钟发生器
(1)可以定闹钟时间,到时间会产生RTC alarm interrupt,通知系统闹钟定时到了。
(1)INTP 中断挂起寄存器
(3)RTCALM ALMxxx 闹钟功能有关的寄存器
(4)BCDxxx 时间寄存器
(1)RTC中所有的时间(年月日时分秒星期,包括闹钟)都是用BCD码编码的。
(2)BCD码本质上是对数字的一种编码。用来解决这种问题:由56得到0x56(或者反过来)。也就是说我们希望十进制的56可以被编码成56(这里的56不是十进制56,而是两个数字5和6).
(3)BCD码的作用在于可以将十进制数拆成组成这个十进制数的各个数字的编码,变成编码后就没有位数的限制了。譬如我有一个很大的数123456789123456789,如果这个数纯粹当数字肯定超出了int的范围,计算机无法直接处理。要想让计算机处理这个数,计算机首先得能表达这个数,表达的方式就是先把这个数转成对应的BCD码(123456789123456789)
(4)BCD码在计算机中可以用十六进制的形式来表示。也就是说十进制的56转成BCD码后是56,在计算机中用0x56来表达(暂时存储与运算)。
(2)读写RTC寄存器时,一定要注意BCD码和十进制之间的转换。
(3)年的问题。S5PV210中做了个设定,BCDYEAR寄存器存的并不是完整的年数(譬如今年2015年),而是基于2000年的偏移量来存储的,譬如今年2015年实际存的就是15(2015-2000).还有些RTC芯片是以1970年(貌似)为基点来记录的。