/*! \file gd32f4xx_rtc.c \brief RTC driver */ /* Copyright (C) 2016 GigaDevice 2016-08-15, V1.0.0, firmware for GD32F4xx */ #include "gd32f4xx_rtc.h" /* RTC timeout value */ #define RTC_WTWF_TIMEOUT ((uint32_t)0x00004000U) /*!< wakeup timer can be write flag timeout */ #define RTC_INITM_TIMEOUT ((uint32_t)0x00004000U) /*!< initialization state flag timeout */ #define RTC_RSYNF_TIMEOUT ((uint32_t)0x00008000U) /*!< register synchronization flag timeout */ #define RTC_HRFC_TIMEOUT ((uint32_t)0x20000000U) /*!< recalibration pending flag timeout */ #define RTC_SHIFTCTL_TIMEOUT ((uint32_t)0x00001000U) /*!< shift function operation pending flag timeout */ #define RTC_ALRMXWF_TIMEOUT ((uint32_t)0x00008000U) /*!< alarm configuration can be write flag timeout */ /*! \brief reset most of the RTC registers \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_deinit(void) { ErrStatus error_status = ERROR; volatile uint32_t time_index = RTC_WTWF_TIMEOUT; uint32_t flag_status = RESET; /* RTC_TAMP register is not under write protection */ RTC_TAMP = RTC_REGISTER_RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ /* reset RTC_CTL register, but RTC_CTL[2£º0] */ RTC_CTL &= (RTC_REGISTER_RESET | RTC_CTL_WTCS); /* before reset RTC_TIME and RTC_DATE, BPSHAD bit in RTC_CTL should be reset as the condition. in order to read calendar from shadow register, not the real registers being reset */ RTC_TIME = RTC_REGISTER_RESET; RTC_DATE = RTC_DATE_RESET; RTC_PSC = RTC_PSC_RESET; /* only when RTC_CTL_WTEN=0 and RTC_STAT_WTWF=1 can write RTC_CTL[2£º0] */ /* wait until the WTWF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_WTWF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET == flag_status){ error_status = ERROR; }else{ RTC_CTL &= RTC_REGISTER_RESET; RTC_WUT = RTC_WUT_RESET; RTC_COSC = RTC_REGISTER_RESET; /* to write RTC_ALRMxSS register, ALRMxEN bit in RTC_CTL register should be reset as the condition */ RTC_ALRM0TD = RTC_REGISTER_RESET; RTC_ALRM1TD = RTC_REGISTER_RESET; RTC_ALRM0SS = RTC_REGISTER_RESET; RTC_ALRM1SS = RTC_REGISTER_RESET; /* reset RTC_STAT register, also exit init mode. at the same time, RTC_STAT_SOPF bit is reset, as the condition to reset RTC_SHIFTCTL register later */ RTC_STAT = RTC_STAT_RESET; /* reset RTC_SHIFTCTL and RTC_HRFC register, this can be done without the init mode */ RTC_SHIFTCTL = RTC_REGISTER_RESET; RTC_HRFC = RTC_REGISTER_RESET; error_status = rtc_register_sync_wait(); } } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief initialize RTC registers \param[in] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains parameters for initialization of the rtc peripheral members of the structure and the member values are shown as below: year: 0x0 - 0x99(BCD format) month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN, RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC date: 0x1 - 0x31(BCD format) day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose minute: 0x0 - 0x59(BCD format) second: 0x0 - 0x59(BCD format) factor_asyn: 0x0 - 0x7F factor_syn: 0x0 - 0x7FFF am_pm: RTC_AM, RTC_PM display_format: RTC_24HOUR, RTC_12HOUR \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_init(rtc_parameter_struct* rtc_initpara_struct) { ErrStatus error_status = ERROR; uint32_t reg_time = 0U, reg_date = 0U; reg_date = (DATE_YR(rtc_initpara_struct->year) | \ DATE_DOW(rtc_initpara_struct->day_of_week) | \ DATE_MON(rtc_initpara_struct->month) | \ DATE_DAY(rtc_initpara_struct->date)); reg_time = (rtc_initpara_struct->am_pm| \ TIME_HR(rtc_initpara_struct->hour) | \ TIME_MN(rtc_initpara_struct->minute) | \ TIME_SC(rtc_initpara_struct->second)); /* 1st: disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* 2nd: enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ RTC_PSC = (uint32_t)(PSC_FACTOR_A(rtc_initpara_struct->factor_asyn)| \ PSC_FACTOR_S(rtc_initpara_struct->factor_syn)); RTC_TIME = (uint32_t)reg_time; RTC_DATE = (uint32_t)reg_date; RTC_CTL &= (uint32_t)(~RTC_CTL_CS); RTC_CTL |= rtc_initpara_struct->display_format; /* 3rd: exit init mode */ rtc_init_mode_exit(); /* 4th: wait the RSYNF flag to set */ error_status = rtc_register_sync_wait(); } /* 5th: enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief enter RTC init mode \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_init_mode_enter(void) { volatile uint32_t time_index = RTC_INITM_TIMEOUT; uint32_t flag_status = RESET; ErrStatus error_status = ERROR; /* check whether it has been in init mode */ if ((uint32_t)RESET == (RTC_STAT & RTC_STAT_INITF)){ RTC_STAT |= RTC_STAT_INITM; /* wait until the INITF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_INITF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET != flag_status){ error_status = SUCCESS; } }else{ error_status = SUCCESS; } return error_status; } /*! \brief exit RTC init mode \param[in] none \param[out] none \retval none */ void rtc_init_mode_exit(void) { RTC_STAT &= (uint32_t)(~RTC_STAT_INITM); } /*! \brief wait until RTC_TIME and RTC_DATE registers are synchronized with APB clock, and the shadow registers are updated \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_register_sync_wait(void) { volatile uint32_t time_index = RTC_RSYNF_TIMEOUT; uint32_t flag_status = RESET; ErrStatus error_status = ERROR; if ((uint32_t)RESET == (RTC_CTL & RTC_CTL_BPSHAD)){ /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* firstly clear RSYNF flag */ RTC_STAT &= (uint32_t)(~RTC_STAT_RSYNF); /* wait until RSYNF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_RSYNF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET != flag_status){ error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; }else{ error_status = SUCCESS; } return error_status; } /*! \brief get current time and date \param[in] none \param[out] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains parameters for initialization of the rtc peripheral members of the structure and the member values are shown as below: year: 0x0 - 0x99(BCD format) month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN, RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC date: 0x1 - 0x31(BCD format) day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose minute: 0x0 - 0x59(BCD format) second: 0x0 - 0x59(BCD format) factor_asyn: 0x0 - 0x7F factor_syn: 0x0 - 0x7FFF am_pm: RTC_AM, RTC_PM display_format: RTC_24HOUR, RTC_12HOUR \retval none */ void rtc_current_time_get(rtc_parameter_struct* rtc_initpara_struct) { uint32_t temp_tr = 0U, temp_dr = 0U, temp_pscr = 0U, temp_ctlr = 0U; temp_tr = (uint32_t)RTC_TIME; temp_dr = (uint32_t)RTC_DATE; temp_pscr = (uint32_t)RTC_PSC; temp_ctlr = (uint32_t)RTC_CTL; /* get current time and construct rtc_parameter_struct structure */ rtc_initpara_struct->year = (uint8_t)GET_DATE_YR(temp_dr); rtc_initpara_struct->month = (uint8_t)GET_DATE_MON(temp_dr); rtc_initpara_struct->date = (uint8_t)GET_DATE_DAY(temp_dr); rtc_initpara_struct->day_of_week = (uint8_t)GET_DATE_DOW(temp_dr); rtc_initpara_struct->hour = (uint8_t)GET_TIME_HR(temp_tr); rtc_initpara_struct->minute = (uint8_t)GET_TIME_MN(temp_tr); rtc_initpara_struct->second = (uint8_t)GET_TIME_SC(temp_tr); rtc_initpara_struct->factor_asyn = (uint16_t)GET_PSC_FACTOR_A(temp_pscr); rtc_initpara_struct->factor_syn = (uint16_t)GET_PSC_FACTOR_S(temp_pscr); rtc_initpara_struct->am_pm = (uint32_t)(temp_pscr & RTC_TIME_PM); rtc_initpara_struct->display_format = (uint32_t)(temp_ctlr & RTC_CTL_CS); } /*! \brief get current subsecond value \param[in] none \param[out] none \retval current subsecond value */ uint32_t rtc_subsecond_get(void) { uint32_t reg = 0U; /* if BPSHAD bit is reset, reading RTC_SS will lock RTC_TIME and RTC_DATE automatically */ reg = (uint32_t)RTC_SS; /* read RTC_DATE to unlock the 3 shadow registers */ (void) (RTC_DATE); return reg; } /*! \brief configure RTC alarm \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[in] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains parameters for RTC alarm configuration members of the structure and the member values are shown as below: alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set 2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format alarm_minute: 0x0 - 0x59(BCD format) alarm_second: 0x0 - 0x59(BCD format) am_pm: RTC_AM, RTC_PM \param[out] none \retval none */ void rtc_alarm_config(uint8_t rtc_alarm, rtc_alarm_struct* rtc_alarm_time) { uint32_t reg_alrmtd = 0U; reg_alrmtd =(rtc_alarm_time->alarm_mask | \ rtc_alarm_time->weekday_or_date | \ rtc_alarm_time->am_pm | \ ALRMTD_DAY(rtc_alarm_time->alarm_day) | \ ALRMTD_HR(rtc_alarm_time->alarm_hour) | \ ALRMTD_MN(rtc_alarm_time->alarm_minute) | \ ALRMTD_SC(rtc_alarm_time->alarm_second)); /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; if(RTC_ALARM0 == rtc_alarm){ RTC_ALRM0TD = (uint32_t)reg_alrmtd; }else{ RTC_ALRM1TD = (uint32_t)reg_alrmtd; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief configure subsecond of RTC alarm \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[in] mask_subsecond: alarm subsecond mask \arg RTC_MASKSSC_0_14: mask alarm subsecond configuration \arg RTC_MASKSSC_1_14: mask RTC_ALRMXSS_SSC[14:1], and RTC_ALRMXSS_SSC[0] is to be compared \arg RTC_MASKSSC_2_14: mask RTC_ALRMXSS_SSC[14:2], and RTC_ALRMXSS_SSC[1:0] is to be compared \arg RTC_MASKSSC_3_14: mask RTC_ALRMXSS_SSC[14:3], and RTC_ALRMXSS_SSC[2:0] is to be compared \arg RTC_MASKSSC_4_14: mask RTC_ALRMXSS_SSC[14:4]], and RTC_ALRMXSS_SSC[3:0] is to be compared \arg RTC_MASKSSC_5_14: mask RTC_ALRMXSS_SSC[14:5], and RTC_ALRMXSS_SSC[4:0] is to be compared \arg RTC_MASKSSC_6_14: mask RTC_ALRMXSS_SSC[14:6], and RTC_ALRMXSS_SSC[5:0] is to be compared \arg RTC_MASKSSC_7_14: mask RTC_ALRMXSS_SSC[14:7], and RTC_ALRMXSS_SSC[6:0] is to be compared \arg RTC_MASKSSC_8_14: mask RTC_ALRMXSS_SSC[14:8], and RTC_ALRMXSS_SSC[7:0] is to be compared \arg RTC_MASKSSC_9_14: mask RTC_ALRMXSS_SSC[14:9], and RTC_ALRMXSS_SSC[8:0] is to be compared \arg RTC_MASKSSC_10_14: mask RTC_ALRMXSS_SSC[14:10], and RTC_ALRMXSS_SSC[9:0] is to be compared \arg RTC_MASKSSC_11_14: mask RTC_ALRMXSS_SSC[14:11], and RTC_ALRMXSS_SSC[10:0] is to be compared \arg RTC_MASKSSC_12_14: mask RTC_ALRMXSS_SSC[14:12], and RTC_ALRMXSS_SSC[11:0] is to be compared \arg RTC_MASKSSC_13_14: mask RTC_ALRMXSS_SSC[14:13], and RTC_ALRMXSS_SSC[12:0] is to be compared \arg RTC_MASKSSC_14: mask RTC_ALRMXSS_SSC[14], and RTC_ALRMXSS_SSC[13:0] is to be compared \arg RTC_MASKSSC_NONE: mask none, and RTC_ALRMXSS_SSC[14:0] is to be compared \param[in] subsecond: alarm subsecond value(0x000 - 0x7FFF) \param[out] none \retval none */ void rtc_alarm_subsecond_config(uint8_t rtc_alarm, uint32_t mask_subsecond, uint32_t subsecond) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; if(RTC_ALARM0 == rtc_alarm){ RTC_ALRM0SS = mask_subsecond | subsecond; }else{ RTC_ALRM1SS = mask_subsecond | subsecond; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief get RTC alarm \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[out] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains parameters for RTC alarm configuration members of the structure and the member values are shown as below: alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set 2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format alarm_minute: 0x0 - 0x59(BCD format) alarm_second: 0x0 - 0x59(BCD format) am_pm: RTC_AM, RTC_PM \retval none */ void rtc_alarm_get(uint8_t rtc_alarm, rtc_alarm_struct* rtc_alarm_time) { uint32_t reg_alrmtd = 0U; /* get the value of RTC_ALRM0TD register */ if(RTC_ALARM0 == rtc_alarm){ reg_alrmtd = RTC_ALRM0TD; }else{ reg_alrmtd = RTC_ALRM1TD; } /* get alarm parameters and construct the rtc_alarm_struct structure */ rtc_alarm_time->alarm_mask = reg_alrmtd & RTC_ALARM_ALL_MASK; rtc_alarm_time->am_pm = (uint32_t)(reg_alrmtd & RTC_ALRMXTD_PM); rtc_alarm_time->weekday_or_date = (uint32_t)(reg_alrmtd & RTC_ALRMXTD_DOWS); rtc_alarm_time->alarm_day = (uint8_t)GET_ALRMTD_DAY(reg_alrmtd); rtc_alarm_time->alarm_hour = (uint8_t)GET_ALRMTD_HR(reg_alrmtd); rtc_alarm_time->alarm_minute = (uint8_t)GET_ALRMTD_MN(reg_alrmtd); rtc_alarm_time->alarm_second = (uint8_t)GET_ALRMTD_SC(reg_alrmtd); } /*! \brief get RTC alarm subsecond \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[out] none \retval RTC alarm subsecond value */ uint32_t rtc_alarm_subsecond_get(uint8_t rtc_alarm) { if(RTC_ALARM0 == rtc_alarm){ return ((uint32_t)(RTC_ALRM0SS & RTC_ALRM0SS_SSC)); }else{ return ((uint32_t)(RTC_ALRM1SS & RTC_ALRM1SS_SSC)); } } /*! \brief enable RTC alarm \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[out] none \retval none */ void rtc_alarm_enable(uint8_t rtc_alarm) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; if(RTC_ALARM0 == rtc_alarm){ RTC_CTL |= RTC_CTL_ALRM0EN; }else{ RTC_CTL |= RTC_CTL_ALRM1EN; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief disable RTC alarm \param[in] rtc_alarm: RTC_ALARM0 or RTC_ALARM1 \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_alarm_disable(uint8_t rtc_alarm) { volatile uint32_t time_index = RTC_ALRMXWF_TIMEOUT; ErrStatus error_status = ERROR; uint32_t flag_status = RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* clear the state of alarm */ if(RTC_ALARM0 == rtc_alarm){ RTC_CTL &= (uint32_t)(~RTC_CTL_ALRM0EN); /* wait until ALRM0WF flag to be set after the alarm is disabled */ do{ flag_status = RTC_STAT & RTC_STAT_ALRM0WF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); }else{ RTC_CTL &= (uint32_t)(~RTC_CTL_ALRM1EN); /* wait until ALRM1WF flag to be set after the alarm is disabled */ do{ flag_status = RTC_STAT & RTC_STAT_ALRM1WF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); } if ((uint32_t)RESET != flag_status){ error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief enable RTC time-stamp \param[in] edge: specify which edge to detect of time-stamp \arg RTC_TIMESTAMP_RISING_EDGE: rising edge is valid event edge for timestamp event \arg RTC_TIMESTAMP_FALLING_EDGE: falling edge is valid event edge for timestamp event \param[out] none \retval none */ void rtc_timestamp_enable(uint32_t edge) { uint32_t reg_ctl = 0U; /* clear the bits to be configured in RTC_CTL */ reg_ctl = (uint32_t)(RTC_CTL & (uint32_t)(~(RTC_CTL_TSEG | RTC_CTL_TSEN))); /* new configuration */ reg_ctl |= (uint32_t)(edge | RTC_CTL_TSEN); /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL = (uint32_t)reg_ctl; /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief disable RTC time-stamp \param[in] none \param[out] none \retval none */ void rtc_timestamp_disable(void) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* clear the TSEN bit */ RTC_CTL &= (uint32_t)(~ RTC_CTL_TSEN); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief get RTC timestamp time and date \param[in] none \param[out] rtc_timestamp: pointer to a rtc_timestamp_struct structure which contains parameters for RTC time-stamp configuration members of the structure and the member values are shown as below: timestamp_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN, RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC timestamp_date: 0x1 - 0x31(BCD format) timestamp_day: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set timestamp_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format timestamp_minute: 0x0 - 0x59(BCD format) timestamp_second: 0x0 - 0x59(BCD format) am_pm: RTC_AM, RTC_PM \retval none */ void rtc_timestamp_get(rtc_timestamp_struct* rtc_timestamp) { uint32_t temp_tts = 0U, temp_dts = 0U; /* get the value of time_stamp registers */ temp_tts = (uint32_t)RTC_TTS; temp_dts = (uint32_t)RTC_DTS; /* get timestamp time and construct the rtc_timestamp_struct structure */ rtc_timestamp->am_pm = (uint32_t)(temp_tts & RTC_TTS_PM); rtc_timestamp->timestamp_month = (uint8_t)GET_DTS_MON(temp_dts); rtc_timestamp->timestamp_date = (uint8_t)GET_DTS_DAY(temp_dts); rtc_timestamp->timestamp_day = (uint8_t)GET_DTS_DOW(temp_dts); rtc_timestamp->timestamp_hour = (uint8_t)GET_TTS_HR(temp_tts); rtc_timestamp->timestamp_minute = (uint8_t)GET_TTS_MN(temp_tts); rtc_timestamp->timestamp_second = (uint8_t)GET_TTS_SC(temp_tts); } /*! \brief get RTC time-stamp subsecond \param[in] none \param[out] none \retval RTC time-stamp subsecond value */ uint32_t rtc_timestamp_subsecond_get(void) { return ((uint32_t)RTC_SSTS); } /*! \brief RTC time-stamp mapping \param[in] rtc_af: \arg RTC_AF0_TIMESTAMP: RTC_AF0 use for timestamp \arg RTC_AF1_TIMESTAMP: RTC_AF1 use for timestamp \param[out] none \retval none */ void rtc_timestamp_pin_map(uint32_t rtc_af) { RTC_TAMP &= ~RTC_TAMP_TSSEL; RTC_TAMP |= rtc_af; } /*! \brief enable RTC tamper \param[in] rtc_tamper: pointer to a rtc_tamper_struct structure which contains parameters for RTC tamper configuration members of the structure and the member values are shown as below: tamper_source: RTC_TAMPER0, RTC_TAMPER1 tamper_trigger: RTC_TAMPER_TRIGGER_EDGE_RISING, RTC_TAMPER_TRIGGER_EDGE_FALLING RTC_TAMPER_TRIGGER_LEVEL_LOW, RTC_TAMPER_TRIGGER_LEVEL_HIGH tamper_filter: RTC_FLT_EDGE, RTC_FLT_2S, RTC_FLT_4S, RTC_FLT_8S tamper_sample_frequency: RTC_FREQ_DIV32768, RTC_FREQ_DIV16384, RTC_FREQ_DIV8192, RTC_FREQ_DIV4096, RTC_FREQ_DIV2048, RTC_FREQ_DIV1024, RTC_FREQ_DIV512, RTC_FREQ_DIV256 tamper_precharge_enable: DISABLE, ENABLE tamper_precharge_time: RTC_PRCH_1C, RTC_PRCH_2C, RTC_PRCH_4C, RTC_PRCH_8C tamper_with_timestamp: DISABLE, ENABLE \param[out] none \retval none */ void rtc_tamper_enable(rtc_tamper_struct* rtc_tamper) { /* disable tamper */ RTC_TAMP &= (uint32_t)~(rtc_tamper->tamper_source); /* tamper filter must be used when the tamper source is voltage level detection */ RTC_TAMP &= (uint32_t)~RTC_TAMP_FLT; /* the tamper source is voltage level detection */ if((uint32_t)(rtc_tamper->tamper_filter) != RTC_FLT_EDGE ){ RTC_TAMP &= (uint32_t)~(RTC_TAMP_DISPU | RTC_TAMP_PRCH | RTC_TAMP_FREQ | RTC_TAMP_FLT); /* check if the tamper pin need precharge, if need, then configure the precharge time */ if(DISABLE == rtc_tamper->tamper_precharge_enable){ RTC_TAMP |= (uint32_t)RTC_TAMP_DISPU; }else{ RTC_TAMP |= (uint32_t)(rtc_tamper->tamper_precharge_time); } RTC_TAMP |= (uint32_t)(rtc_tamper->tamper_sample_frequency); RTC_TAMP |= (uint32_t)(rtc_tamper->tamper_filter); } RTC_TAMP &= (uint32_t)~RTC_TAMP_TPTS; if(DISABLE != rtc_tamper->tamper_with_timestamp){ /* the tamper event also cause a time-stamp event */ RTC_TAMP |= (uint32_t)RTC_TAMP_TPTS; } /* configure the tamper trigger */ RTC_TAMP &= ((uint32_t)~((rtc_tamper->tamper_source) << RTC_TAMPER_TRIGGER_POS)); if(RTC_TAMPER_TRIGGER_EDGE_RISING != rtc_tamper->tamper_trigger){ RTC_TAMP |= (uint32_t)((rtc_tamper->tamper_source)<< RTC_TAMPER_TRIGGER_POS); } /* enable tamper */ RTC_TAMP |= (uint32_t)(rtc_tamper->tamper_source); } /*! \brief disable RTC tamper \param[in] source: specify which tamper source to be disabled \arg RTC_TAMPER0 \arg RTC_TAMPER1 \param[out] none \retval none */ void rtc_tamper_disable(uint32_t source) { /* disable tamper */ RTC_TAMP &= (uint32_t)~source; } /*! \brief RTC tamper0 mapping \param[in] rtc_af: \arg RTC_AF0_TAMPER0: RTC_AF0 use for tamper0 \arg RTC_AF1_TAMPER0: RTC_AF1 use for tamper0 \param[out] none \retval none */ void rtc_tamper0_pin_map(uint32_t rtc_af) { RTC_TAMP &= ~(RTC_TAMP_TP0EN | RTC_TAMP_TP0SEL); RTC_TAMP |= rtc_af; } /*! \brief enable specified RTC interrupt \param[in] interrupt: specify which interrupt source to be enabled \arg RTC_INT_TIMESTAMP: timestamp interrupt \arg RTC_INT_ALARM0: alarm0 interrupt \arg RTC_INT_ALARM1: alarm1 interrupt \arg RTC_INT_TAMP: tamp interrupt \arg RTC_INT_WAKEUP: wakeup timer interrupt \param[out] none \retval none */ void rtc_interrupt_enable(uint32_t interrupt) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enable the interrupts in RTC_CTL register */ RTC_CTL |= (uint32_t)(interrupt & (uint32_t)~RTC_TAMP_TPIE); /* enable the interrupts in RTC_TAMP register */ RTC_TAMP |= (uint32_t)(interrupt & RTC_TAMP_TPIE); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief disble specified RTC interrupt \param[in] interrupt: specify which interrupt source to be disabled \arg RTC_INT_TIMESTAMP: timestamp interrupt \arg RTC_INT_ALARM0: alarm interrupt \arg RTC_INT_ALARM1: alarm interrupt \arg RTC_INT_TAMP: tamp interrupt \arg RTC_INT_WAKEUP: wakeup timer interrupt \param[out] none \retval none */ void rtc_interrupt_disable(uint32_t interrupt) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* disable the interrupts in RTC_CTL register */ RTC_CTL &= (uint32_t)~(interrupt & (uint32_t)~RTC_TAMP_TPIE); /* disable the interrupts in RTC_TAMP register */ RTC_TAMP &= (uint32_t)~(interrupt & RTC_TAMP_TPIE); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief check specified flag \param[in] flag: specify which flag to check \arg RTC_STAT_RECPF: recalibration pending flag \arg RTC_STAT_TP1F: tamper 1 event flag \arg RTC_STAT_TP0F: tamper 0 event flag \arg RTC_STAT_TSOVRF: time-stamp overflow event flag \arg RTC_STAT_TSF: time-stamp event flag \arg RTC_STAT_ALRM0F: alarm0 event flag \arg RTC_STAT_ALRM1F: alarm1 event flag \arg RTC_STAT_WTF: wakeup timer event flag \arg RTC_STAT_INITF: init mode event flag \arg RTC_STAT_RSYNF: time and date registers synchronized event flag \arg RTC_STAT_YCM: year parameter configured event flag \arg RTC_STAT_SOPF: shift operation pending flag \arg RTC_STAT_ALRM0WF: alarm0 writen available flag \arg RTC_STAT_ALRM1WF: alarm1 writen available flag \arg RTC_STAT_WTWF: wakeup timer writen available flag \param[out] none \retval FlagStatus: SET or RESET */ FlagStatus rtc_flag_get(uint32_t flag) { FlagStatus flag_state = RESET; if ((uint32_t)RESET != (RTC_STAT & flag)){ flag_state = SET; } return flag_state; } /*! \brief clear specified flag \param[in] flag: specify which flag to clear \arg RTC_STAT_TP1F: tamper 1 event flag \arg RTC_STAT_TP0F: tamper 0 event flag \arg RTC_STAT_TSOVRF: time-stamp overflow event flag \arg RTC_STAT_TSF: time-stamp event flag \arg RTC_STAT_WTF: time-stamp event flag \arg RTC_STAT_ALRM0F: alarm0 event flag \arg RTC_STAT_ALRM1F: alarm1 event flag \arg RTC_STAT_RSYNF: time and date registers synchronized event flag \param[out] none \retval none */ void rtc_flag_clear(uint32_t flag) { RTC_STAT &= (uint32_t)(~flag); } /*! \brief configure rtc alarm output source \param[in] source: specify signal to output \arg RTC_ALARM0_HIGH: when the alarm0 flag is set, the output pin is high \arg RTC_ALARM0_LOW: when the alarm0 flag is set, the output pin is low \arg RTC_ALARM1_HIGH: when the alarm1 flag is set, the output pin is high \arg RTC_ALARM1_LOW: when the alarm1 flag is set, the output pin is low \arg RTC_WAKEUP_HIGH: when the wakeup flag is set, the output pin is high \arg RTC_WAKEUP_LOW: when the wakeup flag is set, the output pin is low \param[in] mode: specify the output pin mode when output alarm signal \arg RTC_ALARM_OUTPUT_OD: open drain mode \arg RTC_ALARM_OUTPUT_PP: push pull mode \param[out] none \retval none */ void rtc_alarm_output_config(uint32_t source, uint32_t mode) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL &= ~(RTC_CTL_OS | RTC_CTL_OPOL); RTC_TAMP &= ~RTC_TAMP_AOT; RTC_CTL |= (uint32_t)(source); /* alarm output */ RTC_TAMP |= (uint32_t)(mode); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief configure rtc calibration output source \param[in] source: specify signal to output \arg RTC_CALIBRATION_512HZ: when the LSE freqency is 32768Hz and the RTC_PSC is the default value, output 512Hz signal \arg RTC_CALIBRATION_1HZ: when the LSE freqency is 32768Hz and the RTC_PSC is the default value, output 512Hz signal \param[out] none \retval none */ void rtc_calibration_output_config(uint32_t source) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL &= (uint32_t)~(RTC_CTL_COEN | RTC_CTL_COS); RTC_CTL |= (uint32_t)(source); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief adjust the daylight saving time by adding or substracting one hour from the current time \param[in] operation: hour adjustment operation \arg RTC_CTL_A1H: add one hour \arg RTC_CTL_S1H: substract one hour \param[out] none \retval none */ void rtc_hour_adjust(uint32_t operation) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL |= (uint32_t)(operation); /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief adjust RTC second or subsecond value of current time \param[in] add: add 1s to current time or not \arg RTC_SHIFT_ADD1S_RESET: no effect \arg RTC_SHIFT_ADD1S_SET: add 1s to current time \param[in] minus: number of subsecond to minus from current time(0x0 - 0x7FFF) \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_second_adjust(uint32_t add, uint32_t minus) { volatile uint32_t time_index = RTC_SHIFTCTL_TIMEOUT; ErrStatus error_status = ERROR; uint32_t flag_status = RESET; uint32_t temp=0U; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* check if a shift operation is ongoing */ do{ flag_status = RTC_STAT & RTC_STAT_SOPF; }while((--time_index > 0U) && ((uint32_t)RESET != flag_status)); /* check if the function of reference clock detection is disabled */ temp = RTC_CTL & RTC_CTL_REFEN; if((RESET == flag_status) && (RESET == temp)){ RTC_SHIFTCTL = (uint32_t)(add | SHIFTCTL_SFS(minus)); error_status = rtc_register_sync_wait(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief enable RTC bypass shadow registers function \param[in] none \param[out] none \retval none */ void rtc_bypass_shadow_enable(void) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL |= RTC_CTL_BPSHAD; /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief disable RTC bypass shadow registers function \param[in] none \param[out] none \retval none */ void rtc_bypass_shadow_disable(void) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL &= ~RTC_CTL_BPSHAD; /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief enable RTC reference clock detection function \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_refclock_detection_enable(void) { ErrStatus error_status = ERROR; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ RTC_CTL |= (uint32_t)RTC_CTL_REFEN; /* exit init mode */ rtc_init_mode_exit(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief disable RTC reference clock detection function \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_refclock_detection_disable(void) { ErrStatus error_status = ERROR; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ RTC_CTL &= (uint32_t)~RTC_CTL_REFEN; /* exit init mode */ rtc_init_mode_exit(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief enable RTC auto wakeup function \param[in] none \param[out] none \retval none */ void rtc_wakeup_enable(void) { /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL |= RTC_CTL_WTEN; /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; } /*! \brief disable RTC auto wakeup function \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_wakeup_disable(void) { ErrStatus error_status = ERROR; volatile uint32_t time_index = RTC_WTWF_TIMEOUT; uint32_t flag_status = RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; RTC_CTL &= ~RTC_CTL_WTEN; /* wait until the WTWF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_WTWF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET == flag_status){ error_status = ERROR; }else{ error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief set RTC auto wakeup timer clock \param[in] wakeup_clock: \arg WAKEUP_RTCCK_DIV16: RTC auto wakeup timer clock is RTC clock divided by 16 \arg WAKEUP_RTCCK_DIV8: RTC auto wakeup timer clock is RTC clock divided by 8 \arg WAKEUP_RTCCK_DIV4: RTC auto wakeup timer clock is RTC clock divided by 4 \arg WAKEUP_RTCCK_DIV2: RTC auto wakeup timer clock is RTC clock divided by 2 \arg WAKEUP_CKSPRE: RTC auto wakeup timer clock is ckspre \arg WAKEUP_CKSPRE_2EXP16: RTC auto wakeup timer clock is ckspre and wakeup timer add 2exp16 \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_wakeup_clock_set(uint8_t wakeup_clock) { ErrStatus error_status = ERROR; volatile uint32_t time_index = RTC_WTWF_TIMEOUT; uint32_t flag_status = RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* only when RTC_CTL_WTEN=0 and RTC_STAT_WTWF=1 can write RTC_CTL[2£º0] */ /* wait until the WTWF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_WTWF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET == flag_status){ error_status = ERROR; }else{ RTC_CTL &= (uint32_t)~ RTC_CTL_WTCS; RTC_CTL |= (uint32_t)wakeup_clock; error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief set wakeup timer value \param[in] wakeup_timer: 0x0000-0xffff \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_wakeup_timer_set(uint16_t wakeup_timer) { ErrStatus error_status = ERROR; volatile uint32_t time_index = RTC_WTWF_TIMEOUT; uint32_t flag_status = RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* wait until the WTWF flag to be set */ do{ flag_status = RTC_STAT & RTC_STAT_WTWF; }while((--time_index > 0U) && ((uint32_t)RESET == flag_status)); if ((uint32_t)RESET == flag_status){ error_status = ERROR; }else{ RTC_WUT = (uint32_t)wakeup_timer; error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief get wakeup timer value \param[in] none \param[out] none \retval wakeup timer value */ uint16_t rtc_wakeup_timer_get(void) { return (uint16_t)RTC_WUT; } /*! \brief configure RTC smooth calibration \param[in] window: select calibration window \arg RTC_CALIBRATION_WINDOW_32S: 2exp20 RTCCLK cycles, 32s if RTCCLK = 32768 Hz \arg RTC_CALIBRATION_WINDOW_16S: 2exp19 RTCCLK cycles, 16s if RTCCLK = 32768 Hz \arg RTC_CALIBRATION_WINDOW_8S: 2exp18 RTCCLK cycles, 8s if RTCCLK = 32768 Hz \param[in] plus: add RTC clock or not \arg RTC_CALIBRATION_PLUS_SET: add one RTC clock every 2048 rtc clock \arg RTC_CALIBRATION_PLUS_RESET: no effect \param[in] minus: the RTC clock to minus during the calibration window(0x0 - 0x1FF) \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_smooth_calibration_config(uint32_t window, uint32_t plus, uint32_t minus) { volatile uint32_t time_index = RTC_HRFC_TIMEOUT; ErrStatus error_status = ERROR; uint32_t flag_status = RESET; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* check if a smooth calibration operation is ongoing */ do{ flag_status = RTC_STAT & RTC_STAT_SCPF; }while((--time_index > 0U) && ((uint32_t)RESET != flag_status)); if((uint32_t)RESET == flag_status){ RTC_HRFC = (uint32_t)(window | plus | HRFC_CMSK(minus)); error_status = SUCCESS; } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief enable RTC coarse calibration \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_coarse_calibration_enable(void) { ErrStatus error_status = ERROR; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ RTC_CTL |= (uint32_t)RTC_CTL_CCEN; /* exit init mode */ rtc_init_mode_exit(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief disable RTC coarse calibration \param[in] none \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_coarse_calibration_disable(void) { ErrStatus error_status = ERROR; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ RTC_CTL &= (uint32_t)~RTC_CTL_CCEN; /* exit init mode */ rtc_init_mode_exit(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; } /*! \brief config coarse calibration direction and step \param[in] direction: CALIB_INCREASE or CALIB_DECREASE \param[in] step: 0x00-0x1F COSD=0: 0x00:+0 PPM 0x01:+4 PPM 0x02:+8 PPM .... 0x1F:+126 PPM COSD=1: 0x00:-0 PPM 0x01:-2 PPM 0x02:-4 PPM .... 0x1F:-63 PPM \param[out] none \retval ErrStatus: ERROR or SUCCESS */ ErrStatus rtc_coarse_calibration_config(uint8_t direction, uint8_t step) { ErrStatus error_status = ERROR; /* disable the write protection */ RTC_WPK = RTC_UNLOCK_KEY1; RTC_WPK = RTC_UNLOCK_KEY2; /* enter init mode */ error_status = rtc_init_mode_enter(); if(ERROR != error_status){ if(CALIB_DECREASE == direction){ RTC_COSC |= (uint32_t)RTC_COSC_COSD; }else{ RTC_COSC &= (uint32_t)~RTC_COSC_COSD; } RTC_COSC &= ~RTC_COSC_COSS; RTC_COSC |= (uint32_t)((uint32_t)step & 0x1FU); /* exit init mode */ rtc_init_mode_exit(); } /* enable the write protection */ RTC_WPK = RTC_LOCK_KEY; return error_status; }