/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2020-05-19 shelton first version * 2021-08-125 Dozingfiretruck implement RTC framework V2.0 */ #include "board.h" #include #include #include #ifdef BSP_USING_RTC #ifndef BKP_DR1 #define BKP_DR1 RT_NULL #endif //#define DRV_DEBUG #define LOG_TAG "drv.rtc" #include #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."); return timegm(&tm_new); #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; p_tm = gmtime(&time_stamp); 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 /* Set the RTC counter value */ RTC_SetCounter(time_stamp); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); #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; } static rt_err_t rt_rtc_config(void) { #if defined (SOC_SERIES_AT32F415) ERTC_InitType ERTC_InitStructure; #endif /* Allow access to BKP Domain */ PWR_BackupAccessCtrl(ENABLE); #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 { LOG_I("RTC hasn't been configured, please use 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; } static rt_err_t _rtc_init(void) { #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; } static rt_err_t _rtc_get_secs(void *args) { *(rt_uint32_t *)args = get_rtc_timestamp(); LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args); return RT_EOK; } static rt_err_t _rtc_set_secs(void *args) { rt_err_t result = RT_EOK; if (set_rtc_time_stamp(*(rt_uint32_t *)args)) { result = -RT_ERROR; } LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args); return result; } static const struct rt_rtc_ops _rtc_ops = { _rtc_init, _rtc_get_secs, _rtc_set_secs, RT_NULL, RT_NULL, RT_NULL, RT_NULL, }; static rt_rtc_dev_t at32_rtc_dev; int rt_hw_rtc_init(void) { rt_err_t result; at32_rtc_dev.ops = &_rtc_ops; result = rt_hw_rtc_register(&at32_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR,RT_NULL); 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 */