GNU ARM汇编--(十)s3c2440的RTC
RTC
概述
在系统电源关掉时RTC可以在备份电池的支持下来工作.RTC可以使用STRB/LDRB指令传输8bit的BCD值到CPU.数据包括秒,分,时,日期,天,月和年.RTC工作在外部32.768KHz的晶振下,而且有报警功能.
属性
BCD:秒,分,时,日期,天,月和年
闰年产生器
报警功能:报警中断 从power-off模式唤醒
独立的电源管脚(RTCVDD)
为RTOS kernel time tick支持毫秒级的tick.
闰年产生器
闰年产生器通过BCDDATA,BCDMON和BCDYEAR来决定每个月最后一天的日期.一个8bit的计数器只能表示两个BCD码,所以无法决定'00'年是否是闰年.举个例子,它不能区分1900和2000.为了解决这个问题,s3c2440的RTC模块在硬件逻辑上支持闰年是2000.1900不是闰年而2000时闰年.因此s3c2440的00表示2000,而不是1900.
READ/WRITE REGISTERS
为了写BCD寄存器,RTCCON寄存器的第0位必须置高.为了显示秒,分,时,日期,月和年,CPU从BCDSEC,BCDMIN,BCDHOUR,BCDDAY,BCDDATE,BCDMON和BCDYEAR寄存器中读数据.然而,在读取多个寄存器时,可能会有1秒的偏移.比如,当user读数据的时候,假设结果是2059(Year),12(Month),31(Date),23(Hour)和59(Minute).当user读BCDSEC寄存器,值的范围是1--59s,到这没有问题,但是,如果这个值是0s,由于刚才提到的那一s的偏移,年月日时分就会变为2060(year),1(Month),1(Date),0(Hour)和0(Minute).在这种情况下,如果BCDSEC是0 user应该重读各个寄存器.
BACKUP BATTERY OPERATION
RTC由备份电池驱动,及时系统电源断了,备份电池可以通过RTCVDD管脚向RTC模块供电.当系统关闭,CPU和RTC逻辑之间的接口是封闭的,备份电池只是驱动晶振电路和BCD计数器来减少电源消耗.
ALARM FUNCTION
在power-off模式或者正常操作模式下,RTC可以在一个指定的时间产生一个报警信号.在正常操作模式下,报警中断(INT_RTC)是激活的.在power-off模式,电源管理唤醒信号(PMWKUP)和INT_RTC都是激活的.RTC报警寄存器(RTCALM)决定是否开启报警状态和报警时间的设置.
TICK TIME INTERRUPT
RTC的tick time用于中断请求.TICNT寄存器有中断使能位和中断的计数值.当tick time中断产生计数值为0.中断的周期:
Period = (n+1)/128 second
n:Tick time count value(1~127)
REAL TIME CLOCK SPECIAL REGISTERS
RTCCON
RTCCON控制4个bits,比如RTCEN控制BCD寄存器的读写使能,CLKSEL,CNTSEL和CLKRST是用于测试的.
RTCEN bit控制CPU与RTC之间的所有接口,所以在系统重启后应该在RTC控制程序中将其设为1来使能数据的读写.在电源关闭前,RTCEN应该清0来防止对RTC寄存器的不经意的写入.
Register Address R/W Description Reset Value
RTCCON 0x57000040(L)/0x57000043(B) R/W RTC control register 0x0
RTCCON Bit Description Initial State
RTCEN [0] RTC控制使能 0
注意:所有的RTC寄存器都要以字节为单位来访问,可以用STRB和LDRB汇编指令或者char类型的指针.
TICNT
Register Address R/W Description Reset Value
TICNT 0x57000044(L)/0x57000047(B) R/W(by byte) Tick time count register 0x0
TICNT BIT Description Initial State
TICK INT ENABLE [7] tick time 中断使能 0
TICK TIME COUNT [6:0] tick time 计数值(1~127) 000000
RTCALM
RTCALM决定alarm使能和alarm时间.在power-off模式下RTCALM寄存器通过INT_RTC和PWMKUP产生报警信号,而在正常模式下只通过INT_RTC.
Register Address R/W Description Reset Value
RTCALM 0x57000050(L)/0x57000053(B) R/W(by type) RTC报警控制寄存器 0x0
RTCALM Bit Description Initial State
ALMEN [6] 报警总开关 0
YEAREN [5] Year报警开关 0
MONREN [4] Month报警开关 0
DATEEN [3] Date报警开关 0
HOUREN [2] Hour报警开关 0
MINEN [1] Minute报警开关 0
SECEN [0] Second报警开关 0
ALMSEC
设置Second报警的具体秒数
ALMMIN
设置Minute报警的具体分钟数
ALMHOUR
设置Hour报警的具体小时数
ALMDATE
设置Date报警的具体日期
ALMMON
设置Mon报警的具体月份
ALMYEAR
设置Year报警的具体年份
BCDSEC BCDMIN BCDHOUR BCDDATE BCDMON BCDYEAR
用BCD码表示的秒 分 时 日期 月份 年
给出报警中断的rtc汇编和c代码如下,在报警中断时是调用PWM的蜂鸣器来做闹钟的:
start.S:
#include <stdarg.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include "rtc_uart_test.h"extern void Buzzer_Freq_Set(int freq);//extern void Buzzer_Freq_Set( void );char uart_GetByte(void){while(!(rUTRSTAT0 & 0x1)); //Wait until THR is empty.return RdURXH0();}void uart_GetString(char *pt){while(*pt)uart_GetByte();}void uart_SendByte(int data){if(data=='\n'){while(!(rUTRSTAT0 & 0x2));WrUTXH0('\r');}while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.WrUTXH0(data);} //====================================================================void uart_SendString(char *pt){while(*pt) uart_SendByte(*pt++);}void uart_Printf(char *fmt,...){va_list ap;char string[256];va_start(ap,fmt);//vsprintf(string,fmt,ap);uart_SendString(string);va_end(ap);}void uart_test(void){char str[20] = "\nhello world\n";int a = 97;//while(1)//uart_SendByte(a);uart_SendString(str);char s = uart_GetByte();//if(s == 'a')if(s == 97)rGPBDAT = 0x1c0;//uart_SendByte(a);//uart_SendByte(97);//uart_SendByte('a');uart_SendByte((int)s);uart_SendByte((int)'s');}void rtc_uart_test(void){rRTCCON = 0x1;rTICNT = 0x0;rRTCALM = 0x42;rBCDYEAR = 0x10 ;rBCDMON = 0x11 ;rBCDDATE = 0x07 ;rBCDDAY = 0x05 ;rBCDHOUR = 0x12 ;rBCDMIN = 0x03 ;rBCDSEC = 0x00 ;rALMMIN = 0x04;uart_SendString("begin\n");//uart_Printf("year:%d\n",rBCDYEAR);}void pwm_uart_test(void){int freq = 10;int i;for(i=0; i<100;i++)uart_SendString("app\n");//Buzzer_Freq_Set( freq ) ;//Buzzer_Freq_Set( ) ;//uart_test();uart_SendString("start\n");/*int i;for(i=0;i<1000;i++)uart_SendString("wait\n"); while( 1 ) {char key = uart_GetByte();uart_SendByte(key);if( key == 'a' || key == 'A' ){if( freq < 2000 ) //lci 20000freq += 10 ;uart_SendByte('a');Buzzer_Freq_Set( freq ) ;}if( key == 'b' || key == 'B' ){if( freq > 11 )freq -= 10 ;uart_SendByte('b');Buzzer_Freq_Set( freq ) ;}//uart_SendString( "\tFreq = %d\n", freq ) ;//if( key == ESC_KEY )//{//Buzzer_Stop() ;//return ;//}}*/}
ldr r2, =BCDSEC @BCDMIN
ldr r1,[r2]
cmp r1, #0x06
bleq ledon
通过这里的判断,可以明确时间有被设进去,可是时间不走.经过google,才确定是寄存器的设置问题.
到此,rtc的闹钟也实现了功能.明天就用这个做闹钟吧~~