關于借鑒與版權的說明:飛凌提供的代碼有一定問題,并且部分關鍵代碼沒有解釋,我在搜集各方面資料后綜合網(wǎng)友指正和自己的理解,注釋了部分自己認為重要的部分。當然如果大神覺得可不注釋,也可以。此篇文章援引多家大神的微博,如需看大神原作,請百度搜索標題,此處個人見解不恰當?shù)恼埜魑恢刚?br />
6410中的PWM 定時器
1.簡單介紹 :
S3C6410X中有5個定時器,這些定時器產(chǎn)生內(nèi)部中斷。其中,Timer0和Timer1具有PWM功能,而Timer2,3,4沒有此功能。
PWM具有兩種操作模式:自動裝載模式,一次觸發(fā)模式。為實現(xiàn)PWM功能,芯片提供了16個功能寄存器。這些功能寄存器都連接APB總線。
定時器具有雙緩沖特性,這樣就能在不停止當前定時器操作的情況下,為下次定時器運行裝入新的數(shù)值。盡管為定時器設置了新數(shù)值,但當前的定時操作能夠成功完成。定時器從TCNTBn讀取的值是為下次延時定時用的,并不影響當前定時器的運行。當TCNTn減小到0的時候,TCNTBn的值會自動復制到TCNTn中,這就是說的自動裝載操作。定時器的當前計數(shù)值可以從定時計數(shù)觀察寄存器中TCNTOn讀取。如果TCNTn為0且從裝載也為0的話則TCNTn不在進行下次操作。
2.定時器的電路結夠圖:
3.定時器架構流程。
PCLK ---à 經(jīng)過8位的預分頻器【8bit prescaler0】 --à 分頻器divider [1/1 1/2 1/4 1/81/16] -à 多路選擇器 MUX -à 邏輯控制器【比較TCMPBn和TCNTBn的數(shù)值】--à(deadzone generator ) --à 時鐘
計算公式:
4.定時器的工作原理是什么。
每個定時器有32位的遞減計數(shù)器。遞減計數(shù)器的初始值由TCNTBn來加載。 當計數(shù)器的值變?yōu)?時, 定時器產(chǎn)生中斷信號通知cpu定時器操作完成。 當計數(shù)器的值變?yōu)?時,TCNTBn的值自動加載到遞減計數(shù)器并開始下個周期的操作。 如果定時器停止工作(比如,在定時器工作模式期間清空寄存器TCONn的定時器使能位,這樣對應的定時器就會停止工作),這時TCNTBn的值就不會加載到定時器。
而對于PWM 功能,要用到寄存器TCMPBn,當遞減計數(shù)器down-counter的值和比較寄存器TCMPBn的值相同時,定時控制邏輯模塊就會改變輸出電平。因此比較寄存器TCMPBn決定了PWM的輸出。
而且TCNTBn 和 TCMPBn寄存器具有雙緩沖特性,這樣就能在不停止當前定時器操作的情況下,為下次定時器運行裝入新的數(shù)值。盡管為定時器設置了新數(shù)值,但當前的定時操作能夠成功完成。
5. 定時器的工作時序
我說怎么在上面的第一步中突然冒出個TCNTn和TCMPn,我以為是數(shù)據(jù)手冊錯了,因為在PWM提供的16個寄存器中沒有這兩個寄存器。 那么請看下面:
從上面內(nèi)容看出。TCNTn和TCMPn是內(nèi)部的寄存器(internal registers ).而TCNTn寄存器的值可以通過讀取寄存器TCNTOn來獲得。
7.接下來看一下飛凌提供的精確控制LED的程序。【利用定時器來精確控制LED跑馬燈,每隔1s輪詢點亮】
#define rGPMCON (*(volatile unsigned*)(0x7F008820))
#define rGPMDAT (*(volatileunsigned*)(0x7F008824))
#define rGPMPUD (*(volatile unsigned*)(0x7F008828))
#define PCLK 66000000 //forS3C6410 66MHZ
// #define HCLK 133000000//forS3C6410 133MHZ 這一句沒用到,寫上可以。
#define rTCFG0 (*(volatile unsigned*)(0x7F006000))
#define rTCFG1 (*(volatileunsigned*)(0x7F006004))
#define rTCON (*(volatileunsigned*)(0x7F006008))
#define rTCNTB0 (*(volatileunsigned*)(0x7F00600C))
#define rTCMPB0 (*(volatileunsigned*)(0x7F006010))
#define rTCNTO0 (*(volatileunsigned*)(0x7F006014))
#define rTCNTB1 (*(volatileunsigned*)(0x7F006018))
#define rTCMPB1 (*(volatileunsigned*)(0x7F00601c))
#define rTCNTO1 (*(volatileunsigned*)(0x7F006020))
#define rTCNTB2 (*(volatileunsigned*)(0x7F006024))
#define rTCNTO2 (*(volatileunsigned*)(0x7F00602c))
#define rTCNTB3 (*(volatileunsigned*)(0x7F006030))
#define rTCNTO3 (*(volatileunsigned*)(0x7F006038))
#define rTCNTB4 (*(volatileunsigned*)(0x7F00603c))
#define rTCNTO4 (*(volatileunsigned*)(0x7F006040))
#definerTINT_CSTAT (*(volatileunsigned*)(0x7F006044))
void uDelay(intusec)
{
unsignedint val=(PCLK)/1000000-1; //val = 65
//configure prescalerand divider
rTCFG0&=~(0xff<<8); //0000_0000_1111_1111 TCFG0[15:8-7:0]
rTCFG0|=0<<8; //0000_0000_0000_0000 |0000_0000_1111_1111 prescalar0 = 255 timer0,timer1 的prescalar value= 255 timer2,3,4的prescalar1 value = 0
rTCFG1&=~(0xf<<8); // 0000_1111_1111 TCFG1 [7:0] =1111_1111 TCFG1[11:8] = 0000(select mux for timer2. divider value = 1 );
rTCFG1|=0<<8;
//compute :
//timerinput clock frequency = PCLK /({prescaler value + 1})/{divider value}
// timer2input clock frequency = 66M /(1)/(1)= 66M hz
//configure timercounter buffer and enable timer2
rTCNTB2=val;
rTCON&=~(0xf<<12); // 0000_1111_1111_1111
rTCON|=0xb<<12; // 1011_0000_0000_0000|0000_1111_1111_1111 = 1011_1111_1111_1111
rTCON&=~(2<<12); // 1101_1111_1111_1111&1011_1111_1111_1111 = 1001_1111_1111_1111
【// TCON(Timer control register)
//1001 : 表示 : auto-reload , starttimer2】
//TCON[15]=1 auto-reload
//TCON[14] Reserved bits
//TCON[13]=0 no operatin , =1,update TCNTB2 TCMPB2
//TCON[12]=0 stop , =1 ,start timer2
//rTCON&= 0x9fff;
while(usec--){
while(rTCNTO2 >= val>>1);
while(rTCNTO2 < val>>1);
};
}
void msDelay(inttime)
{
volatile unsigned int i,j;
for(i=0;i<2000000;i++)
for(j=0;j<time;j++);
}
void GPIO_Init(void)
{
rGPMCON =0x11111;
rGPMPUD =0x00;
rGPMDAT =0X1F;
}
voidLedTest(void)
{
volatile unsigned int i ,j;
while(1)
{
for(i=0;i<4;i++)
{
rGPMDAT=~(1<<i);
for(j=0;j<1000;j++)
uDelay(1000);
}
}
}
void Main(void)
{
GPIO_Init();
LedTest();
}