#ifndef STM32U5XX_HAL_RTC_HPP #define STM32U5XX_HAL_RTC_HPP #include "global_variable.h" #include "stdint.h" #include "stdlib.h" #include "stm32u575xx.h" #include "stm32u5xx.h" class Rtc { private: public: Rtc() = default; void setup() { RCC->AHB3ENR |= RCC_AHB3ENR_PWREN; // enable power clock RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN; // enable rtc and temp apb RCC->SRDAMR |= RCC_SRDAMR_RTCAPBAMEN; // enable rtc and temp apb RCC->APB3SMENR |= RCC_APB3SMENR_RTCAPBSMEN; // enable rtc and temp apb } void rtc_setup_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { SET_BIT(PWR->DBPR, PWR_DBPR_DBP); // enable backup domain write // enable LSE as rtc clock source RCC->BDCR |= RCC_BDCR_RTCEN; RCC->BDCR |= RCC_BDCR_LSEON; // wait for LSE to be ready while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0) {} MODIFY_REG(RCC->BDCR, RCC_BDCR_RTCSEL, 0b01 << RCC_BDCR_RTCSEL_Pos); // set rtc clock source to LSE CLEAR_BIT(RTC->ICSR, RTC_ICSR_BIN); // set to BCD mode // write protection disable RTC->WPR = 0xCA; RTC->WPR = 0x53; // enter init_old mode SET_BIT(RTC->ICSR, RTC_ICSR_INIT); while ((RTC->ICSR & RTC_ICSR_INITF) == 0) {} // set prescale to 1Hz uint32_t tmpreg = 0; tmpreg = 127 << RTC_PRER_PREDIV_A_Pos | // set async prescale to 127 255 << RTC_PRER_PREDIV_S_Pos; // sync prescale to 255 WRITE_REG(RTC->PRER, tmpreg); tmpreg = 0; tmpreg = 0b0 << RTC_TR_PM_Pos | // set to 24 hour mode (hour / 10) << RTC_TR_HT_Pos | (hour % 10) << RTC_TR_HU_Pos | // set hour (minute / 10) << RTC_TR_MNT_Pos | (minute % 10) << RTC_TR_MNU_Pos | // set minute (second / 10) << RTC_TR_ST_Pos | (second % 10) << RTC_TR_SU_Pos; // set second WRITE_REG(RTC->TR, tmpreg); tmpreg = 0; tmpreg = (year / 10) << RTC_DR_YT_Pos | (year % 10) << RTC_DR_YU_Pos | // set year (month / 10) << RTC_DR_MT_Pos | (month % 10) << RTC_DR_MU_Pos | // set month (day / 10) << RTC_DR_DT_Pos | (day % 10) << RTC_DR_DU_Pos; // set day WRITE_REG(RTC->DR, tmpreg); // TODO: test whether system reset will clear RTC registers CLEAR_BIT(RTC->CR, RTC_CR_BYPSHAD); // clear bypass shadow register. CLEAR_BIT(RTC->ICSR, RTC_ICSR_INIT); // exit init_old mode CLEAR_BIT(PWR->DBPR, PWR_DBPR_DBP); // disable backup domain write. Protect RTC registers. WRITE_REG(RTC->WPR, 0xFF); // write protection enable } /** * @brief get current year from rtc * @param year (return) current year */ void rtc_get_year(uint8_t *year) { uint32_t tmpreg = RTC->DR; *year = ((tmpreg & RTC_DR_YT) >> RTC_DR_YT_Pos) * 10 + ((tmpreg & RTC_DR_YU) >> RTC_DR_YU_Pos); } /** * @brief get current month from rtc * @param month (return) current month */ void rtc_get_month(uint8_t *month) { uint32_t tmpreg = RTC->DR; *month = ((tmpreg & RTC_DR_MT) >> RTC_DR_MT_Pos) * 10 + ((tmpreg & RTC_DR_MU) >> RTC_DR_MU_Pos); } /** * @brief get current day from rtc * @param day (return) current day */ void rtc_get_day(uint8_t *day) { uint32_t tmpreg = RTC->DR; *day = ((tmpreg & RTC_DR_DT) >> RTC_DR_DT_Pos) * 10 + ((tmpreg & RTC_DR_DU) >> RTC_DR_DU_Pos); } /** * @brief get current hour from rtc * @param hour (return) current hour */ void rtc_get_hour(uint8_t *hour) { uint32_t tmpreg = RTC->TR; *hour = ((tmpreg & RTC_TR_HT) >> RTC_TR_HT_Pos) * 10 + ((tmpreg & RTC_TR_HU) >> RTC_TR_HU_Pos); } /** * @brief get current minute from rtc * @param minute (return) current minute */ void rtc_get_minute(uint8_t *minute) { uint32_t tmpreg = RTC->TR; *minute = ((tmpreg & RTC_TR_MNT) >> RTC_TR_MNT_Pos) * 10 + ((tmpreg & RTC_TR_MNU) >> RTC_TR_MNU_Pos); } /** * @brief get current second from rtc * @param second (return) current second */ void rtc_get_second(uint8_t *second) { uint32_t tmpreg = RTC->TR; *second = ((tmpreg & RTC_TR_ST) >> RTC_TR_ST_Pos) * 10 + ((tmpreg & RTC_TR_SU) >> RTC_TR_SU_Pos); } /** * @brief get current time from rtc * @param hour (return) current hour * @param minute (return) current minute * @param second (return) current second */ void rtc_get_time(uint8_t *hour, uint8_t *minute, uint8_t *second) { uint32_t tmpreg = RTC->TR; *hour = ((tmpreg & RTC_TR_HT) >> RTC_TR_HT_Pos) * 10 + ((tmpreg & RTC_TR_HU) >> RTC_TR_HU_Pos); *minute = ((tmpreg & RTC_TR_MNT) >> RTC_TR_MNT_Pos) * 10 + ((tmpreg & RTC_TR_MNU) >> RTC_TR_MNU_Pos); *second = ((tmpreg & RTC_TR_ST) >> RTC_TR_ST_Pos) * 10 + ((tmpreg & RTC_TR_SU) >> RTC_TR_SU_Pos); } /** * @brief get current date from rtc * @param year (return) current year * @param month (return) current month * @param day (return) current day */ void rtc_get_date(uint8_t *year, uint8_t *month, uint8_t *day) { uint32_t tmpreg = RTC->DR; *year = ((tmpreg & RTC_DR_YT) >> RTC_DR_YT_Pos) * 10 + ((tmpreg & RTC_DR_YU) >> RTC_DR_YU_Pos); *month = ((tmpreg & RTC_DR_MT) >> RTC_DR_MT_Pos) * 10 + ((tmpreg & RTC_DR_MU) >> RTC_DR_MU_Pos); *day = ((tmpreg & RTC_DR_DT) >> RTC_DR_DT_Pos) * 10 + ((tmpreg & RTC_DR_DU) >> RTC_DR_DU_Pos); } /** * @brief get current time and date from rtc * @param year (return) current year * @param month (return) current month * @param day (return) current day * @param hour (return) current hour * @param minute (return) current minute * @param second (return) current second * @note this function will disable irq and RTC_CR_BYPSHAD should be cleared. * This function should read shadow registers to avoid reading inconsistent values. * @todo set timeout for while loop */ void rtc_get_datetime(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second) { if (READ_BIT(RTC->CR, RTC_CR_BYPSHAD) != 0) { return; } while (READ_BIT(RTC->ICSR, RTC_ICSR_RSF) == 0) ; // wait for sync. it will take 2 RTCCLK cycles (rtcclk is 32.768khz) __disable_irq(); rtc_get_date(year, month, day); rtc_get_time(hour, minute, second); __enable_irq(); } }; #endif // STM32U5XX_HAL_RTC_HPP