183 lines
6.9 KiB
C++
Executable File
183 lines
6.9 KiB
C++
Executable File
#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
|