📄 tm_clk.c
字号:
#include "../inc/def.h"
#include "../inc/config.h"
#include "../inc/board.h"
#include "../inc/slib.h"
#include "AT91RM9200.h"
#include "lib_AT91RM9200.h"
#include "../inc/utils.h"
#define DELAY_PLL 1000
#define DELAY_MAIN_FREQ 1000
#define EXT_OSC_CLK 18432000
#define AT91C_PLLA_VALUE 0x205FBE0A //PLLA = 0x60*18.432M/0xa = 176.9472M
#define MCKR_VAL 0x202 //1/3
static struct{
U32 plla;
U32 mckr;
U32 n1;
U32 n2;
} ClkPara;
#define AT91C_PLLB_VALUE 0x10483E0E //* 48,054857 MHz (divider by 2 for USB)
static void set_pll(void)
{
volatile int tmp = 0;
U32 freq;
/* APMC Initialization for Crystal */
AT91PS_PMC pApmc = (AT91PS_PMC)AT91C_BASE_PMC;
AT91PS_CKGR pCkgr = (AT91PS_CKGR)AT91C_BASE_CKGR;
// if(((pCkgr->CKGR_PLLAR&0x7ff0000)==(ClkPara.plla&0x7ff0000)) &&
// ((pCkgr->CKGR_PLLAR&0xff)==(ClkPara.plla&0xff)) &&
// (pApmc->PMC_MCKR==))
// return
ClkPara.plla &= 0x7ff00ff;
ClkPara.plla |= (1<<29)|(0x3f<<8);
freq = (((ClkPara.plla>>16)&0x7ff)+1)*EXT_OSC_CLK/(ClkPara.plla&0xff);
if(freq>=150000000)
ClkPara.plla |= 1<<15;
ClkPara.mckr &= 0x300;
ClkPara.mckr |= 2;
//禁止PMC的所有中断源
pApmc->PMC_IDR = 0xFFFFFFFF;
// Setting PLLB and Divider B
if((pCkgr->CKGR_PLLBR^AT91C_PLLB_VALUE)&0x07ff00ff) {
pCkgr->CKGR_PLLBR = AT91C_PLLB_VALUE;
//* Wait for PLLB stabilization LOCKB bit in PMC_SR
tmp = 0;
while(!(pApmc->PMC_SR & AT91C_PMC_LOCKB) && (tmp++ < DELAY_MAIN_FREQ));
}
//先选择PLLB做为主时钟
/* Write in the MCKR dirty value concerning the clock selection CSS then overwrite it in a second sequence */
pApmc->PMC_MCKR = 0x203;
/* Wait until the master clock is established */
tmp = 0;
while(!(pApmc->PMC_SR & AT91C_PMC_MCKRDY) && (tmp++ < DELAY_PLL));
//再设置PLLA,若原主时钟为PLLA而在未切换到其他时钟源时设置PLLA(值不变),启动会等很久,why?
if((pCkgr->CKGR_PLLAR^ClkPara.plla)&0x07ff00ff) {
pCkgr->CKGR_PLLAR = ClkPara.plla;
//* Wait for PLLB stabilization LOCKB bit in PMC_SR
tmp = 0;
while(!(pApmc->PMC_SR & AT91C_PMC_LOCKA) && (tmp++ < DELAY_PLL));
}
//再把主时钟源换到PLLA,设置同步模式,等待时钟稳定
/* - Commuting Master Clock from PLLB to PLLA/3 */
pApmc->PMC_MCKR = ClkPara.mckr; //master clock 为 PLLA,预分频为1,Processor clock为master clock的2/3倍
/* Wait until the master clock is established */
tmp = 0;
while(!(pApmc->PMC_SR & AT91C_PMC_MCKRDY) && (tmp++ < DELAY_MAIN_FREQ));
MMU_SetAsyncBusMode(); //设置CPU总线同步模式
ClkPara.n1 = GetCpuClock();
ClkPara.n2 = GetMasterClock();
}
void SystemClockInit(void)
{
//ClkPara.plla = AT91C_PLLA_VALUE;
//ClkPara.mckr = MCKR_VAL;
ClkPara.plla = (97<<16)|10;
ClkPara.mckr = 2<<8;
set_pll();
}
U32 GetCpuClock(void)
{
return AT91F_PMC_GetProcessorClock(AT91C_BASE_PMC, AT91C_BASE_CKGR, 32768);
}
U32 GetMasterClock(void)
{
return AT91F_PMC_GetMasterClock(AT91C_BASE_PMC, AT91C_BASE_CKGR, 32768);
}
int SetSysClock(void)
{
int mul, div, mdiv;
char tmp[8];
printf("Please enter the PLL parameter to use, mul[0-2047], div[0-255], mdiv[0-3]\n");
printf("mul: ");
if((mul=strtodec(tmp, GetParameter(tmp, 4)))<0) {
printf("\nget mull Error!\n");
return -1;
}
printf("\ndiv: ");
if((div=strtodec(tmp, GetParameter(tmp, 3)))<0) {
printf("\nget div Error!\n");
return -1;
}
printf("\nmdiv: ");
if((mdiv=strtodec(tmp, GetParameter(tmp, 1)))<0) {
printf("\nget mdiv Error!\n");
return -1;
}
if((mul>2047)||(div>255)||(mdiv>3)) {
printf("Parameters error!\n");
return -1;
}
printf("\nYou set System clock mul = %d, div = %d, mdiv = %d\n", mul, div, mdiv);
Delay(10);
ClkPara.plla = (mul<<16)|div;
ClkPara.mckr = mdiv<<8;
set_pll();
return 0;
}
U32 GetSysClock(SysClock pSysClock[])
{
pSysClock[0].name = "CPU";
pSysClock[0].freq = GetCpuClock();
pSysClock[1].name = "Master";
pSysClock[1].freq = GetMasterClock();
return 2;
}
void SetSysClockPara(void *addr)
{
U32 *pData = addr;
ClkPara.plla = pData[0];
ClkPara.mckr = pData[1];
set_pll();
}
void GetSysClockPara(void *addr)
{
U32 *pData = addr;
pData[0] = ClkPara.plla;
pData[1] = ClkPara.mckr;
pData[2] = ClkPara.n1;
pData[3] = ClkPara.n2;
}
void TimerInit(U32 HZ)
{
AT91PS_TC pTC = AT91C_BASE_TC0;
AT91F_TC0_CfgPMC();
pTC->TC_IDR = 0xff; //disable all interrupts
//select TIMER_CLOCK2 = MCK/8, CPCTRG, up mode, Waveform mode
pTC->TC_CMR = 1|(2<<13)|(1<<15); //Capture模式下,RC COMPARE也可复位计数器
pTC->TC_RC = (GetMasterClock()>>3)/HZ;
pTC->TC_CCR = 5; //enable timer-counter and trig it
}
/*static __inline void ResetTimer(void)
{
AT91C_BASE_TC0->TC_CCR = 4;
}*/
void Delay(U32 ms)
{
U16 i;
i = AT91C_BASE_TC0->TC_RC>>1; //1000us/2
AT91C_BASE_TC0->TC_CCR = 4; //复位为0,加计数
while(ms--) {
while(AT91C_BASE_TC0->TC_CV<=i);
while(AT91C_BASE_TC0->TC_CV>i);
}
}
int WaitEventWithTimeout(int (*event)(void), int cond, U32 ms)
{
int result;
U16 half, ms_h;
AT91C_BASE_TC0->TC_CCR = 4;
half = AT91C_BASE_TC0->TC_RC>>1;
ms_h = 0;
while(ms) {
result = (*event)();
if(cond) {
if(result)
return 0;
} else {
if(!result)
return 0;
}
if(!ms_h) {
if(AT91C_BASE_TC0->TC_CV>=half)
ms_h = 1;
} else {
if(AT91C_BASE_TC0->TC_CV<half) {
ms_h = 0;
ms--;
}
}
}
return -1;
}
/*************************************************************/
void RtcSetDay(TIME_STRUC *time)
{
AT91PS_RTC pRTC = AT91C_BASE_RTC;
U32 tmp;
// printf("RTC_VER=%x\n", pRTC->RTC_VER);
//设置正确日期时间后可清除invalid位
while(!(pRTC->RTC_SR&4));
tmp = pRTC->RTC_CALR&(7<<21);
tmp |= ((time->year&0x3f00)>>8) |
((time->year&0xff)<<8) |
((time->month&0x1f)<<16) |
(time->day&0x3f)<<24;
pRTC->RTC_CR |= 3;
while(!(pRTC->RTC_SR&1));
pRTC->RTC_CALR = tmp;
pRTC->RTC_CR &= ~3;
pRTC->RTC_SCCR = 0x1f;
// printf("RTC_VER=%x\n", pRTC->RTC_VER);
}
void RtcSetWeek(TIME_STRUC *time)
{
AT91PS_RTC pRTC = AT91C_BASE_RTC;
U32 tmp;
while(!(pRTC->RTC_SR&4));
tmp = pRTC->RTC_CALR;
tmp &= ~(7<<21);
tmp |= (time->weekday&7)<<21;
pRTC->RTC_CR |= 3;
while(!(pRTC->RTC_SR&1));
pRTC->RTC_CALR = tmp;
pRTC->RTC_CR &= ~3;
pRTC->RTC_SCCR = 0x1f;
}
void RtcSetTime(TIME_STRUC *time)
{
AT91PS_RTC pRTC = AT91C_BASE_RTC;
while(!(pRTC->RTC_SR&4));
pRTC->RTC_CR |= 1;
while(!(pRTC->RTC_SR&1));
pRTC->RTC_MR &= ~1; //24 Hour mode
pRTC->RTC_TIMR = (time->hour<<16)|(time->min<<8)|time->sec;
pRTC->RTC_CR &= ~1;
pRTC->RTC_SCCR = 0x1f;
}
void RtcGetTime(TIME_STRUC *time)
{
AT91PS_RTC pRTC = AT91C_BASE_RTC;
U32 tmp, tmp1;
get_tm_agn:
tmp = pRTC->RTC_TIMR;
tmp1 = pRTC->RTC_CALR;
time->year = ((tmp1&0x3f)<<8)+((tmp1&0xff00)>>8);
time->month = (tmp1>>16)&0x1f;
time->day = (tmp1>>24)&0x3f;
time->weekday = (tmp1>>21)&0x7;
time->hour = (tmp>>16)&0x3f;
time->min = (tmp>>8)&0x7f;
time->sec = tmp&0x7f;
if(tmp!=pRTC->RTC_TIMR)
goto get_tm_agn;
if(pRTC->RTC_MR&1) {
if(pRTC->RTC_TIMR&(1<<22))
time->hour += 0x12;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -