standby.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Simple PWM controller
  3. * Standby coordination
  4. *
  5. * Copyright (c) 2020 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. */
  21. #include "compat.h"
  22. #include "debug.h"
  23. #include "standby.h"
  24. #include "util.h"
  25. #include "watchdog.h"
  26. #include "adc.h"
  27. #include "main.h"
  28. #include "arithmetic.h"
  29. #include "battery.h"
  30. /* Delay before entering deep sleep mode. */
  31. #define DEEP_SLEEP_DELAY_MS 5000u /* milliseconds */
  32. /* Use the deep sleep delay after this many active microseconds. */
  33. #define DEEP_SLEEP_DELAY_AFTER_ACTIVE_MS 300u /* milliseconds */
  34. enum standby_suppress {
  35. STANDBY_SUPPRESS_UNKNOWN,
  36. STANDBY_SUPPRESS_YES,
  37. STANDBY_SUPPRESS_NO,
  38. };
  39. static struct {
  40. uint16_t sys_active_ms;
  41. uint16_t delay_timer_ms;
  42. enum standby_suppress suppress[NR_STANDBY_SRC];
  43. bool was_possible;
  44. } standby;
  45. /* Check if standby is possible according to all sources. */
  46. static bool standby_is_possible(void)
  47. {
  48. uint8_t i;
  49. bool possible;
  50. if (USE_DEEP_SLEEP) {
  51. possible = true;
  52. for (i = 0u; i < NR_STANDBY_SRC; i++)
  53. possible &= standby.suppress[i] == STANDBY_SUPPRESS_NO;
  54. } else
  55. possible = false;
  56. return possible;
  57. }
  58. void set_standby_suppress(enum standby_source source, bool suppress)
  59. {
  60. if (USE_DEEP_SLEEP) {
  61. if (source < NR_STANDBY_SRC) {
  62. if (suppress)
  63. standby.suppress[source] = STANDBY_SUPPRESS_YES;
  64. else
  65. standby.suppress[source] = STANDBY_SUPPRESS_NO;
  66. }
  67. }
  68. }
  69. /* Handle wake up from deep sleep.
  70. * Interrupts shall be disabled before calling this function. */
  71. void standby_handle_deep_sleep_wakeup(void)
  72. {
  73. uint8_t i;
  74. if (USE_DEEP_SLEEP) {
  75. /* We just woke up from standby.
  76. * Reset active time and reset all suppress-flags. */
  77. standby.sys_active_ms = 0u;
  78. for (i = 0u; i < NR_STANDBY_SRC; i++)
  79. standby.suppress[i] = STANDBY_SUPPRESS_UNKNOWN;
  80. }
  81. }
  82. /* Watchdog timer interrupt service routine
  83. * for standby handling.
  84. * Interrupts shall be disabled before calling this function. */
  85. void standby_handle_watchdog_interrupt(bool wakeup_from_standby)
  86. {
  87. uint16_t sys_active_rel_ms;
  88. if (USE_DEEP_SLEEP) {
  89. sys_active_rel_ms = watchdog_interval_ms();
  90. if (!wakeup_from_standby) {
  91. /* The system is active.
  92. * Increment the active time.
  93. * The time is approximate and saturates at 65535 ms. */
  94. standby.sys_active_ms = add_sat_u16(standby.sys_active_ms,
  95. sys_active_rel_ms);
  96. }
  97. if (standby_is_possible()) {
  98. /* A deep sleep is pending.
  99. * Decrement the delay timer. */
  100. standby.delay_timer_ms = sub_sat_u16(
  101. standby.delay_timer_ms, sys_active_rel_ms);
  102. }
  103. }
  104. }
  105. /* Update the watchdog standby state, if required.
  106. * Interrupts shall be disabled before calling this function. */
  107. static void update_watchdog_standby(void)
  108. {
  109. uint8_t i;
  110. bool set_wd_standby;
  111. bool wd_standby;
  112. if (USE_DEEP_SLEEP) {
  113. set_wd_standby = true;
  114. wd_standby = true;
  115. for (i = 0u; i < NR_STANDBY_SRC; i++) {
  116. /* If any source state is still unknown, do not update WD state. */
  117. set_wd_standby &= standby.suppress[i] != STANDBY_SUPPRESS_UNKNOWN;
  118. /* WD standby, if all sources are Ok for standby. */
  119. wd_standby &= standby.suppress[i] == STANDBY_SUPPRESS_NO;
  120. }
  121. if (set_wd_standby)
  122. watchdog_set_standby(wd_standby);
  123. }
  124. }
  125. /* Main loop check: Enter deep sleep now?
  126. * Interrupts shall be disabled before calling this function. */
  127. bool standby_is_desired_now(void)
  128. {
  129. bool is_possible;
  130. bool standby_request_normal;
  131. bool standby_request_battery;
  132. bool go_standby = false;
  133. if (USE_DEEP_SLEEP) {
  134. is_possible = standby_is_possible();
  135. /* If we just got ready to enter standby
  136. * and the system has been running for some time
  137. * then delay the standby for a bit. */
  138. if (is_possible && !standby.was_possible) {
  139. if (standby.sys_active_ms >= DEEP_SLEEP_DELAY_AFTER_ACTIVE_MS)
  140. standby.delay_timer_ms = DEEP_SLEEP_DELAY_MS;
  141. }
  142. standby.was_possible = is_possible;
  143. /* Check if normal standby is requested. */
  144. standby_request_normal = (is_possible &&
  145. standby.delay_timer_ms == 0u);
  146. /* Check if standby due to critical battery voltage is requested. */
  147. standby_request_battery = (battery_voltage_is_critical() &&
  148. !adc_battery_measurement_active());
  149. if (standby_request_normal || standby_request_battery)
  150. go_standby = true;
  151. update_watchdog_standby();
  152. }
  153. return go_standby;
  154. }