#include "rtc.h" #include "settings_api.h" #include "common_config.h" #include #include // Days in a month uint8_t TM_RTC_Months[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // Not leap year {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // Leap year }; // monthly correction data sheet const uint8_t table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; // monmonth data table of common year const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Internal RTC defines #define TM_RTC_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) #define TM_RTC_DAYS_IN_YEAR(x) TM_RTC_LEAP_YEAR(x) ? 366 : 365 #define TM_RTC_OFFSET_YEAR 1970 #define TM_RTC_SECONDS_PER_DAY 86400 #define TM_RTC_SECONDS_PER_HOUR 3600 #define TM_RTC_SECONDS_PER_MINUTE 60 #define TM_RTC_BCD2BIN(x) ((((x) >> 4) & 0x0F) * 10 + ((x) & 0x0F)) #define TM_RTC_CHAR2NUM(x) ((x) - '0') #define TM_RTC_CHARISNUM(x) ((x) >= '0' && (x) <= '9') extern SemaphoreHandle_t flash_mutex; /** * @brief rtc peripheral initialization. * @param calendar * @retval 0: rtc already init 1: rtc init */ uint8_t TM_RTC_Init(void) { TM_RTC_t datatime; uint16_t tmp = 0; // enable pwc and bpr clocks crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE); // enable the battery-powered domain write operations pwc_battery_powered_domain_access(TRUE); tmp = bpr_data_read(BACKUP_RTC_KEY); printf("RTC: %X\r\n", tmp); // check if rtc is initialized if (bpr_data_read(BACKUP_RTC_KEY) != 0x1234) { // reset battery-powered domain register bpr_reset(); // enable the lext osc crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE); // wait lext is ready while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET); // select the rtc clock source crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT); // enable rtc clock crm_rtc_clock_enable(TRUE); // wait for rtc registers update rtc_wait_update_finish(); // wait for the register write to complete rtc_wait_config_finish(); // enable the rtc second nvic_irq_enable(RTC_IRQn, 6, 0); rtc_interrupt_enable(RTC_TS_INT, TRUE); // set rtc divider: set rtc period to 1sec rtc_divider_set(32767); // wait for the register write to complete rtc_wait_config_finish(); // set date and time datatime.date = 1; datatime.day = 1; datatime.month = 1; datatime.year = 0; datatime.hours = 0; datatime.minutes = 0; datatime.seconds = 0; TM_RTC_SetDateTime(&datatime); // writes data to bpr register bpr_data_write(BACKUP_RTC_KEY, 0x1234); return 1; } else { // wait for rtc registers update rtc_wait_update_finish(); // wait for the register write to complete rtc_wait_config_finish(); // enable the rtc second nvic_irq_enable(RTC_IRQn, 6, 0); rtc_interrupt_enable(RTC_TS_INT, TRUE); return 0; } } // void TM_RTC_SetDataTimeUnix(uint32_t unixTime) { TM_RTC_t data; TM_RTC_GetDateTimeFromUnix(&data, unixTime); rtc_counter_set(unixTime); rtc_wait_config_finish(); } /** * @brief set time. convert the input clock to a second. * the time basic : 1970.1.1 * legitimate year: 1970 ~ 2099 * @param calendar * @retval 0: set time right. * 1: set time failed. */ TM_RTC_Result_t TM_RTC_SetDateTime(TM_RTC_t* data) { uint32_t seccount = 0; if (data->year > 99 || data->month == 0 || data->month > 12 || data->date == 0 || data->date > TM_RTC_Months[TM_RTC_LEAP_YEAR(2000 + data->year) ? 1 : 0][data->month - 1] || data->hours > 23 || data->minutes > 59 || data->seconds > 59 || data->day == 0 || data->day > 7) { return TM_RTC_Result_Error; } // enable pwc and bpr clocks crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE); // enable write access to bpr domain pwc_battery_powered_domain_access(TRUE); // set the rtc counter value seccount = TM_RTC_GetUnixTimeStamp(data); rtc_counter_set(seccount); // wait for the register write to complete rtc_wait_config_finish(); return TM_RTC_Result_Ok; } // TM_RTC_Result_t TM_RTC_SetDateTimeString(char* str) { TM_RTC_t tmp; uint8_t i = 0; // Get date tmp.date = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.date = tmp.date * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get month tmp.month = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.month = tmp.month * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get year tmp.year = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.year = tmp.year * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get day in a week tmp.day = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.day = tmp.day * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get hours tmp.hours = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.hours = tmp.hours * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get minutes tmp.minutes = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.minutes = tmp.minutes * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Get seconds tmp.seconds = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.seconds = tmp.seconds * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; // Return status from set date time function return TM_RTC_SetDateTime(&tmp); } // void TM_RTC_GetDateTime(TM_RTC_t* data, TM_RTC_Format_t format) { (void)format; uint32_t unix = rtc_counter_get(); TM_RTC_GetDateTimeFromUnix(data, unix); } // uint32_t TM_RTC_GetUnixTimeStamp(TM_RTC_t* data) { uint32_t days = 0, seconds = 0; uint16_t i; uint16_t year = (uint16_t)(data->year + 2000); // Year is below offset year if (year < TM_RTC_OFFSET_YEAR) { return 0; } // Days in back years for (i = TM_RTC_OFFSET_YEAR; i < year; i++) { days += TM_RTC_DAYS_IN_YEAR(i); } // Days in current year for (i = 1; i < data->month; i++) { days += TM_RTC_Months[TM_RTC_LEAP_YEAR(year)][i - 1]; } // Day starts with 1 days += data->date - 1; seconds = days * TM_RTC_SECONDS_PER_DAY; seconds += data->hours * TM_RTC_SECONDS_PER_HOUR; seconds += data->minutes * TM_RTC_SECONDS_PER_MINUTE; seconds += data->seconds; // seconds = days * 86400; return seconds; } // void TM_RTC_GetDateTimeFromUnix(TM_RTC_t* data, uint32_t unix) { uint16_t year; // Store unix time to unix in struct data->unix = unix; // Get seconds from unix data->seconds = unix % 60; // Go to minutes unix /= 60; // Get minutes data->minutes = unix % 60; // Go to hours unix /= 60; // Get hours data->hours = unix % 24; // Go to days unix /= 24; // Get week day // Monday is day one data->day = (unix + 3) % 7 + 1; // Get year year = 1970; while (1) { if (TM_RTC_LEAP_YEAR(year)) { if (unix >= 366) { unix -= 366; } else { break; } } else if (unix >= 365) { unix -= 365; } else { break; } year++; } // Get year in xx format data->year = (uint8_t) (year - 2000); // Get month for (data->month = 0; data->month < 12; data->month++) { if (TM_RTC_LEAP_YEAR(year) && unix >= (uint32_t)TM_RTC_Months[1][data->month]) { unix -= TM_RTC_Months[1][data->month]; } else if (unix >= (uint32_t)TM_RTC_Months[0][data->month]) { unix -= TM_RTC_Months[0][data->month]; } else { break; } } // Get month // Month starts with 1 data->month++; // Get date // Date starts with 1 data->date = unix + 1; } // void TM_RTC_PrintTime(void) { TM_RTC_t data; uint32_t unix = rtc_counter_get(); TM_RTC_GetDateTimeFromUnix(&data, unix); printf("%02d.%02d.%02d %02d:%02d:%02d\r\n", data.date, data.month, data.year, data.hours, data.minutes, data.seconds); } // uint32_t RTC_GetUnixTime(void) { TM_RTC_t currentTime; TM_RTC_GetDateTime(¤tTime, TM_RTC_Format_BIN); return TM_RTC_GetUnixTimeStamp(¤tTime); } // void rtc_subtim_init(void) { crm_clocks_freq_type crm_clocks_freq_struct = {0}; crm_periph_clock_enable(CRM_TMR5_PERIPH_CLOCK, TRUE); crm_clocks_freq_get(&crm_clocks_freq_struct); tmr_base_init(TMR5, 9999, 24000 - 1); tmr_cnt_dir_set(TMR5, TMR_COUNT_UP); tmr_flag_clear(TMR5, TMR_OVF_FLAG); NVIC_ClearPendingIRQ(TMR5_GLOBAL_IRQn); nvic_irq_enable(TMR5_GLOBAL_IRQn, 5, 0); tmr_counter_enable(TMR5, TRUE); tmr_interrupt_enable(TMR5, TMR_OVF_INT, TRUE); } // uint64_t rtc_get_ms(void) { return ((uint64_t)RTC_GetUnixTime()*1000 + TMR5->cval/10); } // uint32_t rtc_foo(void) { return tmr_counter_value_get(TMR5); } // void rtc_set_in_ms(uint64_t ms) { TM_RTC_SetDataTimeUnix(ms); } // void TMR5_GLOBAL_IRQHandler(void) { if (tmr_flag_get(TMR5, TMR_OVF_FLAG) != RESET) { tmr_flag_clear(TMR5, TMR_OVF_FLAG); tmr_interrupt_enable(TMR5, TMR_OVF_INT, FALSE); tmr_counter_enable(TMR5, FALSE); } } // void RTC_IRQHandler(void) { if (rtc_flag_get(RTC_TS_FLAG) != RESET) { rtc_flag_clear(RTC_TS_FLAG); tmr_interrupt_enable(TMR5, TMR_OVF_INT, TRUE); tmr_counter_enable(TMR5, TRUE); TMR5->cval = 0; } }