SimpleSleep
An Arduino library for simple means of putting your Arduino into low power sleep modes.
avr.h
Go to the documentation of this file.
1 
6 #ifndef SS_AVR_h
7 #define SS_AVR_h
8 #if defined (__AVR__)
9 
10 #include <Arduino.h>
11 
12 #include <avr/sleep.h>
13 #include <avr/wdt.h>
14 #include <avr/power.h>
15 #include <avr/interrupt.h>
16 
19 #include "ATMegaX8.h"
20 #include "ATTinyX5.h"
21 #include "ATTinyX4.h"
22 #include "ATTiny13.h"
23 
24 #ifndef SS_SUPPORTED_CHIP
25  #error "SimpleSleep does not support this microcontroller."
26 #endif
27 
33 #ifndef SS_USE_INT_CAL
34  #define SS_USE_INT_CAL 1
35 #endif
36 
37 #ifdef NO_MILLIS
38 
39  /* If millis is not available, then we can not really do calibration,
40  * the calibration will always just return 1
41  */
42 
43  typedef uint8_t SimpleSleep_Cal;
44 
45 #elif SS_USE_INT_CAL == 1
46 
58 struct SimpleSleep_Cal
59 {
60  int8_t adjust15MS = 0; // Increase or decrease the sleepMs by this many mS every 15mS
61  int8_t adjust250MS = 0; // Increase or decrease the sleepMs by this many mS every 250mS
62 };
63 
64 #else
65 
69 typedef float SimpleSleep_Cal;
70 #endif
71 
73 #ifndef WDT_HAS_INTERRUPT
74  #if !defined(WDIE) && !defined(WDTIE)
75  #define WDT_HAS_INTERRUPT 0
76  #else
77  #define WDT_HAS_INTERRUPT 1
78  #endif
79 #endif
80 
90 inline uint16_t wdt_period_for(uint32_t *sleepMs)
91 {
92  #ifdef WDP3
93  // 8000, 4000, 2000, 1000, 500, 250, and then 120, 60, 30, 15
94  uint16_t period = 8000;
95  int8_t x = 9;
96  #else
97  // 2000, 1000, 500, 250, and then 120, 60, 30, 15
98  uint16_t period = 2000;
99  int8_t x = 7;
100  #endif
101 
102  while(x >= 1)
103  {
104  if(*sleepMs >= period)
105  {
106  *sleepMs -= period;
107  return x;
108  }
109 
110  x--;
111  period/=2;
112 
113  // There are two sequences, 8000->250 and 120->15 so that you don't
114  // end up fractional,so once we hit 125, drop down to the 120->15 seequence
115  if(period == 125)
116  {
117  period = 120;
118  }
119  }
120 
121  // The sleep time is less than 30mS (x == 1), if it's greater than 15mS,
122  // spin-wait until it's 15mS then allow the WDT to do the rest, if it's less
123  // than 15mS then 15mS it is, that is the minimum we can sleep for and we
124  // MUST sleep.
125 
126  if(*sleepMs > 15)
127  {
128  delay(*sleepMs - 15);
129  }
130 
131  *sleepMs = 0;
132  return WDTO_15MS;
133 }
134 
150 #define power_declare_all(...) \
151  power_declare_prr(__VA_ARGS__); \
152  power_declare_prr0(__VA_ARGS__);\
153  power_declare_prr1(__VA_ARGS__);\
154  power_declare_prr2(__VA_ARGS__);\
155  power_declare_prpa(__VA_ARGS__);\
156  power_declare_prpb(__VA_ARGS__);\
157  power_declare_prpc(__VA_ARGS__);\
158  power_declare_prpd(__VA_ARGS__);\
159  power_declare_prpe(__VA_ARGS__);\
160  power_declare_prpf(__VA_ARGS__);\
161  power_declare_prgen(__VA_ARGS__);
162 
163 
174 #define power_save_all() \
175  power_save_prr(); \
176  power_save_prr0();\
177  power_save_prr1();\
178  power_save_prr2();\
179  power_save_prpa();\
180  power_save_prpb();\
181  power_save_prpc();\
182  power_save_prpd();\
183  power_save_prpe();\
184  power_save_prpf();\
185  power_save_prgen();
186 
187 
198 #define power_restore_all() \
199  power_restore_prr(); \
200  power_restore_prr0();\
201  power_restore_prr1();\
202  power_restore_prr2();\
203  power_restore_prpa();\
204  power_restore_prpb();\
205  power_restore_prpc();\
206  power_restore_prpd();\
207  power_restore_prpe();\
208  power_restore_prpf();\
209  power_restore_prgen();
210 
211 // The below register names are extraced from
212 // cat ./hardware/tools/avr/avr/include/avr/power.h | grep "define powe" | grep -Po "[0-9A-Z_]+ &" | sort | uniq
213 
214 #ifdef PRR
215  #define power_declare_prr(...) __VA_ARGS__ uint8_t oldPRR;
216  #define power_save_prr() oldPRR = PRR;
217  #define power_restore_prr() PRR = oldPRR;
218 #else
219  #define power_declare_prr(...)
220  #define power_save_prr()
221  #define power_restore_prr()
222 #endif
223 
224 #ifdef PRR0
225  #define power_declare_prr0(...) __VA_ARGS__ uint8_t oldPRR0;
226  #define power_save_prr0() oldPRR0 = PRR0;
227  #define power_restore_prr0() PRR = oldPRR0;
228 #else
229  #define power_declare_prr0(...)
230  #define power_save_prr0()
231  #define power_restore_prr0()
232 #endif
233 
234 #ifdef PRR1
235  #define power_declare_prr1(...) __VA_ARGS__ uint8_t oldPRR1;
236  #define power_save_prr1() oldPRR1 = PRR1;
237  #define power_restore_prr1() PRR = oldPRR1;
238 #else
239  #define power_declare_prr1(...)
240  #define power_save_prr1()
241  #define power_restore_prr1()
242 #endif
243 
244 #ifdef PRR2
245  #define power_declare_prr2(...) __VA_ARGS__ uint8_t oldPRR2;
246  #define power_save_prr2() oldPRR2 = PRR2;
247  #define power_restore_prr2() PRR = oldPRR2;
248 #else
249  #define power_declare_prr2(...)
250  #define power_save_prr2()
251  #define power_restore_prr2()
252 #endif
253 
254 #ifdef PR_PRPF
255  #define power_declare_prpf(...) __VA_ARGS__ uint8_t oldPRPF;
256  #define power_save_prpf() oldPR_PRPF = PR_PRPF;
257  #define power_restore_prpf() PR_PRPF = oldPR_PRPF;
258 #else
259  #define power_declare_prpf(...)
260  #define power_save_prpf()
261  #define power_restore_prpf()
262 #endif
263 
264 #ifdef PR_PRPE
265  #define power_declare_prpe(...) __VA_ARGS__ uint8_t oldPRPE;
266  #define power_save_prpe() oldPR_PRPE = PR_PRPE;
267  #define power_restore_prpe() PR_PRPE = oldPR_PRPE;
268 #else
269  #define power_declare_prpe(...)
270  #define power_save_prpe()
271  #define power_restore_prpe()
272 #endif
273 
274 #ifdef PR_PRPD
275  #define power_declare_prpd(...) __VA_ARGS__ uint8_t oldPRPD;
276  #define power_save_prpd() oldPR_PRPD = PR_PRPD;
277  #define power_restore_prpd() PR_PRPD = oldPR_PRPD;
278 #else
279  #define power_declare_prpd(...)
280  #define power_save_prpd()
281  #define power_restore_prpd()
282 #endif
283 
284 #ifdef PR_PRPC
285  #define power_declare_prpc(...) __VA_ARGS__ uint8_t oldPRPC;
286  #define power_save_prpc() oldPR_PRPC = PR_PRPC;
287  #define power_restore_prpc() PR_PRPC = oldPR_PRPC;
288 #else
289  #define power_declare_prpc(...)
290  #define power_save_prpc()
291  #define power_restore_prpc()
292 #endif
293 
294 #ifdef PR_PRPB
295  #define power_declare_prpb(...) __VA_ARGS__ uint8_t oldPRPB;
296  #define power_save_prpb() oldPR_PRPB = PR_PRPB;
297  #define power_restore_prpb() PR_PRPB = oldPR_PRPB;
298 #else
299  #define power_declare_prpb(...)
300  #define power_save_prpb()
301  #define power_restore_prpb()
302 #endif
303 
304 #ifdef PR_PRPA
305  #define power_declare_prpa(...) __VA_ARGS__ uint8_t oldPRPA;
306  #define power_save_prpa() oldPR_PRPA = PR_PRPA;
307  #define power_restore_prpa() PR_PRPA = oldPR_PRPA;
308 #else
309  #define power_declare_prpa(...)
310  #define power_save_prpa()
311  #define power_restore_prpa()
312 #endif
313 
314 #ifdef PR_PRGEN
315  #define power_declare_prgen(...) __VA_ARGS__ uint8_t oldPRGEN;
316  #define power_save_prgen() oldPR_PRGEN = PR_PRGEN;
317  #define power_restore_prgen() PR_PRGEN = oldPR_PRGEN;
318 #else
319  #define power_declare_prgen(...)
320  #define power_save_prgen()
321  #define power_restore_prgen()
322 #endif
323 
324 #if defined(PRR) || defined(PRR0) || defined(PRR1) || defined(PRR2) || \
325  defined( PR_PRPA ) || defined( PR_PRPB ) || defined( PR_PRPC ) || defined( PR_PRPD ) || defined( PR_PRPE ) || defined( PR_PRPF ) || \
326  defined(PRGEN)
327 
328  #define power_has_power() 1
329 #else
330  #define power_has_power() 0
331 #endif
332 #endif
333 #endif