Properly shut down peripherals before entering deep sleep
This is most important for the LEDs and the RS485 interface. If any LED is on when deep sleep is entered, it will stay on the whole sleep time, drawing about 10 mA on the 3,3V rail. The RS485 transceiver must be switched to RX mode, as it consumes about 30 mA from the 5V rail in TX mode.
This commit is contained in:
parent
5ceb014d1b
commit
df3211333e
|
@ -56,7 +56,7 @@
|
||||||
/* Generic configuration */
|
/* Generic configuration */
|
||||||
|
|
||||||
/* Time (in ms) to stay active in idle state before entering deep sleep. */
|
/* 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). */
|
/* Deep sleep duration (in seconds). */
|
||||||
#define DEEPSLEEP_DURATION 10
|
#define DEEPSLEEP_DURATION 10
|
||||||
|
|
|
@ -118,9 +118,9 @@ void deepsleep(uint32_t duration_secs)
|
||||||
lock_rtc_access();
|
lock_rtc_access();
|
||||||
|
|
||||||
// enter deep sleep mode
|
// enter deep sleep mode
|
||||||
SCB_SCR |= SCB_SCR_SLEEPDEEP;
|
|
||||||
pwr_voltage_regulator_low_power_in_stop();
|
|
||||||
pwr_set_stop_mode();
|
pwr_set_stop_mode();
|
||||||
|
pwr_voltage_regulator_low_power_in_stop();
|
||||||
|
SCB_SCR |= SCB_SCR_SLEEPDEEP;
|
||||||
__WFI();
|
__WFI();
|
||||||
SCB_SCR &= ~SCB_SCR_SLEEPDEEP; // no deepsleep except in this function
|
SCB_SCR &= ~SCB_SCR_SLEEPDEEP; // no deepsleep except in this function
|
||||||
|
|
||||||
|
|
|
@ -105,3 +105,17 @@ void led_chplex_mask(uint8_t mask)
|
||||||
{
|
{
|
||||||
led_mask = 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
|
||||||
|
}
|
||||||
|
|
|
@ -19,4 +19,7 @@ void led_chplex_toggle(uint8_t idx);
|
||||||
|
|
||||||
void led_chplex_mask(uint8_t mask);
|
void led_chplex_mask(uint8_t mask);
|
||||||
|
|
||||||
|
void led_chplex_deepsleep_prepare(void);
|
||||||
|
void led_chplex_deepsleep_resume(void);
|
||||||
|
|
||||||
#endif // LED_CHPLEX_H
|
#endif // LED_CHPLEX_H
|
||||||
|
|
30
src/main.c
30
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)
|
int main(void)
|
||||||
{
|
{
|
||||||
//uint32_t cpuload = 0;
|
//uint32_t cpuload = 0;
|
||||||
|
@ -224,14 +245,7 @@ int main(void)
|
||||||
} else {
|
} else {
|
||||||
// charge control already idle
|
// charge control already idle
|
||||||
if((timebase_ms - charge_control_idle_since) > DEEPSLEEP_DELAY) {
|
if((timebase_ms - charge_control_idle_since) > DEEPSLEEP_DELAY) {
|
||||||
systick_counter_disable();
|
low_power_mode(DEEPSLEEP_DURATION);
|
||||||
// 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");
|
|
||||||
charge_control_was_idle = false;
|
charge_control_was_idle = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/rs485.c
16
src/rs485.c
|
@ -120,3 +120,19 @@ void rs485_enqueue(const char *str)
|
||||||
rs485_transfer();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,4 +6,7 @@ void rs485_periodic(void);
|
||||||
|
|
||||||
void rs485_enqueue(const char *str);
|
void rs485_enqueue(const char *str);
|
||||||
|
|
||||||
|
void rs485_deepsleep_prepare(void);
|
||||||
|
void rs485_deepsleep_resume(void);
|
||||||
|
|
||||||
#endif // RS485_H
|
#endif // RS485_H
|
||||||
|
|
Loading…
Reference in a new issue