IMX6ULL裸机-1-RTC定时器

发布时间:2024-07-03  

1 引入RTC定时器

RTC定时器被叫做实时时钟(real time clock)。 CPU内部有很多定时器,像看门狗WDT,PWM定时器,高精度定时器Timer等等, 只在“启动”即“通电时”运行,断电时停止。当然,如果时钟不能连续跟踪时间,则必须手动设置。那么当关机后就没办法自动计数统计时间了。 定时器的本质就是计数器,有向上计数,也有向下计数。RTC有一个与主机单独分离的电源,如纽扣电池(备用电池),即使主机电源关闭,它也保持计数定时功能。这也是为什么我们手机关机后时间还能保持准确。再比如以前的老诺基亚手机,拆掉电池就时间不准了,因为rtc电源被切断了,无法在计数,RTC定时器的计数器会被清0,需要手动设置当前时间。 RTC一般都是用纽扣电池给外部晶振和电路供电。 !

2 RTC定时器原理

以IMX6U芯片的RTC定时器为例,I.MX6U 内部也有 个 RTC 模块,但是不叫作“RTC”,而是叫做“SNVS”。 RTC模块结构图如下:


SNVS 分为两个子模块:SNVS_HP 和 SNVS_LP,也就是高功耗域(SNVS_HP)和低功耗域(SNVS_LP),这两个域的电源来源如下:

SNVS_LP:专用的 always-powered-on 电源域,系统主电源和备用电源都可以为其供电。
SNVS_HP:系统(芯片)电源。

系统主电源断电以后 SNVS_HP 也会断电,但是在备用电源支持下,SNVS_LP 是不会断电的,而且 SNVS_LP 是和芯片复位隔离开的,因此 SNVS_LP 相关的寄存器的值会一直保存着, 也就是low Power Domain是不受系统电源影响。 上图各个序号含义如下: ①、VDD_HIGH_IN 是系统(芯片)主电源,这个电源会同时供给给 SNVS_HP 和 SNVS_LP。 ②、VDD_SNVS_IN 是纽扣电池供电的电源,这个电源只会供给给 SNVS_LP,保证在系统主电源 VDD_HIGH_IN 掉电以后 SNVS_LP 会继续运行。 ③、SNVS_HP 部分。 ④、SNVS_LP 部分,此部分有个 SRTC,这个就是要使用的 RTC。 SRTC 需要外界提供一个 32.768KHz 的时钟,I.MX6U-ALPHA 核心板上的 32.768KHz 的晶振就是提供这个时钟的。


3 RTC定时器寄存器

SNVS_SRTCMR[14:0]代表SRTC计数器的高15位 SNVS_SRTCLR[31:15]代表SRTC计数器的低17位 注意:是以 1970 年 1 月 1 日0点0分0秒为起点,加上经过的总秒数即可得到现在的时间点。 SNVS_HPCOMR[31], NPSWA_EN位,非特权软件访问控制位,如果非特权软件要访问 SNVS 的话此位必须为 1。 SNVS_LPCR[0], SRTC_ENV位,使能 STC 计数器。

4 RTC裸机源码展示

NXP 官方 SDK 包是针对 I.MX6ULL 编写的,因此文件 MCIMX6Y2.h中的结构体 SNVS_Type 里面的寄存器是不全的,我们需要在其中加入本章实验所需要的寄存器,修改 SNVS_Type 为如下所示:


/*!

 * @addtogroup SNVS_Peripheral_Access_Layer SNVS Peripheral Access Layer

 * @{

 */


/** SNVS - Register Layout Typedef */

/* zuozhongkai 2018/12/13 */

typedef struct {

  __IO uint32_t HPLR;                              /**< SNVS_HP Lock register, offset: 0x0 */

  __IO uint32_t HPCOMR;                            /**< SNVS_HP Command register, offset: 0x4 */

  __IO uint32_t HPCR;                              /**< SNVS_HP Control register, offset: 0x8 */

  __IO uint32_t HPSICR;                              /**< SNVS_HP Control register, offset: 0x8 */

  __IO uint32_t HPSVCR;   

  __IO uint32_t HPSR;   

  __IO uint32_t HPSVSR;

  __IO uint32_t HPHACIVR;

  __IO uint32_t HPHACR;

  __IO uint32_t HPRTCMR;

  __IO uint32_t HPRTCLR;

  __IO uint32_t HPTAMR;

  __IO uint32_t HPTALR;

  __IO uint32_t LPLR;

  __IO uint32_t LPCR;

  __IO uint32_t LPMKCR;

  __IO uint32_t LPSVCR;

  __IO uint32_t LPTGFCR;

  __IO uint32_t LPTDCR;

  __IO uint32_t LPSR;

  __IO uint32_t LPSRTCMR;

  __IO uint32_t LPSRTCLR;

  __IO uint32_t LPTAR;

  __IO uint32_t LPSMCMR;

  __IO uint32_t LPSMCLR;

}SNVS_Type;



bsp_rtc.h




#ifndef _BSP_RTC_H

#define _BSP_RTC_H

/***************************************************************

Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.

文件名 :    bsp_rtc.c

作者     : 左忠凯

版本     : V1.0

描述     : RTC驱动头文件。

其他     : 无

论坛     : www.wtmembed.com

日志     : 初版V1.0 2019/1/3 左忠凯创建

***************************************************************/

#include "imx6ul.h"


/* 相关宏定义 */ 

#define SECONDS_IN_A_DAY        (86400) /* 一天86400秒         */

#define SECONDS_IN_A_HOUR       (3600)  /* 一个小时3600秒        */

#define SECONDS_IN_A_MINUTE     (60)    /* 一分钟60秒           */

#define DAYS_IN_A_YEAR          (365)   /* 一年365天           */

