1 引言 桌面Windows系統(tǒng)的時(shí)間顯示功能已為大家所熟知,它是通過BIOS上的時(shí)鐘模塊實(shí)現(xiàn)的。用戶通過點(diǎn)擊桌面系統(tǒng)任務(wù)欄右下腳的時(shí)間,可以修改當(dāng)前時(shí)間、時(shí)區(qū)以及實(shí)現(xiàn)與Internet時(shí)間同步等功能。 目前流行的手機(jī)、PDA、HMI(人機(jī)接口設(shè)備)等嵌入式系統(tǒng)中,都大量移植了微軟的Windows CE操作系統(tǒng)。雖然WinCE系統(tǒng)也實(shí)現(xiàn)了時(shí)間顯示,但是在具體的實(shí)現(xiàn)中,其原理和方法與桌面系統(tǒng)大不相同,即使是基于不同嵌入式硬件平臺(tái)的WinCE開發(fā),也有所不同。由于嵌入式系統(tǒng)的復(fù)雜性、分散性,目前嵌入式系統(tǒng)的實(shí)時(shí)時(shí)鐘RTC功能的實(shí)現(xiàn),大部分是在基于內(nèi)嵌于SoC處理器的RTC功能IP模塊的基礎(chǔ)上,通過軟件驅(qū)動(dòng)實(shí)現(xiàn)的。 S3C2440是三星公司推出的一款基于ARM920T處理器構(gòu)架的低功耗、高性能的嵌入式SoC處理器,應(yīng)用極為廣泛。RTC是S3C2440的一個(gè)內(nèi)部功能模塊,本文首先對(duì)于S3C2440的硬件架構(gòu)進(jìn)行介紹,在此基礎(chǔ)上對(duì)S3C2440的RTC功能模塊的工作機(jī)理進(jìn)行了分析,最后給出Windows CE.net下的RTC功能的驅(qū)動(dòng)程序設(shè)計(jì)、實(shí)現(xiàn),本驅(qū)動(dòng)程序成功地應(yīng)用在基于S3C2440Window CE平臺(tái)的手持GPS機(jī)實(shí)時(shí)時(shí)鐘功能的實(shí)現(xiàn),對(duì)于基于Windows CE.net其它硬件平臺(tái)的RTC功能實(shí)現(xiàn)具有一定的借鑒作用。 2 硬件構(gòu)架 WinCE下RTC功能實(shí)現(xiàn)是基于RTC模塊的,在此先對(duì)S3C2440處理器作簡單介紹,主要對(duì)于S3C2440的RTC的硬件結(jié)構(gòu)、工作機(jī)理進(jìn)行分析,這些是Windows CE.net下RTC功能實(shí)現(xiàn)的基礎(chǔ)。 2.1 簡介 S3C2440 是三星公司推出的基于ARM920T的嵌入式處理器,主頻高達(dá)400MHz,最高可達(dá)533MHz,低功耗、高性能,廣泛地應(yīng)用于PDA、便攜媒體播放器、衛(wèi)星導(dǎo)航儀等多媒體終端,片上集成指令/數(shù)據(jù)分開的16KCache、SDRAM控制器、LCD控制器、4通道DMA、3通道UART、IIC總線、IIS總線、SD主機(jī)接口、PWM定時(shí)器、看門狗、片上PLL時(shí)鐘發(fā)生器、8通道10位AD控制器和觸摸屏接口以及帶日歷函數(shù)的實(shí)時(shí)時(shí)鐘,極大地方便于系統(tǒng)開發(fā)。 2.2 S3C244O處理器的RTC硬件構(gòu)架 S3C2440內(nèi)部RTC模塊結(jié)構(gòu)框圖如圖1所示。S3C2440處理器的RTC模塊依靠外部32.768kHz晶振提供基準(zhǔn)時(shí)鐘,系統(tǒng)能夠在斷電的情況下由后備電池供電繼續(xù)工作,能夠?qū)?位數(shù)據(jù)轉(zhuǎn)換為BCD碼的格式傳送給處理器。這些數(shù)據(jù)包括秒、分、時(shí)、日期、星期、月、年。 如圖1所示,RTC模塊由基準(zhǔn)晶振的連接引腳、時(shí)鐘滴答發(fā)生器、215時(shí)鐘分頻器、控制和重置寄存器、閏年發(fā)生器、報(bào)警發(fā)生器以及BCD數(shù)字(秒、分、時(shí)、日期、星期、月、年)等幾部分組成:XTlrtc與XTortc是連接外部晶振32.768kHz的兩個(gè)引腳,為RTC內(nèi)部提供輸入。215時(shí)鐘分頻器負(fù)責(zé)對(duì)基準(zhǔn)頻率進(jìn)行分頻。時(shí)鐘滴答發(fā)生器可以產(chǎn)生時(shí)鐘滴答,它可以引起中斷。閏年發(fā)生器按照從日期、月、年得來的BCD數(shù)據(jù)決定一個(gè)月最后一天是28、29、30還是31號(hào)(也就是計(jì)算是否是閏年)。報(bào)警發(fā)生器可以根據(jù)系統(tǒng)設(shè)定時(shí)間和當(dāng)前時(shí)間決定是否報(bào)警。控制寄存器控制包括讀/寫B(tài)CD寄存器使能、時(shí)鐘復(fù)位、時(shí)鐘選擇等。重置寄存器可以選擇”秒”對(duì)”分”進(jìn)位邊界,提供三個(gè)可選邊界:30、40或者50秒。 圖1 S3C2440內(nèi)部RTC模塊結(jié)構(gòu)圖 2.3 S3C2440處理器的RTC工作原理 由RTC模塊的結(jié)構(gòu)圖可以看出,RTC模塊的有三種功能:產(chǎn)生時(shí)鐘滴答、實(shí)時(shí)計(jì)時(shí)和作為系統(tǒng)的觸發(fā)喚醒器。RTC時(shí)鐘滴答可以作為實(shí)時(shí)操作系統(tǒng)(RTOS)的內(nèi)核時(shí)鐘滴答,當(dāng)時(shí)鐘滴答周期確定后,就會(huì)定時(shí)產(chǎn)生中斷,操作系統(tǒng)的中斷服務(wù)程序會(huì)實(shí)時(shí)處理這個(gè)中斷。 RTC模塊可以在處理器的掉電模式或普通模式在設(shè)定時(shí)間(由BCD數(shù)據(jù)給出)和當(dāng)前時(shí)間相同時(shí)發(fā)生報(bào)警。在普通模式下,ALMINT(報(bào)警中斷)處于激活狀態(tài)。在掉電模式下,PMWKUP(電源管理喚醒信號(hào))與ALMINT一起處于報(bào)警狀態(tài)。 RTC最重要的功能就是顯示時(shí)間。在掉電模式下,RTC依然能夠正常工作,此時(shí),RTC模塊通過外部的電池工作。RTC時(shí)間顯示功能是通過讀/寫寄存器來實(shí)現(xiàn)的。要顯示秒、分、時(shí)、日期、月、年,處理器只要讀取存在于BCDSEC、BCDMIN、BCDHOUR、BCDDAY、BCDDATE、BCDMON和BCDYEAR寄存器中的值即可。 3 驅(qū)動(dòng)程序?qū)崿F(xiàn) 本RTC功能的實(shí)現(xiàn)在基于S3C2440嵌入式開發(fā)平臺(tái)上,通過WinCE下的RTC模塊的驅(qū)動(dòng)程序完成,而WinCE下RTC的驅(qū)動(dòng)是在底層實(shí)現(xiàn)的,具體要在OAL(OEM Adaption Layer)實(shí)現(xiàn)。下面對(duì)于OAL代碼層進(jìn)行簡要介紹,然后分析RTC驅(qū)動(dòng)代碼,在此基礎(chǔ)上給出部分源程序。 3.1 OAL概述 OAL的全稱是OEM Adaption Layer,即原始設(shè)備制造商適配層。從邏輯結(jié)構(gòu)上看,它位于操作系統(tǒng)的內(nèi)核與硬件之間,是連接系統(tǒng)與硬件的樞紐;從功能上看,OAL是被鏈接到內(nèi)核的庫,它可以用來創(chuàng)建內(nèi)核的可執(zhí)行文件。OAL在系統(tǒng)內(nèi)核與目標(biāo)設(shè)備之間進(jìn)行通信,隸屬于操作系統(tǒng).是操作系統(tǒng)的一部分。從存在方式上講OAL是一組函數(shù)的集合體,這些函數(shù)體現(xiàn)出OAL的功能,如圖2所示。 圖2 OAL功能結(jié)構(gòu)關(guān)系框圖 OAL層包含Startup()、OEMInit()、實(shí)時(shí)時(shí)鐘函數(shù)、串口調(diào)試函數(shù)、底層中斷處理函數(shù)、以太網(wǎng)口調(diào)試函數(shù)、KITL(Kernel Independent Transport Layer)內(nèi)核獨(dú)立傳輸層,此外,它還實(shí)現(xiàn)了包括電源管理、模塊認(rèn)證等高級(jí)功能。 WinCE的啟動(dòng)過程為:CPU執(zhí)行引導(dǎo)向量,跳轉(zhuǎn)到硬件初始化代碼,即Startup函數(shù)。 在Startup函數(shù)完成最小硬件環(huán)境初始化后跳轉(zhuǎn)到KernelStart函數(shù)來對(duì)內(nèi)核進(jìn)行初始化;KernelStart函數(shù)調(diào)用OEMInitDebugSerial完成對(duì)調(diào)試串口的初始化,調(diào)用OEMInit函數(shù)來完成硬件初始化工作以及設(shè)置時(shí)鐘、中斷,調(diào)用OEMGetExtensionDRAM函數(shù)來判斷是否還有另一塊DRAM。 因此,實(shí)時(shí)時(shí)鐘驅(qū)動(dòng)實(shí)現(xiàn)代碼是在OAL層實(shí)現(xiàn)的,當(dāng)Windows CE啟動(dòng)時(shí),會(huì)調(diào)用實(shí)時(shí)時(shí)鐘函數(shù)來初始化系統(tǒng)時(shí)間,下面介紹這些函數(shù)的具體實(shí)現(xiàn)。 3.2 時(shí)鐘函數(shù) 實(shí)現(xiàn)RTC功能需要編寫3個(gè)函數(shù),分別是OEMGetRealTime()、OEMSetRealTime()與OEMSetAlarmTime()。下面對(duì)于這三個(gè)函數(shù)分別介紹。 OEMGetRealTime()得到當(dāng)前時(shí)間。此函數(shù)名不可更改,是WinCE內(nèi)核規(guī)定好了的,也就是當(dāng)內(nèi)核需要知道當(dāng)前時(shí)間的時(shí)候直接調(diào)用此函數(shù)。圖3為函數(shù)OEMGetRealTime()執(zhí)行流程。 由于RTC不能任意地修改,不然會(huì)造成時(shí)間的混亂,所以每次獲取時(shí)間或者設(shè)置時(shí)間完畢以后必須禁止RTC,具體是通過設(shè)置RTC使能/禁止寄存器實(shí)現(xiàn)的。而在每次讀取時(shí)間或者設(shè)置時(shí)間的時(shí)候必須先使用它。在讀取時(shí)間的時(shí)候 若讀取的“秒”為0必須重新讀取時(shí)間,因此時(shí)的“分”已經(jīng)被進(jìn)位了。 OEMSetRealTime()設(shè)置時(shí)間。與OEMGetRealTime()一樣,它也不可改名,通過此函數(shù)核心可以直接修改時(shí)間。也就是說,如果用戶點(diǎn)擊WinCE任務(wù)欄中的時(shí)間以后,修改時(shí)間最終都是調(diào)用此函數(shù)。 OEMSetAlarmTime()設(shè)置系統(tǒng)報(bào)警時(shí)間,其參數(shù)為指向含有SYSTEMTIME結(jié)構(gòu)體緩沖區(qū)的長指針。如果此函數(shù)執(zhí)行成功則返回TRUE,執(zhí)行失敗則返回FALSE。此函數(shù)必須是可重人的以防止對(duì)硬件的多次操作。對(duì)于一般用戶的操作,用戶可以不用編寫此函數(shù)。如果需要系統(tǒng)在特定的時(shí)間完成特定的功能就需要完成此函數(shù)的編寫。 下面給出OEMGetRealTime()的源代碼僅供參考。 OEMGetRealTime(LPSYSTEMTIME lpst) { volatile RTCreg *s2440RTC; s2440RTC = (RTCreg *)RTC_BASE; //RETAILMSG(1,(_T("OEMGetRealTime "))); //使能RTC s2440RTC->rRTCCON =0x1; lpst->wMilliseconds=0; lpst->wSecond= FROM_BCD(s2440RTC->rBCDSEC&0x7f); lpst->wMinute= FROM_BCD(s2440RTC->rBCDMIN&0x7f); lpst->wHour= FROM_BCD(s2440RTC->rBCDHOUR&0x3f); lpst->wDayOfWeek=(s2440RTC->rBCDDATE-1); lpst->wDay= FROM_BCD(s2440RTC->rBCDDAY&0x3f); lpst->wMonth=FROM_BCD(s2440RTC->rBCDMON&0x1f); //lpst->wYear=(2000+s2440RTC->rBCDYEAR); lpst->wYear=FROM_BCD(s2440RTC->rBCDYEAR)+2000; if(lpst->wSecond==0) { lpst->wSecond=FROM_BCD(s2440RTC->rBCDSEC&0x7f); lpst->wMinute=FROM_BCD(s2440RTC->rBCDMIN&0x7f); lpst->wHour=FROM_BCD(s2440RTC->rBCDHOUR&0x3f); lpst->wDayOfWeek=(s2440RTC->rBCDDATE-1); lpst->wDay=FROM_BCD(s2440RTC->rBCDDAY&0x3f); lpst->wMonth=FROM_BCD(s240RTC->rBCDMON&0x1f); lpst->wYear=(2000+s240RTC->rBCDYEAR); } //禁止RTC s2440RTC->rRTCCON=0; return TRUE; } 3.3 系統(tǒng)I/O OAL代碼層提供了與內(nèi)核交互的函數(shù),通過它內(nèi)核可以獲得硬件平臺(tái)的信息 。在OAL層中,完成此功能的函數(shù)為OEMIOcontrol()。其函數(shù)原型如下: Bool OEMIoContol(……) {switch(dwIoContro1) {case IOCTL_HAL_INIT_RTC; if(nInBufSize>= sizeof(SYSTEMTIME)) return OEMSetRealTime((LPSYSTEMTIME)lpInBuf); else return FALSE; break; …… default: return FALSE; } WinCE每次啟動(dòng)時(shí)都會(huì)由KernelIoContrl()函數(shù)調(diào)用OEMIOcontrol(),完成底層硬件信息的讀取,其中參數(shù)dwIoControl為內(nèi)核與OAL通信的控制代碼,通過它可以完成硬件信息的讀取。控制代碼一般都是微軟定義好的,其中RTC模塊定義的控制代碼為IOCTL_HAL_INIT_RTC,通過它內(nèi)核可以完成底層RTC模塊的初始化。 nInBufSize是由lpInBuf(指針)指向的緩沖區(qū)的大小,緩沖區(qū)是按字節(jié)大小計(jì)算的。SYSTEMTIME是WinCE內(nèi)部定義的一個(gè)表示時(shí)間的結(jié)構(gòu)體,LPSYSTEMTIME為指向此結(jié)構(gòu)體的指針。SYSTEMTIME結(jié)構(gòu)體原型如下,原型中定義了字格式的年、月、星期、日、時(shí)、分、秒、毫秒。 typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSeeond; WORD wMilliseconds; }SYSTEMTIME; 在本設(shè)計(jì)中,RTC的時(shí)間分辨率為“秒”,這是因?yàn)镾3C2440的RTC模塊所能提供的最小時(shí)間基準(zhǔn)就是“秒”。用戶可以根據(jù)實(shí)際需求編寫系統(tǒng)I/O下的RTC初始化代碼,也可以禁止這部分代碼。若WinCE從OAL層讀不到時(shí)鐘參數(shù)的話,它會(huì)以系統(tǒng)的默認(rèn)時(shí)間值來初始化SYSTEMTIME結(jié)構(gòu)體。 4 結(jié)束語 當(dāng)前比較流行的ARM嵌入式處理器,如Samsung的S3C系列、Intel的Xscale系列、Motorola的龍珠系列等幾乎都內(nèi)嵌有RTC模塊。使許多嵌入式產(chǎn)品如手機(jī)、PDA等的時(shí)間顯示豐富多彩,如具有顯示陽歷、陰歷、萬年歷等功能。本文給出了RTC模塊的WinCE驅(qū)動(dòng)程序?qū)崿F(xiàn),基于本設(shè)計(jì)可以進(jìn)一步開發(fā)如時(shí)鐘界面等時(shí)鐘應(yīng)用功能,以滿足多姿多彩的嵌入式系統(tǒng)對(duì)于時(shí)鐘功能的應(yīng)用需求。 |