drv_rtc.c 5.7 KB
Newer Older
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
3 4 5 6
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
Dozingfiretruck's avatar
Dozingfiretruck 已提交
7 8 9
 * Date         Author              Notes
 * 2020-05-19   shelton             first version
 * 2021-08-125  Dozingfiretruck     implement RTC framework V2.0
10 11 12 13
 */

#include "board.h"
#include <rtthread.h>
Dozingfiretruck's avatar
Dozingfiretruck 已提交
14
#include <rtdevice.h>
15
#include <sys/time.h>
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

#ifdef BSP_USING_RTC

#ifndef BKP_DR1
#define BKP_DR1 RT_NULL
#endif

//#define DRV_DEBUG
#define LOG_TAG             "drv.rtc"
#include <drv_log.h>

#define BKUP_REG_DATA 0xA5A5

static time_t get_rtc_timestamp(void)
{
#ifdef SOC_SERIES_AT32F415
    struct tm tm_new;
    ERTC_TimeType ERTC_TimeStruct;
    ERTC_DateType ERTC_DateStruct;

    ERTC_GetTimeValue(ERTC_Format_BIN, &ERTC_TimeStruct);
    ERTC_GetDateValue(ERTC_Format_BIN, &ERTC_DateStruct);
    tm_new.tm_sec  = ERTC_TimeStruct.ERTC_Seconds;
    tm_new.tm_min  = ERTC_TimeStruct.ERTC_Minutes;
    tm_new.tm_hour = ERTC_TimeStruct.ERTC_Hours;
    tm_new.tm_mday = ERTC_DateStruct.ERTC_Date;
    tm_new.tm_mon  = ERTC_DateStruct.ERTC_Month - 1;
    tm_new.tm_year = ERTC_DateStruct.ERTC_Year + 100;

    LOG_D("get rtc time.");
46
    return timegm(&tm_new);
47 48 49 50 51 52 53 54 55 56 57 58 59
#else
    return RTC_GetCounter();
#endif
}

static rt_err_t set_rtc_time_stamp(time_t time_stamp)
{
#ifdef SOC_SERIES_AT32F415
    ERTC_TimeType  ERTC_TimeStructure;
    ERTC_DateType  ERTC_DateStructure;

    struct tm *p_tm;

mysterywolf's avatar
mysterywolf 已提交
60
    p_tm = gmtime(&time_stamp);
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    if (p_tm->tm_year < 100)
    {
        return -RT_ERROR;
    }
    ERTC_TimeStructure.ERTC_Seconds = p_tm->tm_sec ;
    ERTC_TimeStructure.ERTC_Minutes = p_tm->tm_min ;
    ERTC_TimeStructure.ERTC_Hours   = p_tm->tm_hour;
    ERTC_DateStructure.ERTC_Date    = p_tm->tm_mday;
    ERTC_DateStructure.ERTC_Month   = p_tm->tm_mon + 1 ;
    ERTC_DateStructure.ERTC_Year    = p_tm->tm_year - 100;
    ERTC_DateStructure.ERTC_WeekDay = p_tm->tm_wday + 1;

    if (ERTC_SetTimeValue(ERTC_Format_BIN, &ERTC_TimeStructure) != SUCCESS)
    {
        return -RT_ERROR;
    }
    if (ERTC_SetDateValue(ERTC_Format_BIN, &ERTC_DateStructure) != SUCCESS)
    {
        return -RT_ERROR;
    }
#else
mysterywolf's avatar
mysterywolf 已提交
82 83 84 85
    /* Set the RTC counter value */
    RTC_SetCounter(time_stamp);
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
86 87 88 89 90 91 92 93 94 95
#endif /* SOC_SERIES_AT32F415 */
    LOG_D("set rtc time.");
#ifdef SOC_SERIES_AT32F415
    ERTC_WriteBackupRegister(ERTC_BKP_DT0, BKUP_REG_DATA);
#else
    BKP_WriteBackupReg(BKP_DT1, BKUP_REG_DATA);
#endif
    return RT_EOK;
}

