First try to implement deep sleep
It sleeps, but never wakes up again. Also it consumes a lot of current which suspended?!
This commit is contained in:
parent
fa71acfc8e
commit
98d0c08ec3
|
@ -313,6 +313,13 @@ void charge_control_update(uint64_t uptime_ms, struct MeasurementResult *meas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool charge_control_is_idle(void)
|
||||||
|
{
|
||||||
|
return ((charge_state == CHARGE_SLEEP)
|
||||||
|
&& (discharge_state == DISCHARGE_VOLTAGE_LOW));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool charge_control_is_charge_blocked(void)
|
bool charge_control_is_charge_blocked(void)
|
||||||
{
|
{
|
||||||
switch(charge_state) {
|
switch(charge_state) {
|
||||||
|
|
|
@ -37,4 +37,6 @@ void charge_control_update(uint64_t uptime_ms, struct MeasurementResult *meas);
|
||||||
bool charge_control_is_charge_blocked(void);
|
bool charge_control_is_charge_blocked(void);
|
||||||
bool charge_control_is_discharge_blocked(void);
|
bool charge_control_is_discharge_blocked(void);
|
||||||
|
|
||||||
|
bool charge_control_is_idle(void);
|
||||||
|
|
||||||
#endif // CHARGE_CONTROL_H
|
#endif // CHARGE_CONTROL_H
|
||||||
|
|
|
@ -52,4 +52,13 @@
|
||||||
/* The minimum time the load must be off before it can be switched on again (in ms). */
|
/* The minimum time the load must be off before it can be switched on again (in ms). */
|
||||||
#define LOAD_ON_DELAY 10000
|
#define LOAD_ON_DELAY 10000
|
||||||
|
|
||||||
|
|
||||||
|
/* Generic configuration */
|
||||||
|
|
||||||
|
/* Time (in ms) to stay active in idle state before entering deep sleep. */
|
||||||
|
#define DEEPSLEEP_DELAY 5000
|
||||||
|
|
||||||
|
/* Deep sleep duration (in seconds). */
|
||||||
|
#define DEEPSLEEP_DURATION 10
|
||||||
|
|
||||||
#endif // CONFIG_H
|
#endif // CONFIG_H
|
||||||
|
|
140
src/deepsleep.c
Normal file
140
src/deepsleep.c
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include <libopencm3/stm32/rcc.h>
|
||||||
|
#include <libopencm3/stm32/pwr.h>
|
||||||
|
#include <libopencm3/stm32/rtc.h>
|
||||||
|
#include <libopencmsis/core_cm3.h>
|
||||||
|
#include <libopencm3/stm32/exti.h>
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
#include "deepsleep.h"
|
||||||
|
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
rcc_periph_clock_disable(RCC_PWR); // no longer needed
|
||||||
|
rcc_osc_off(RCC_LSI);
|
||||||
|
init_clock(); // ensure that all clocks are running again
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_isr(void)
|
||||||
|
{
|
||||||
|
exti_reset_request(EXTI17);
|
||||||
|
}
|
||||||
|
|
9
src/deepsleep.h
Normal file
9
src/deepsleep.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef DEEPSLEEP_H
|
||||||
|
#define DEEPSLEEP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void init_rtc(void);
|
||||||
|
void deepsleep(uint32_t duration_secs);
|
||||||
|
|
||||||
|
#endif // DEEPSLEEP_H
|
23
src/main.c
23
src/main.c
|
@ -13,7 +13,9 @@
|
||||||
#include "charge_control.h"
|
#include "charge_control.h"
|
||||||
#include "power_switch.h"
|
#include "power_switch.h"
|
||||||
#include "measurement.h"
|
#include "measurement.h"
|
||||||
|
#include "deepsleep.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
volatile int wait_frame = 1;
|
volatile int wait_frame = 1;
|
||||||
|
|
||||||
|
@ -160,9 +162,13 @@ int main(void)
|
||||||
bool ledtest_done = false;
|
bool ledtest_done = false;
|
||||||
bool startup_done = false;
|
bool startup_done = false;
|
||||||
|
|
||||||
|
bool charge_control_was_idle = false;
|
||||||
|
uint64_t charge_control_idle_since = 0;
|
||||||
|
|
||||||
struct MeasurementResult meas_data;
|
struct MeasurementResult meas_data;
|
||||||
|
|
||||||
init_clock();
|
init_clock();
|
||||||
|
init_rtc();
|
||||||
|
|
||||||
rs485_init();
|
rs485_init();
|
||||||
charge_pump_init();
|
charge_pump_init();
|
||||||
|
@ -208,6 +214,23 @@ int main(void)
|
||||||
// Update the charge controller immediately after the measurement.
|
// Update the charge controller immediately after the measurement.
|
||||||
// This ensures fast reaction time to overcurrent/overvoltage.
|
// This ensures fast reaction time to overcurrent/overvoltage.
|
||||||
charge_control_update(timebase_ms, &meas_data);
|
charge_control_update(timebase_ms, &meas_data);
|
||||||
|
|
||||||
|
// deep sleep control
|
||||||
|
if(charge_control_is_idle()) {
|
||||||
|
if(!charge_control_was_idle) {
|
||||||
|
charge_control_was_idle = true;
|
||||||
|
charge_control_idle_since = timebase_ms;
|
||||||
|
} else {
|
||||||
|
// charge control already idle
|
||||||
|
if((timebase_ms - charge_control_idle_since) > DEEPSLEEP_DELAY) {
|
||||||
|
rs485_enqueue("PWR:DEEPSLEEP");
|
||||||
|
deepsleep(DEEPSLEEP_DURATION);
|
||||||
|
charge_control_was_idle = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
charge_control_was_idle = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timebase_ms++;
|
timebase_ms++;
|
||||||
|
|
Loading…
Reference in a new issue