| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 | #include "rtc.h"#include "settings_api.h"#include "common_config.h"#include <string.h>#include <stdio.h>// Days in a monthuint8_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 sheetconst uint8_t table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};// monmonth data table of common yearconst 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();    bpr_data_write(BACKUP_RTC_UPDATE, 0x1234);}/**  * @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;    }}
 |