Dozingfiretruck's avatar
Dozingfiretruck 已提交
96
static rt_err_t rt_rtc_config(void)
97 98 99 100 101
{
#if defined (SOC_SERIES_AT32F415)
    ERTC_InitType ERTC_InitStructure;
#endif
    /* Allow access to BKP Domain */
mysterywolf's avatar
mysterywolf 已提交
102
    PWR_BackupAccessCtrl(ENABLE);
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

#ifdef SOC_SERIES_AT32F415
  #ifdef BSP_RTC_USING_LSI
    RCC_ERTCCLKConfig(RCC_ERTCCLKSelection_LSI);
    RCC_ERTCCLKCmd(ENABLE);
  #else
    RCC_ERTCCLKConfig(RCC_ERTCCLKSelection_LSE);
    RCC_ERTCCLKCmd(ENABLE);
  #endif /* BSP_RTC_USING_LSI */
    /* Wait for ERTC APB registers synchronisation */
    ERTC_WaitForSynchro();
#else
  #ifdef BSP_RTC_USING_LSI
    RCC_RTCCLKConfig(RCC_RTCCLKSelection_LSI);
    RCC_RTCCLKCmd(ENABLE);
  #else
    RCC_RTCCLKConfig(RCC_RTCCLKSelection_LSE);
    RCC_RTCCLKCmd(ENABLE);
  #endif /* BSP_RTC_USING_LSI */
    /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
#endif /* SOC_SERIES_AT32F415 */

#ifdef SOC_SERIES_AT32F415
    if (ERTC_ReadBackupRegister(BKP_DT1)!= BKUP_REG_DATA)
#else
    if (BKP_ReadBackupReg(BKP_DT1) != BKUP_REG_DATA)
#endif
mysterywolf's avatar
mysterywolf 已提交
133
    {
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        LOG_I("RTC hasn't been configured, please use <date> command to config.");
#ifdef SOC_SERIES_AT32F415
        /* Configure the ERTC data register and ERTC prescaler */
        ERTC_InitStructure.ERTC_AsynchPrediv = 0x7F;
        ERTC_InitStructure.ERTC_SynchPrediv = 0xFF;
        ERTC_InitStructure.ERTC_HourFormat = ERTC_HourFormat_24;
        ERTC_Init(&ERTC_InitStructure);
#else
        /* Set RTC prescaler: set RTC period to 1sec */
        RTC_SetDIV(32767);
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
#endif
    }
    return RT_EOK;
}

151
static rt_err_t _rtc_init(void)
Dozingfiretruck's avatar
Dozingfiretruck 已提交
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
{
#if defined (SOC_SERIES_AT32F415)
    RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR, ENABLE);
#else
    RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR | RCC_APB1PERIPH_BKP, ENABLE);
#endif

#ifdef BSP_RTC_USING_LSI
    RCC_LSICmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_LSISTBL) == RESET);
#else
    PWR_BackupAccessCtrl(ENABLE);
    RCC_LSEConfig(RCC_LSE_ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_LSESTBL) == RESET);
#endif /* BSP_RTC_USING_LSI */
    if (rt_rtc_config() != RT_EOK)
    {
        LOG_E("rtc init failed.");
        return -RT_ERROR;
    }

    return RT_EOK;
}

176
static rt_err_t _rtc_get_secs(void *args)
Dozingfiretruck's avatar
Dozingfiretruck 已提交
177 178 179 180 181 182 183
{
    *(rt_uint32_t *)args = get_rtc_timestamp();
    LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);

    return RT_EOK;
}

184
static rt_err_t _rtc_set_secs(void *args)
185 186
{
    rt_err_t result = RT_EOK;
Dozingfiretruck's avatar
Dozingfiretruck 已提交
187 188

    if (set_rtc_time_stamp(*(rt_uint32_t *)args))
189
    {
Dozingfiretruck's avatar
Dozingfiretruck 已提交
190
        result = -RT_ERROR;
191
    }
Dozingfiretruck's avatar
Dozingfiretruck 已提交
192
    LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);
193 194 195 196

    return result;
}

197
static const struct rt_rtc_ops _rtc_ops =
198
{
199 200 201
    _rtc_init,
    _rtc_get_secs,
    _rtc_set_secs,
202 203 204 205 206 207
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
};

Dozingfiretruck's avatar
Dozingfiretruck 已提交
208
static rt_rtc_dev_t at32_rtc_dev;
209 210 211 212

int rt_hw_rtc_init(void)
{
    rt_err_t result;
213
    at32_rtc_dev.ops = &_rtc_ops;
Dozingfiretruck's avatar
Dozingfiretruck 已提交
214
    result = rt_hw_rtc_register(&at32_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR,RT_NULL);
215 216 217 218 219 220 221 222 223 224 225 226
    if (result != RT_EOK)
    {
        LOG_E("rtc register err code: %d", result);
        return result;
    }
    LOG_D("rtc init success");
    return RT_EOK;
}

INIT_DEVICE_EXPORT(rt_hw_rtc_init);

#endif /* BSP_USING_RTC */