Contiki-NG
lpm.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Texas Instruments Incorporated - http://www.ti.com/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /**
32  * \addtogroup cc2538
33  * @{
34  *
35  * \defgroup cc2538-lpm cc2538 Low Power Modes
36  *
37  * Driver for the cc2538 power modes
38  * @{
39  *
40  * \file
41  * Header file with register, macro and function declarations for the cc2538
42  * low power module
43  */
44 #ifndef LPM_H_
45 #define LPM_H_
46 
47 #include "contiki.h"
48 #include "rtimer.h"
49 
50 #include <stdbool.h>
51 #include <stdint.h>
52 /*---------------------------------------------------------------------------*/
53 /**
54  * \name LPM stats
55  *
56  * Maintains a record of how many rtimer ticks spent in each Power Mode.
57  * Mainly used for debugging the module
58  * @{
59  */
60 #if LPM_CONF_STATS
61 extern rtimer_clock_t lpm_stats[3];
62 
63 /**
64  * \brief Read the time spent in a PM in rtimer ticks
65  * \param pm The pm as a value in [0,2]
66  */
67 #define LPM_STATS_GET(pm) lpm_stats[pm]
68 #else
69 #define LPM_STATS_GET(pm)
70 #endif
71 /** @} */
72 /*---------------------------------------------------------------------------*/
73 /**
74  * \name Constants to be used as arguments to lpm_set_max_pm()
75  * @{
76  */
77 #define LPM_PM0 0
78 #define LPM_PM1 1
79 #define LPM_PM2 2
80 /** @} */
81 /*---------------------------------------------------------------------------*/
82 typedef bool (*lpm_periph_permit_pm1_func_t)(void);
83 
84 #if LPM_CONF_ENABLE
85 /**
86  * \brief Initialise the LPM module
87  */
88 void lpm_init(void);
89 
90 /**
91  * \brief Drop to Deep Sleep
92  *
93  * This function triggers a sequence to enter Deep Sleep. The sequence involves
94  * determining the most suitable PM and switching the system clock source to
95  * the 16MHz if required. If the energest module is enabled, the sequence also
96  * performs some simple energest calculations.
97  *
98  * Broadly speaking, this function will be called from the main loop when all
99  * events have been serviced. This functions aims to be clever enough in order
100  * to be able to choose between PMs 0/1/2 depending on chip status and
101  * anticipated sleep duration. This choice is made subject to configuration
102  * restrictions and subject to restrictions imposed by calls to
103  * lpm_set_max_pm().
104  *
105  * This PM selection heuristic has the following primary criteria:
106  * - Is the RF off?
107  * - Are all registered peripherals permitting PM1+?
108  * - Is the Sleep Timer scheduled to fire an interrupt?
109  *
110  * If the answer to any of those questions is no, we will drop to PM0 and
111  * will wake up to any interrupt. Best case scenario (if nothing else happens),
112  * we will idle until the next SysTick in no more than 1000/CLOCK_SECOND ms
113  * (7.8125ms).
114  *
115  * If all can be answered with 'yes', we can drop to PM1/2 knowing that the
116  * Sleep Timer will wake us up. Depending on the estimated deep sleep duration
117  * and the max PM allowed by user configuration, we select the most efficient
118  * Power Mode to drop to. If the duration is too short, we simply IDLE in PM0.
119  *
120  * Dropping to PM1/2 requires a switch to the 16MHz OSC. We have the option of
121  * letting the SoC do this for us automatically. However, if an interrupt fires
122  * during this automatic switch, we will need to re-assert WFI. To avoid this
123  * complexity, we perform the switch to the 16MHz OSC manually in software and
124  * we assert WFI after the transition has been completed. This gives us a
125  * chance to bail out if an interrupt fires or an event is raised during the
126  * transition. If nothing happens, dropping to PM1+ is un-interruptible and
127  * with a deterministic duration. When we wake up, we switch back to the 32MHz
128  * OSC manually before handing control back to main. This is implemented in
129  * lpm_exit(), which will always be called from within the Sleep Timer ISR
130  * context.
131  *
132  * \note Dropping to PM2 means that data in the SRAM non-retention area will
133  * be lost. It is recommended to disable PM2 if the total RAM footprint is
134  * larger than what will fit in the retention area.
135  * .nrdata* sections can be used to place uninitialized data in the SRAM
136  * non-retention area.
137  *
138  * \sa main(), rtimer_arch_next_trigger(), lpm_exit(), lpm_set_max_pm()
139  */
140 void lpm_enter(void);
141 
142 /**
143  * \brief Perform an 'Exit Deep Sleep' sequence
144  *
145  * This routine is called from within the context of the ISR that caused us to
146  * come out of PM1/2. It performs a wake up sequence to make sure the 32MHz OSC
147  * is back on and the system clock is sourced on it.
148  *
149  * While in PMs 1 and 2, the system clock stops ticking. This functions adjusts
150  * it when we wake up.
151  *
152  * We always exit PM1/2 as a result of a scheduled rtimer task or a GPIO
153  * interrupt. This may lead to other parts of the code trying to use the RF,
154  * so we need to switch the clock source \e before said code gets executed.
155  *
156  * This function also makes sure that the sleep timer value is up-to-date
157  * following wake-up from PM1/2 so that RTIMER_NOW() works.
158  *
159  * \note This function should be called at the very beginning of ISRs waking up
160  * the SoC in order to restore all clocks and timers.
161  *
162  * \sa lpm_enter(), rtimer_isr()
163  */
164 void lpm_exit(void);
165 
166 /**
167  * \brief Prevent the SoC from dropping to a PM higher than \e max_pm
168  * \param pm The highest PM we are allowed to enter, specified as a
169  * number in [0, 2]
170  *
171  * Defines for the \e pm argument are LPM_PMx.
172  *
173  * This function can be used by software in situations where some power
174  * modes are undesirable. If, for example, an application needs to avoid PM2,
175  * it would call lpm_set_max_pm(LPM_PM1).
176  * If an application wants to avoid PM1 as well, it would call
177  * lpm_set_max_pm(LPM_PM0)
178  *
179  * PM0 can not be disabled at runtime. Use LPM_CONF_ENABLE to disable LPM
180  * support altogether
181  *
182  * \note If the value of argument \e pm is greater than the value of the
183  * LPM_CONF_MAX_PM configuration directive, LPM_CONF_MAX_PM is used. Thus
184  * if LPM_CONF_MAX_PM==1, calling lpm_set_max_pm(LPM_PM2) would
185  * result in a maximum PM set to 1 and all subsequent Deep Sleeps would
186  * be limited to either PM0 or PM1.
187  *
188  * \sa lpm_enter()
189  */
190 void lpm_set_max_pm(uint8_t pm);
191 
192 /**
193  * \brief Register a peripheral function which will get called by the LPM
194  * module to get 'permission' to drop to PM1+
195  * \param permit_pm1_func Pointer to the function
196  *
197  * Some peripherals are sensitive to PM changes. For instance, we don't want to
198  * drop to PM1+ if the USB PLL is active or if the UART TX FIFO is not clear.
199  *
200  * When changing power modes, the LPM driver will call all FPs registered with
201  * this function. The peripheral's function will return true or false to permit
202  * / prohibit PM1+ respectively. If at least one peripheral returns false, the
203  * SoC will drop to PM0 Deep Sleep instead.
204  *
205  * Registering several times the same function makes the LPM module behave as if
206  * the function had been registered once.
207  */
208 void lpm_register_peripheral(lpm_periph_permit_pm1_func_t permit_pm1_func);
209 /*---------------------------------------------------------------------------*/
210 /* Disable the entire module if required */
211 #else
212 #define lpm_init()
213 #define lpm_enter()
214 #define lpm_exit()
215 static inline void
216 lpm_set_max_pm(uint8_t pm)
217 {
218 }
219 static inline void
220 lpm_register_peripheral(lpm_periph_permit_pm1_func_t permit_pm1_func)
221 {
222 }
223 #endif
224 
225 #endif /* LPM_H_ */
226 
227 /**
228  * @}
229  * @}
230  */
#define lpm_init()
Initialise the low-power mode management module.
Definition: lpm.h:212
Header file for the real-time timer module.