#define YEAR_RANGE_START        (1970)  /* 开始年份1970年        */

#define YEAR_RANGE_END          (2099)  /* 结束年份2099年        */


/* 时间日期结构体 */   

struct rtc_datetime

{

    unsigned short year;  /* 范围为:1970 ~ 2099        */

    unsigned char month;  /* 范围为:1 ~ 12             */

    unsigned char day;    /* 范围为:1 ~ 31 (不同的月,天数不同).*/

    unsigned char hour;   /* 范围为:0 ~ 23             */

    unsigned char minute; /* 范围为:0 ~ 59             */

    unsigned char second; /* 范围为:0 ~ 59             */

};


/* 函数声明 */

void rtc_init(void);

void rtc_enable(void);

void rtc_disable(void);

unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime);

unsigned int rtc_getseconds(void);

void rtc_setdatetime(struct rtc_datetime *datetime);

void rtc_getdatetime(struct rtc_datetime *datetime);

#endif





bsp_rtc.c




/***************************************************************

Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.

文件名 :    bsp_rtc.c

作者     : 左忠凯

版本     : V1.0

描述     : RTC驱动文件。

其他     : 无

论坛     : www.wtmembed.com

日志     : 初版V1.0 2019/1/3 左忠凯创建

***************************************************************/

#include "bsp_rtc.h"

#include "stdio.h"


/* 

 * 描述:初始化RTC

 */

void rtc_init(void)

{

    /*

     * 设置HPCOMR寄存器

     * bit[31] 1 : 允许访问SNVS寄存器,一定要置1

     * bit[8]  1 : 此位置1,需要签署NDA协议才能看到此位的详细说明,

     *             这里不置1也没问题

     */

    SNVS->HPCOMR |= (1 << 31) | (1 << 8);


#if 0

    struct rtc_datetime rtcdate;


    rtcdate.year = 2018U;

    rtcdate.month = 12U;

    rtcdate.day = 13U;

    rtcdate.hour = 14U;

    rtcdate.minute = 52;

    rtcdate.second = 0;

    rtc_setDatetime(&rtcdate); //初始化时间和日期

#endif


    rtc_enable();   //使能RTC


}


/*

 * 描述: 开启RTC

 */

void rtc_enable(void)

{

    /*

     * LPCR寄存器bit0置1,使能RTC

     */

    SNVS->LPCR |= 1 << 0;   

    while(!(SNVS->LPCR & 0X01));//等待使能完成


}


/*

 * 描述: 关闭RTC

 */

void rtc_disable(void)

{

    /*

     * LPCR寄存器bit0置0,关闭RTC

     */

    SNVS->LPCR &= ~(1 << 0);    

    while(SNVS->LPCR & 0X01);//等待关闭完成

}


/*

 * @description : 判断指定年份是否为闰年,闰年条件如下:

 * @param - year: 要判断的年份

 * @return      : 1 是闰年,0 不是闰年

 */

unsigned char rtc_isleapyear(unsigned short year)

{   

    unsigned char value=0;


    if(year % 400 == 0)

        value = 1;

    else 

    {

        if((year % 4 == 0) && (year % 100 != 0))

            value = 1;

        else 

            value = 0;

    }

    return value;

}


/*

 * @description     : 将时间转换为秒数

 * @param - datetime: 要转换日期和时间。

 * @return          : 转换后的秒数

 */

unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime)

{   

    unsigned short i = 0;

    unsigned int seconds = 0;

    unsigned int days = 0;

    unsigned short monthdays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};


    for(i = 1970; i < datetime->year; i++)

    {

        days += DAYS_IN_A_YEAR;         /* 平年,每年365天 */

        if(rtc_isleapyear(i)) days += 1;/* 闰年多加一天       */

    }


    days += monthdays[datetime->month];

    if(rtc_isleapyear(i) && (datetime->month >= 3)) days += 1;/* 闰年,并且当前月份大于等于3月的话加一天 */


    days += datetime->day - 1;

    seconds = days * SECONDS_IN_A_DAY + 

                datetime->hour * SECONDS_IN_A_HOUR +

                datetime->minute * SECONDS_IN_A_MINUTE +

                datetime->second;

    return seconds; 

}


/*

 * @description     : 设置时间和日期

 * @param - datetime: 要设置的日期和时间

 * @return          : 无

 */

void rtc_setdatetime(struct rtc_datetime *datetime)

{

    unsigned int seconds = 0;

    unsigned int tmp = SNVS->LPCR; 


    rtc_disable();  /* 设置寄存器HPRTCMR和HPRTCLR的时候一定要先关闭RTC */


    /* 先将时间转换为秒         */

    seconds = rtc_coverdate_to_seconds(datetime);


    SNVS->LPSRTCMR = (unsigned int)(seconds >> 17); /* 设置高16位 */

    SNVS->LPSRTCLR = (unsigned int)(seconds << 15); /* 设置地16位 */


    /* 如果此前RTC是打开的在设置完RTC时间以后需要重新打开RTC */

    if (tmp & 0x1)

        rtc_enable();

}


/*

 * @description     : 将秒数转换为时间

 * @param - seconds : 要转换的秒数

 * @param - datetime: 转换后的日期和时间

 * @return          : 无

 */

void rtc_convertseconds_to_datetime(u64 seconds, struct rtc_datetime *datetime)

{

    u64 x;

    u64  secondsRemaining, days;

    unsigned short daysInYear;


    /* 每个月的天数       */

    unsigned char daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};


    secondsRemaining = seconds; /* 剩余秒数初始化 */

    days = secondsRemaining / SECONDS_IN_A_DAY + 1;         /* 根据秒数计算天数,加1是当前天数 */

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>