一文搞懂Cortex-A9 RTC(下)

电子说

1.2w人已加入

描述

2. 操作滴答定时器

TICNT

时钟芯片

TICNT

RTC计时器是一个递增计数器,并引发计时中断。TICNT寄存器包含32位目标计数值,并且CURTICCNT寄存器包含32位当前计时计数。如果当前滴答数达到TICNT中指定的目标值时,计时中断发生。

一秒钟计数的次数,由RTCCON[7:4]即TICCKSEL位决定:

时钟芯片

TICCKSEL

因为我们的晶振频率也是32768,为方便计数,所以我们设置RTCCON[7:4]为0,开启滴答计时器需要设置RTCCON[8]位1:

时钟芯片

TICEN

代码如下:

RTCCON = RTCCON & (~(0xf << 4)) | (1 << 8);
 TICCNT = 32768;

3. 操作ALARM闹钟

RTCALM

时钟芯片RTCALM寄存器控制报警功能的启用和报警时间。请注意,RTCALM寄存器在断电模式下将同时生成ALARM_INT和ALARM_WK信号,但在正常模式下仅生成ALARM_INT信号。设置ALMEN[6]为1以产生ALARM_INT和ALARM_WK信号。

「举例:」

比如我们想每个小时的25分58秒产生一个中断信号,那我们需要设置RTCALM[1]、RTCALM[0]为1,同时设置RTCALM[6]为1以开启alarm功能,然后将BCD格式的时间设置到寄存器ALMSEC、ALMMIN。

代码如下:

RTCALM.ALM = (1 << 6)|(1 << 0)|(1 << 1);//使能bite:MINEN、SECEN
 RTCALM.SEC = 0x58;
 RTCALM.MIN = 0x25;  //每小时25:58产生一次中断

alarm功能设置闹钟时间寄存器如下:

时钟芯片时钟芯片时钟芯片时钟芯片时钟芯片时钟芯片寄存器操作,采用BCD格式。

五、完整代码实现

滴答计时器和alarm闹钟会产生内部中断信号,所以我们必须给这两个中断信号进行中断相关的初始化,并在中断处理函数中增加相应的处理代码。

中断号

参考datasheet 9.2.2 GIC Interrupt Table

时钟芯片

rtc中断号

关于中断的初始化的寄存器配置,我们可以参考《11. 从0开始学ARM-基于Exynos4412中断详解、key程序编写》

区别是,key连接在了第一级中断控制器,而rtc的这两个中断则没有。清中断需要设置的寄存器如下:

「滴答计时器清中断:」

RTCINTP  = RTCINTP | (1 << 0);
//清GIC中断标志位
ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 13);
//清cpu中断标志位
CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num;

「alarm计时器清中断:」

RTCINTP  = RTCINTP | (1 << 1);
//清GIC中断标志位
ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 12);
//清cpu中断标志位
CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num;

「滴答计时器中断初始化:」

void rtc_tic(void)
{
 RTCCON = RTCCON & (~(0xf << 4)) | (1 << 8);
 TICCNT = 32768;
 ICDDCR = 1;  //使能分配器
 ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 13); //使能相应中断到分配器
 ICDIPTR.ICDIPTR19 = ICDIPTR.ICDIPTR19 & (~(0xff << 8))|(0x1 << 8); //选择CPU接口
 CPU0.ICCPMR = 255; //中断屏蔽优先级
 CPU0.ICCICR = 1;   //使能中断到CPU
}

「alarm初始化」

void rtc_alarm(void)
{
 RTCALM.ALM = (1 << 6)|(1 << 0)|(1 << 1);
 RTCALM.SEC = 0x58;
 RTCALM.MIN = 0x25;  //每小时25:58产生一次中断
 ICDDCR = 1;    //使能分配器
  //使能相应中断到分配器
 ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 12);
 //选择CPU接口
 ICDIPTR.ICDIPTR19 = ICDIPTR.ICDIPTR19 & (~(0xff << 0))|(0x1 << 0); 
 CPU0.ICCPMR = 255; //中断屏蔽优先级
 CPU0.ICCICR = 1;   //使能中断到CPU
}

「中断处理函数」

void do_irq(void)
{
 static int a = 1;
 int irq_num;
 irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号
 switch(irq_num)
 {
  case 57: //按键key
   printf("in the irq_handler\\n");
   //清GPIO中断标志位
   EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); 
   //清GIC中断标志位
   ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); 
  break;
  case 76:
   printf("in the alarm interrupt!\\n");
   RTCINTP  = RTCINTP | (1 << 1);
   //清GIC中断标志位
   ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 12); 
  break;
  case 77:
   printf("in the tic interrupt!\\n");
   RTCINTP  = RTCINTP | (1 << 0);
    //清GIC中断标志位
   ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 13);
   break;
 }
 //清cpu中断标志位
 CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; 
}

「其他代码:」

void rtc_init(void)
{
 RTCCON = 1;//使能RTC控制写功能
 RTC.BCDYEAR = 0x20;// 20201111日, 15:24:50.以BCD码格式写入
 RTC.BCDMON = 0x11;
 RTC.BCDDAY = 0x11;
 RTC.BCDHOUR = 0x15;
 RTC.BCDMIN = 0x24;
 RTC.BCDSEC = 0x50;
 RTCCON = 0;//关闭RTC控制写功能
}
int main (void)
{     rtc_init();
  rtc_alarm();
  rtc_tic();
  //每隔一秒打印以下当前时间
  while(1)
  {
   printf("%x-%x-%x %x:%x:%x\\n",RTC.BCDYEAR,
   RTC.BCDMON,
   RTC.BCDDAY,
   RTC.BCDHOUR,
   RTC.BCDMIN,RTC.BCDSEC);
   delay_ms(1000);
  }
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分