diff --git a/src/config.h b/src/config.h index bba8724..c3e341f 100644 --- a/src/config.h +++ b/src/config.h @@ -56,7 +56,7 @@ /* Generic configuration */ /* Time (in ms) to stay active in idle state before entering deep sleep. */ -#define DEEPSLEEP_DELAY 5000 +#define DEEPSLEEP_DELAY 1000 /* Deep sleep duration (in seconds). */ #define DEEPSLEEP_DURATION 10 diff --git a/src/deepsleep.c b/src/deepsleep.c index f626eb2..a7f6425 100644 --- a/src/deepsleep.c +++ b/src/deepsleep.c @@ -118,9 +118,9 @@ void deepsleep(uint32_t duration_secs) lock_rtc_access(); // enter deep sleep mode - SCB_SCR |= SCB_SCR_SLEEPDEEP; - pwr_voltage_regulator_low_power_in_stop(); pwr_set_stop_mode(); + pwr_voltage_regulator_low_power_in_stop(); + SCB_SCR |= SCB_SCR_SLEEPDEEP; __WFI(); SCB_SCR &= ~SCB_SCR_SLEEPDEEP; // no deepsleep except in this function diff --git a/src/led_chplex.c b/src/led_chplex.c index 0c1fc9d..86f138e 100644 --- a/src/led_chplex.c +++ b/src/led_chplex.c @@ -105,3 +105,17 @@ void led_chplex_mask(uint8_t mask) { led_mask = mask; } + + + +void led_chplex_deepsleep_prepare(void) +{ + // set all GPIOs to input to ensure the LEDs are properly switched off + gpio_mode_setup(LED_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, LED_ALL_PINS); +} + + +void led_chplex_deepsleep_resume(void) +{ + // nothing to do here +} diff --git a/src/led_chplex.h b/src/led_chplex.h index 13961c3..0dd01ab 100644 --- a/src/led_chplex.h +++ b/src/led_chplex.h @@ -19,4 +19,7 @@ void led_chplex_toggle(uint8_t idx); void led_chplex_mask(uint8_t mask); +void led_chplex_deepsleep_prepare(void); +void led_chplex_deepsleep_resume(void); + #endif // LED_CHPLEX_H diff --git a/src/main.c b/src/main.c index e0bf945..4e8812d 100644 --- a/src/main.c +++ b/src/main.c @@ -156,6 +156,27 @@ static void report_status(struct MeasurementResult *meas_data) } +static void low_power_mode(uint32_t duration_sec) +{ + // stop the systick counter for reliable deep sleep + systick_counter_disable(); + + // prepare the individual modules for sleep + rs485_deepsleep_prepare(); + led_chplex_deepsleep_prepare(); + + // enter deep sleep for the given duration + deepsleep(duration_sec); + + // resume the modules + led_chplex_deepsleep_resume(); + rs485_deepsleep_resume(); + + systick_counter_enable(); + rs485_enqueue("PWR:DEEPSLEEP:EXIT\n"); +} + + int main(void) { //uint32_t cpuload = 0; @@ -224,14 +245,7 @@ int main(void) } else { // charge control already idle if((timebase_ms - charge_control_idle_since) > DEEPSLEEP_DELAY) { - systick_counter_disable(); - // force the RS485 driver into receive mode. The RS485 - // driver alone consumes 150 mW if enabled. - gpio_clear(RS485_PORT, RS485_DE_PIN); - deepsleep(DEEPSLEEP_DURATION); - gpio_set(RS485_PORT, RS485_DE_PIN); - systick_counter_enable(); - rs485_enqueue("PWR:DEEPSLEEP:EXIT\n"); + low_power_mode(DEEPSLEEP_DURATION); charge_control_was_idle = false; } } diff --git a/src/rs485.c b/src/rs485.c index 1d34dfb..3c46457 100644 --- a/src/rs485.c +++ b/src/rs485.c @@ -120,3 +120,19 @@ void rs485_enqueue(const char *str) rs485_transfer(); } } + + +void rs485_deepsleep_prepare(void) +{ + // force the transceiver to RX mode + gpio_clear(RS485_PORT, RS485_DE_PIN); +} + + +void rs485_deepsleep_resume(void) +{ + // if a transmission is still in progress, switch to TX mode again + if(usartActive) { + gpio_set(RS485_PORT, RS485_DE_PIN); + } +} diff --git a/src/rs485.h b/src/rs485.h index 9325daf..5a16e8f 100644 --- a/src/rs485.h +++ b/src/rs485.h @@ -6,4 +6,7 @@ void rs485_periodic(void); void rs485_enqueue(const char *str); +void rs485_deepsleep_prepare(void); +void rs485_deepsleep_resume(void); + #endif // RS485_H