1+ /* * This file contains implementation of timed sleeping which are common amongst AVR chips.
2+ *
3+ * SimpleSleep methods in this file are typically declared as weak so that variants may
4+ * define their own.
5+ *
6+ * Keep ifdef to a minimum, use variant implementation files if there is any substantial difference.
7+ */
8+
9+ #if defined (__AVR__)
10+
11+ #include " ../SimpleSleep.h"
12+
13+ static void timed_sleep (uint32_t sleepMs, uint8_t mode, uint8_t bod, uint8_t interrupts);
14+
15+ __attribute__ ((weak)) void SimpleSleep::sleepDeeply(uint32_t sleepMs)
16+ {
17+ // ADC OFF
18+ uint8_t oldADCSRA = ADCSRA;
19+ ADCSRA &= ~(1 << ADEN);
20+
21+ power_declare_all ();
22+ power_save_all ();
23+ power_all_disable ();
24+
25+
26+ // For a timed sleep we may need millis() in order
27+ // to make up sleep to a multiple of 15mS (min sleep period)
28+ // so we will need to leave timer0 powered up (obviously
29+ // during the actual power-down it won't be counting
30+ // we only need it to count between the power-down periods
31+ // of which a timed_sleep might be made up of more than one).
32+ #if power_has_power()
33+ power_timer0_enable ();
34+ #endif
35+
36+ // sleep with bod off, interrupts on
37+ timed_sleep (sleepMs, SLEEP_MODE_PWR_DOWN, false , true );
38+
39+
40+ power_restore_all ();
41+ ADCSRA = oldADCSRA;
42+ }
43+
44+ __attribute__ ((weak)) void SimpleSleep::sleepLightly(uint32_t sleepMs)
45+ {
46+ // ADC OFF
47+ uint8_t oldADCSRA = ADCSRA;
48+ ADCSRA &= ~(1 << ADEN);
49+
50+ // sleep with bod off, interrupts on
51+ #ifdef SLEEP_MODE_EXT_STANDBY
52+ timed_sleep (sleepMs, SLEEP_MODE_EXT_STANDBY, false , true );
53+ #else
54+ timed_sleep (sleepMs, SLEEP_MODE_ADC, false , true );
55+ #endif
56+
57+ ADCSRA = oldADCSRA;
58+ }
59+
60+ __attribute__ ((weak)) void SimpleSleep::sleepIdle(uint32_t sleepMs)
61+ {
62+ timed_sleep (sleepMs, SLEEP_MODE_IDLE, true , true );
63+ }
64+
65+ #if WDT_HAS_INTERRUPT == 1
66+ volatile uint8_t wdt_triggered = 1 ;
67+
68+ ISR (WDT_vect)
69+ {
70+ wdt_disable ();
71+ wdt_triggered = 1 ;
72+ }
73+
74+ static void timed_sleep (uint32_t sleepMs, uint8_t mode, uint8_t bod, uint8_t interrupts)
75+ {
76+ do
77+ {
78+ // If we are not waiting on the WDT, and there is time still to sleep, setup the WDT (again)
79+ if (wdt_triggered && sleepMs)
80+ {
81+ wdt_triggered = 0 ;
82+ wdt_enable (wdt_period_for (&sleepMs));
83+ WDTCSR |= (1 << WDIE);
84+ }
85+
86+ set_sleep_mode (mode);
87+ cli ();
88+ sleep_enable ();
89+ #ifdef sleep_bod_disable
90+ if (!bod)
91+ {
92+ sleep_bod_disable ();
93+ }
94+ #else
95+ (void )(bod); // Silence warning
96+ #endif
97+
98+ // Caution, with interrupts disabled the only way you are likely
99+ // to wake up is with a reset
100+ if (interrupts)
101+ {
102+ sei ();
103+ }
104+
105+ sleep_cpu ();
106+ sleep_disable ();
107+ sei ();
108+ } while (!wdt_triggered || sleepMs > 0 );
109+ }
110+
111+ #else
112+
113+ /* * This implements timed sleep without WDT, instead we force into IDLE mode and just
114+ * spin-wait until the time is up. millis() must be available.
115+ *
116+ */
117+
118+ void timed_sleep (uint32_t sleepMs, uint8_t mode, uint8_t bod, uint8_t interrupts)
119+ {
120+ mode = SLEEP_MODE_IDLE;
121+ uint32_t startSleep = millis ();
122+
123+ do
124+ {
125+ // If we are not waiting on the WDT, and there is time still to sleep, setup the WDT (again)
126+ if ((millis () - startSleep)>=sleepMs)
127+ {
128+ return ;
129+ }
130+
131+
132+ set_sleep_mode (mode);
133+ cli ();
134+ sleep_enable ();
135+ #ifdef sleep_bod_disable
136+ if (!bod)
137+ {
138+ sleep_bod_disable ();
139+ }
140+ #else
141+ (void )(bod); // Silence warning
142+ #endif
143+
144+ // Caution, with interrupts disabled the only way you are likely
145+ // to wake up is with a reset
146+ if (interrupts)
147+ {
148+ sei ();
149+ }
150+
151+ sleep_cpu ();
152+ sleep_disable ();
153+ sei ();
154+ } while (sleepMs > 0 );
155+
156+ }
157+ #endif
158+
159+ #endif
0 commit comments