Huge refactoring for C++ and low-power mode
The display currently shows the time, with hours and minutes, and is capable of receiving input with buttons (though does nothing). It sleeps during intervals where nothing is happening. The display task runs once per second, and RTC alarm A is used for periodic alarms to update the system time.
This commit is contained in:
134
SystemTime.cpp
134
SystemTime.cpp
@@ -27,145 +27,21 @@ namespace BSP {
|
||||
using Common::ReturnCode;
|
||||
using Common::time_t;
|
||||
|
||||
uint32_t SystemTimer::m_seconds(0);
|
||||
RTC_TypeDef *SystemTimer::m_rtc = nullptr;
|
||||
SystemTimerImpl *SystemTimer::m_impl = nullptr;
|
||||
|
||||
void SystemTimer::enable_rtc_write()
|
||||
{
|
||||
/*<! Disable write protection */
|
||||
RTC->WPR = 0xCA;
|
||||
RTC->WPR = 0x53;
|
||||
}
|
||||
|
||||
void SystemTimer::disable_rtc_write()
|
||||
{
|
||||
/*<! Disable write protection */
|
||||
RTC->WPR = 0x00;
|
||||
}
|
||||
|
||||
void SystemTimer::enable_rtc_wakeup_interrupt()
|
||||
{
|
||||
CLR(RTC->CR, RTC_CR_WUTE);
|
||||
while (!(RTC->ISR & RTC_ISR_WUTWF)) {}
|
||||
SET_TO(RTC->WUTR, RTC_WUTR_WUT, 0);
|
||||
SET_TO(RTC->CR, RTC_CR_WUCKSEL, RTC_CR_WUCKSEL_2);
|
||||
|
||||
SET(EXTI->IMR, EXTI_IMR_IM20);
|
||||
SET(EXTI->EMR, EXTI_EMR_EM20);
|
||||
SET(EXTI->RTSR, EXTI_RTSR_RT20);
|
||||
|
||||
NVIC_EnableIRQ(RTC_IRQn);
|
||||
NVIC_SetPriority(RTC_IRQn, 0);
|
||||
|
||||
SET(RTC->CR, RTC_CR_WUTE | RTC_CR_WUTIE);
|
||||
}
|
||||
|
||||
ReturnCode SystemTimer::init_hw()
|
||||
{
|
||||
uint32_t temp = RCC->CSR;
|
||||
|
||||
SET(RCC->CSR, RCC_CSR_RTCRST);
|
||||
SET(RCC->APB1ENR, RCC_APB1ENR_PWREN);
|
||||
SET(PWR->CR, PWR_CR_DBP);
|
||||
|
||||
/*<! Set RTC input clock to the LSI (low-speed internal 32.768kHz) clock */
|
||||
SET(temp, RCC_CSR_LSEON);
|
||||
SET_TO(temp, RCC_CSR_RTCSEL, RCC_CSR_RTCSEL_0);
|
||||
SET(temp, RCC_CSR_RTCEN);
|
||||
RCC->CSR = temp;
|
||||
|
||||
while (!(RCC->CSR & RCC_CSR_LSERDY)) {}
|
||||
|
||||
enable_rtc_write();
|
||||
|
||||
RTC->ISR = RTC_ISR_INIT;
|
||||
while (!(RTC->ISR & RTC_ISR_INITF)) {}
|
||||
|
||||
// FIXME: Make this use the minimum prescaler value
|
||||
/*<! Set the Clock Prescalers (32.768kHz / 128 / 256 = 1Hz */
|
||||
/*<! Set the Async prescaler to the Maximum (divide the clock by 128) */
|
||||
SET_TO(RTC->PRER, RTC_PRER_PREDIV_A, 0);
|
||||
/*<! Set the Syncronous scaler (divide the clock by 255 + 1) */
|
||||
SET_TO(RTC->PRER, RTC_PRER_PREDIV_S, (LSE_CLOCK_FREQ - 1));
|
||||
|
||||
/*<! Load initial date and time */
|
||||
// TODO
|
||||
/* uint32_t time = 0; */
|
||||
/* uint32_t date = 0; */
|
||||
/*<! Set the date and time format */
|
||||
// TODO: currently defaults to 24hr
|
||||
|
||||
// 12-Hour format
|
||||
SET(RTC->CR, RTC_CR_FMT);
|
||||
|
||||
uint32_t time = 0;
|
||||
SET(time, RTC_TR_PM);
|
||||
SET_TO(time, RTC_TR_HT, 1 << RTC_TR_HT_Pos);
|
||||
SET_TO(time, RTC_TR_HU, 2 << RTC_TR_HU_Pos);
|
||||
SET_TO(time, RTC_TR_MNT, 5 << RTC_TR_MNT_Pos);
|
||||
SET_TO(time, RTC_TR_MNU, 9 << RTC_TR_MNU_Pos);
|
||||
SET_TO(time, RTC_TR_ST, 0 << RTC_TR_ST_Pos);
|
||||
SET_TO(time, RTC_TR_SU, 0 << RTC_TR_SU_Pos);
|
||||
RTC->TR = time;
|
||||
|
||||
|
||||
CLR(RTC->ISR, RTC_ISR_INIT);
|
||||
|
||||
enable_rtc_wakeup_interrupt();
|
||||
|
||||
disable_rtc_write();
|
||||
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
ReturnCode SystemTimer::init(RTC_TypeDef *rtc)
|
||||
{
|
||||
if (rtc == nullptr) {
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
m_rtc = rtc;
|
||||
m_seconds = 0;
|
||||
|
||||
init_hw();
|
||||
|
||||
return ReturnCode::OK;
|
||||
void SystemTimer::set_timer(SystemTimerImpl &timer) {
|
||||
m_impl = &timer;
|
||||
}
|
||||
|
||||
ReturnCode SystemTimer::get_time(time_t &time)
|
||||
{
|
||||
if (m_rtc == nullptr) {
|
||||
if (m_impl == nullptr) {
|
||||
return ReturnCode::FAIL;
|
||||
}
|
||||
|
||||
uint32_t new_secs, old_secs, ssr, subsecond;
|
||||
do {
|
||||
old_secs = m_seconds;
|
||||
ssr = m_rtc->SSR & 0xFFFF;
|
||||
new_secs = m_seconds;
|
||||
} while (new_secs != old_secs);
|
||||
|
||||
new_secs = new_secs * LSE_CLOCK_FREQ;
|
||||
/** SSR is a countdown register */
|
||||
subsecond = (new_secs + LSE_CLOCK_FREQ - 1 - ssr) * Common::Time::MILLIS_PER_SEC / LSE_CLOCK_FREQ;
|
||||
time += Common::Time::millis(subsecond);
|
||||
time = m_impl->get_time();
|
||||
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
void SystemTimer::increment_seconds()
|
||||
{
|
||||
m_seconds++;
|
||||
}
|
||||
|
||||
extern "C" void RTC_IRQHandler(void);
|
||||
|
||||
void RTC_IRQHandler() {
|
||||
SystemTimer::increment_seconds();
|
||||
// Clear the interrupt in the EXTI
|
||||
SET(EXTI->PR, EXTI_PR_PIF20);
|
||||
// Clear the interrupt in the RTC
|
||||
CLR(RTC->ISR, RTC_ISR_WUTF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user