S3C2440之設定系統時鐘
阿新 • • 發佈:2019-01-12
任何一個ARM初始化的時候一般都會優先設定系統時間,尤其是在設定一些與系統時鐘息息相關的外設的時候,
S3C2440也不例外,系統時鐘設定如下:
/****************************** *檔名:clock.c * *功能: 電子鐘 * *建立者: 潘星宇 * *最後修改:2013.03.7 * *備註: * * * *******************************/ #include "clock.h" static U32 UPLL; /***************************************************************************** ***函式名:cal_cpu_bus_clk() ***功能:讀取系統時鐘值,提供給別的外設使用 ***引數:無 ***返回:無 *****************************************************************************/ void cal_cpu_bus_clk(void) { U32 val; U8 m, p, s; /*從暫存器MPLLCON中提取MDIV,PDIV,SDIV的值,從而計算FCLK的值, 就是MPLLout val = rMPLLCON; */ val = rMPLLCON; m = (val>>12)&0xff; //注意,之前在呼叫函式中已經設定好了rMPLLCON的值 p = (val>>4)&0x3f; //p=PDIV=MPLLCON[9:4] 6位取值 s = val&3; //s=SDIV=MPLLCON[1:0] 低2位取值 /*(m+8)*FIN*2 不要超出32位數! //(1<<s)表示第s位置1,也就是2^s. 公式MPLL=(2*(MDIV+8)*FIN)/((PDIV+2)*(2^s)) FIN=12000000*/ FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; /*從暫存器CLKDIVN中提取出HDIVN和PDIVN,進行FCLK:HCLK:PCLK分頻比的設定*/ val = rCLKDIVN; //在呼叫函式裡面已經設定了rCLKDIVN的值 m = (val>>1)&3; //從暫存器CAMDIVN中提取出CAMDIVN[9:8] p = val&1; //在呼叫函式裡面已經設定了rCAMDIVN的值 val = rCAMDIVN; //s[1:0]=CAMDIVN[9:8]=HCLK4_HALF,HCLK3_HALF /*s[4]=CAMDIVN[12]=DVS_EN,如果DVS_EN=1,則CPU時鐘為HCLK,否則為FCLK*/ s = val>>8; switch (m) { //這裡的m=HDIVN,對FCLK和HCLK進行分頻設定 case 0: HCLK = FCLK; break; case 1: HCLK = FCLK>>1; //HCLK=FCLK/2 break; case 2: if(s&2) //如果s[1]=1,也即CAMDIVN[9]=HCLK4_HALF=1 HCLK = FCLK>>3; //HCLK=FCLK/8 else HCLK = FCLK>>2; //HCLK=FCLK/4 break; case 3: if(s&1) //如果s[0]=1,也即CAMDIVN[8]=HCLK3_HALF=1 HCLK = FCLK/6; //HCLK=FCLK/6 else HCLK = FCLK/3; //HCLK=FCLK/3 break; } if(p) //這裡p=PDIVN,對HCLK和PCLK進行分頻設定 PCLK = HCLK>>1; //PDIVN=1,則PCLK=HCLK/2;否則PCLK=HCLK else PCLK = HCLK; //如果s[4]=1,也即CAMDIVN[12]=DVS_EN=1 val = rUPLLCON; //讀ytfrUPLLCON的值 m = (val>>12)&0xff; //m=MDIV=UPLLCON[19:12] 8位 p = (val>>4)&0x3f; //p=PDIV=UPLLCON[9:4] 6位 s = val&3; //s=SDIV=UPLLCON[1:0] 2位 /*公式UPLL=((MDIV+8)*FIN)/((PDIV+2)*(2^s)) FIN為輸入時鐘頻率*/ UPLL = ((m+8)*FIN)/((p+2)*(1<<s)); /*如果CLKDIVN[3]=1,則UPLL需要分頻*/ UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL; } /************************************************************************** ***** 函式名: clock(void) ***** 功能: 電子鐘 ***** 引數: 無 ***** 返回值: 無 ***** 建立者: 潘星宇 ***** 建立時間: 2013-03-5 ***** 最後更新:2013-03-7 ****************************************************************************/ void clock(void) { static U8 str[30] = {0}; //串列埠寄存陣列 U8 ch; //串列埠用變數 static U8 UART_i = 0; //串列埠陣列計數用 U8 hour_i; //畫小時刻度計數用的變數 U8 minute_i; //畫分鐘刻度計數用的變數 U32 hour; //從RTC讀取的小時 U32 minute; //分鐘 U32 second; //秒 U32 second_ch; //秒控制變數,用於控制每秒才顯示一次 static U32 hour_register; //小時暫存器,用於儲存上一次畫時針的位置,用於清屏 static U32 minute_register; //分鐘暫存器 static U32 second_register; //秒暫存器 Brush_Background(0x435c); //繪製背景品藍色 RTC_time_set (0x13, 0x03, 0x07, 0x04, 0x14, 0x55, 0x35); draw_circle(180,136,123,0xfea0); //表外框金黃色 //繪製返回 draw_return(400, 130, COLOR_BLACK, COLOR_LIGHT_GREEN); //背景淺綠色 /********************************************** *已知起始點、兩點距離和角度畫線的引數分別為:* *第一點座標x1,y1; * *長度; * *角度(不是弧度); * *顏色; * *希望保留起始的點的個數; * *希望保留最後的點的個數 * **********************************************/ //畫小時刻度 for (hour_i=0; hour_i<12; hour_i++) { one_point_to_another(180, 136, 120, hour_i*30, 0xfb00, 0, 15); //從0點畫到11點 橙色 } //畫分鐘刻度 for (minute_i=0; minute_i<60; minute_i++) { if (minute_i % 5) //整點處不畫刻度 { one_point_to_another(180, 136, 120, minute_i*6, 0xfc00, 0, 1 ); //從1分畫到59分 橘黃色 } } while (function_flag==0) { hour = rBCDHOUR; //獲取小時 minute = rBCDMIN; //獲取分鐘 second = rBCDSEC; //獲取秒 hour = ((hour / 16)*10 + hour % 16) % 12;//由於從RTC讀出的都是16進位制的,先轉成10進位制,再將24小時格式轉化為12小時格式 minute = (minute / 16)*10 + minute % 16; second = (second / 16)*10 + second % 16; if (second != second_ch) { //先清除掉上次畫的時針,分針,秒針,長度暫分別定為35,60,90 if ((hour_register*30 + (minute_register / 10)*5) != (hour*30 + (minute / 10)*5)) //為了消除分針和時針閃屏的問 { //只有當分針或時針確實移動了位置才消除上一次畫的的值 one_point_to_another(180, 136, 120, hour_register*30 + (minute_register / 10)*5, 0x435c, 35, 0); } if (minute_register != minute) { one_point_to_another(180, 136, 120, minute_register*6, 0x435c, 60, 0); } one_point_to_another(180, 136, 120, second_register*6, 0x435c, 90, 0); second_ch = second; //使秒控制變數等於當前時鐘的秒值,這樣直到秒變化,才再次進入這個內部來 one_point_to_another(180, 136, 120, hour*30 + (minute /10)*5, COLOR_BLACK, 35, 0); //時針每小時走30°,分鐘動10分鐘,時鐘動5° one_point_to_another(180, 136, 120, minute*6, 0x001f, 60, 0); //藍色 one_point_to_another(180, 136, 120, second*6, 0xf800, 90, 0); //紅色 rtc_display_lcd(320,150,0xb1dd,0x08a8); //顯示電子鐘,引數分別為橫座標、縱座標、顏色、背景色 hour_register = hour; //將時分秒的值儲存起來,用於下一秒清除上一秒的變化 minute_register = minute; second_register = second; } while (rUTRSTAT0 & 0x1) //當串列埠接收緩衝器有資料時 { ch = rURXH0; //接收資料 str[UART_i++] = ch; if((ch == 0xff)||(UART_i == 29 )) //接收資料完成 { RTC_time_set (str[0], str[1], str[2], str[3], str[4], str[5], str[6]); UART_i = 0; } } } }
附送一部分電子時鐘的程式碼,標頭檔案如下:
#ifndef CLOCK_H #define CLOCK_H #include "LCD.h" #include "zi.h" #include "global_value.h" #include "2440addr.h" #include "RTC.h" #include "interface.h" #include "common_functions.h" /***************************************************************************** ***函式名:cal_cpu_bus_clk() ***功能:讀取系統時鐘值,提供給別的外設使用 ***引數:無 ***返回:無 *****************************************************************************/ extern void cal_cpu_bus_clk(void); /************************************************************************** ***** 函式名: clock(void) ***** 功能: 電子鐘 ***** 引數: 無 ***** 返回值: 無 ***** 建立者: 潘星宇 ***** 建立時間: 2013-03-5 ***** 最後更新:2013-03-7 ****************************************************************************/ extern void clock(void); #endif