diff --git a/src/main.c b/src/main.c index c15a0ef..eed5a6a 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include #include @@ -33,6 +36,19 @@ volatile int wait_frame = 1; #define ADC_NUM_CHANNELS 3 volatile uint16_t adc_values[ADC_NUM_CHANNELS]; +static void unlock_rtc_access(void) +{ + pwr_disable_backup_domain_write_protect(); + RTC_WPR = 0xCA; + RTC_WPR = 0x53; +} + +static void lock_rtc_access(void) +{ + RTC_WPR = 0xFF; + pwr_enable_backup_domain_write_protect(); +} + static void init_gpio(void) { // Set up UART TX on PB6 for debugging @@ -79,6 +95,39 @@ static void init_clock(void) rcc_periph_clock_enable(RCC_DMA); } +static void init_rtc(void) +{ + // RTC clock setup + // see libopencm3-examples::examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/main.c + + /* turn on power block to enable unlocking */ + rcc_periph_clock_enable(RCC_PWR); + pwr_disable_backup_domain_write_protect(); + + /* reset rtc */ + RCC_BDCR |= RCC_BDCR_BDRST; + RCC_BDCR &= ~RCC_BDCR_BDRST; + + // use LSI for RTC + rcc_osc_on(RCC_LSI); + rcc_wait_for_osc_ready(RCC_LSI); + + /* Select the LSI as rtc clock */ + RCC_BDCR |= RCC_BDCR_RTCSEL_LSI; + + /* ?! Stdperiph examples don't turn this on until _afterwards_ which + * simply doesn't work. It must be on at least to be able to + * configure it */ + RCC_BDCR |= RCC_BDCR_RTCEN; + + pwr_enable_backup_domain_write_protect(); + + nvic_enable_irq(NVIC_RTC_IRQ); + + exti_set_trigger(EXTI17, EXTI_TRIGGER_RISING); + exti_enable_request(EXTI17); +} + static void init_timer(void) { // *** TIM1 *** @@ -183,6 +232,83 @@ static void init_adc(void) } +static void deepsleep(uint32_t duration_secs) +{ + uint32_t tmp = 0; + + // unlock RTC registers + unlock_rtc_access(); + + // enter initialization mode + RTC_ISR |= RTC_ISR_INIT; + + // wait until initialization mode has been entered + while((RTC_ISR & RTC_ISR_INITF) != RTC_ISR_INITF) { + // do nothing + } + + RTC_TR = 0; // 00:00:00 + RTC_DR = // friday, 01.01.16 + (1 << RTC_DR_YT_SHIFT) | + (6 << RTC_DR_YU_SHIFT) | + (5 << RTC_DR_WDU_SHIFT) | + (0 << RTC_DR_MT_SHIFT) | + (1 << RTC_DR_MU_SHIFT) | + (0 << RTC_DR_DT_SHIFT) | + (1 << RTC_DR_DU_SHIFT); + + // disable Alarm A + RTC_CR &= ~RTC_CR_ALRAE; + + // wait until register is writeable + while((RTC_ISR & RTC_ISR_ALRAWF) != RTC_ISR_ALRAWF) { + // do nothing + } + + tmp |= (duration_secs % 10) << RTC_ALRMXR_SU_SHIFT; + duration_secs /= 10; + + tmp |= (duration_secs % 6) << RTC_ALRMXR_ST_SHIFT; + duration_secs /= 6; + + tmp |= (duration_secs % 10) << RTC_ALRMXR_MNU_SHIFT; + duration_secs /= 10; + + tmp |= (duration_secs % 6) << RTC_ALRMXR_MNT_SHIFT; + duration_secs /= 6; + + tmp |= (duration_secs % 10) << RTC_ALRMXR_HU_SHIFT; + duration_secs /= 10; + + tmp |= (duration_secs % 2) << RTC_ALRMXR_HT_SHIFT; + // FIXME: >1d is not supported + + tmp |= RTC_ALRMXR_MSK4; // ignore day/date + + // set alarm register + RTC_ALRMAR = tmp; + + // clear Alarm A flag + RTC_ISR &= ~RTC_ISR_ALRAF; + + // enable RTC alarm interrupt for wakeup + RTC_CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; + + // leave initialization mode + RTC_ISR &= ~RTC_ISR_INIT; + + // lock registers again (using invalid key) + lock_rtc_access(); + + // enter deep sleep mode + SCB_SCR |= SCB_SCR_SLEEPDEEP; + PWR_CR |= PWR_CR_LPDS; // voltage regulator low-power mode + pwr_set_stop_mode(); + __WFI(); + SCB_SCR &= ~SCB_SCR_SLEEPDEEP; // no deepsleep except in this function + init_clock(); +} + #if 0 /* Set up timer to fire freq times per second */ static void init_systick(int freq) @@ -256,6 +382,7 @@ int main(void) fxp_t CURRENT_OFFSET = fxp_from_float(0.049); init_clock(); + init_rtc(); init_gpio(); init_adc(); init_timer(); @@ -514,6 +641,14 @@ int main(void) nextState = ConvMPP; } + if(time_in_state > 10000) { + lcd_set_cursor_pos(0, 0); + lcd_send_string("Sleep mode "); + while(lcd_process() == 0); // send everything immediately + deepsleep(10); + time_in_state = 9500; // run the voltage test again + } + break; default: @@ -598,6 +733,25 @@ int main(void) sentSomething = 1; } + if((timebase_ms % 500) == 300) { + debug_send_string("RTC seconds: "); + + fxp_format_int((RTC_TR >> RTC_TR_SU_SHIFT) & RTC_TR_SU_MASK, msg); + debug_send_string(msg); + + debug_send_string(" - ALRAF: "); + + fxp_format_int(RTC_ISR & RTC_ISR_ALRAF, msg); + debug_send_string(msg); + + debug_send_string(" - EXTI17: "); + + fxp_format_int(exti_get_flag_status(EXTI17), msg); + debug_send_string(msg); + + sentSomething = 1; + } + if(sentSomething) { debug_send_string("\r\n"); sentSomething = 0; @@ -633,6 +787,11 @@ void tim3_isr(void) } } +void rtc_isr(void) +{ + exti_reset_request(EXTI17); +} + void hard_fault_handler(void) { while (1);