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:
2019-04-17 21:51:35 -07:00
parent 6747d6c831
commit a7f1ffc1b5
22 changed files with 1051 additions and 231 deletions

View File

@@ -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);
}
}