This repository has been archived by the owner on Feb 22, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
/
app_timer.h
275 lines (252 loc) · 15 KB
/
app_timer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
/** @file
*
* @defgroup app_timer Application Timer
* @{
* @ingroup app_common
*
* @brief Application timer functionality.
*
* @details It enables the application to create multiple timer instances based on the RTC1
* peripheral. Checking for timeouts and invokation of user timeout handlers is performed
* in the RTC1 interrupt handler. List handling is done using a software interrupt (SWI0).
* Both interrupt handlers are running in APP_LOW priority level.
*
* @note When calling app_timer_start() or app_timer_stop(), the timer operation is just queued,
* and the software interrupt is triggered. The actual timer start/stop operation is
* executed by the SWI0 interrupt handler. Since the SWI0 interrupt is running in APP_LOW,
* if the application code calling the timer function is running in APP_LOW or APP_HIGH,
* the timer operation will not be performed until the application handler has returned.
* This will be the case e.g. when stopping a timer from a timeout handler when not using
* the scheduler.
*
* @details Use the USE_SCHEDULER parameter of the APP_TIMER_INIT() macro to select if the
* @ref app_scheduler is to be used or not.
*
* @note Even if the scheduler is not used, app_timer.h will include app_scheduler.h, so when
* compiling, app_scheduler.h must be available in one of the compiler include paths.
*/
#ifndef APP_TIMER_H__
#define APP_TIMER_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "app_error.h"
#include "app_util.h"
#include "compiler_abstraction.h"
#ifdef __cplusplus
extern "C" {
#endif
#define APP_TIMER_CLOCK_FREQ 32768 /**< Clock frequency of the RTC timer used to implement the app timer module. */
#define APP_TIMER_MIN_TIMEOUT_TICKS 5 /**< Minimum value of the timeout_ticks parameter of app_timer_start(). */
#define APP_TIMER_NODE_SIZE 40 /**< Size of app_timer.timer_node_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_OP_SIZE 24 /**< Size of app_timer.timer_user_op_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_SIZE 8 /**< Size of app_timer.timer_user_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_INT_LEVELS 3 /**< Number of interrupt levels from where timer operations may be initiated (only for use inside APP_TIMER_BUF_SIZE()). */
/**@brief Compute number of bytes required to hold the application timer data structures.
*
* @param[in] MAX_TIMERS Maximum number of timers that can be created at any given time.
* @param[in] OP_QUEUE_SIZE Size of queues holding timer operations that are pending execution.
* NOTE: Due to the queue implementation, this size must be one more
* than the size that is actually needed.
*
* @return Required application timer buffer size (in bytes).
*/
#define APP_TIMER_BUF_SIZE(MAX_TIMERS, OP_QUEUE_SIZE) \
( \
((MAX_TIMERS) * APP_TIMER_NODE_SIZE) \
+ \
( \
APP_TIMER_INT_LEVELS \
* \
(APP_TIMER_USER_SIZE + ((OP_QUEUE_SIZE) + 1) * APP_TIMER_USER_OP_SIZE) \
) \
)
/**@brief Convert milliseconds to timer ticks.
*
* @note This macro uses 64 bit integer arithmetic, but as long as the macro parameters are
* constants (i.e. defines), the computation will be done by the preprocessor.
*
* @param[in] MS Milliseconds.
* @param[in] PRESCALER Value of the RTC1 PRESCALER register (must be the same value that was
* passed to APP_TIMER_INIT()).
*
* @note When using this macro, it is the responsibility of the developer to ensure that the
* values provided as input result in an output value that is supported by the
* @ref app_timer_start function. For example, when the ticks for 1 ms is needed, the
* maximum possible value of PRESCALER must be 6, when @ref APP_TIMER_CLOCK_FREQ is 32768.
* This will result in a ticks value as 5. Any higher value for PRESCALER will result in a
* ticks value that is not supported by this module.
*
* @return Number of timer ticks.
*/
#define APP_TIMER_TICKS(MS, PRESCALER)\
((uint32_t)ROUNDED_DIV((MS) * (uint64_t)APP_TIMER_CLOCK_FREQ, ((PRESCALER) + 1) * 1000))
/**@brief Timer id type. */
typedef uint32_t app_timer_id_t;
/**@brief Application timeout handler type. */
typedef void (*app_timer_timeout_handler_t)(void * p_context);
/**@brief Type of function for passing events from the timer module to the scheduler. */
typedef uint32_t (*app_timer_evt_schedule_func_t) (app_timer_timeout_handler_t timeout_handler,
void * p_context);
/**@brief Timer modes. */
typedef enum
{
APP_TIMER_MODE_SINGLE_SHOT, /**< The timer will expire only once. */
APP_TIMER_MODE_REPEATED /**< The timer will restart each time it expires. */
} app_timer_mode_t;
/**@brief Macro for initializing the application timer module.
*
* @details It will handle dimensioning and allocation of the memory buffer required by the timer,
* making sure that the buffer is correctly aligned. It will also connect the timer module
* to the scheduler (if specified).
*
* @note This module assumes that the LFCLK is already running. If it isn't, the module will
* be non-functional, since the RTC will not run. If you don't use a softdevice, you'll
* have to start the LFCLK manually. See the rtc_example's lfclk_config() function
* for an example of how to do this. If you use a softdevice, the LFCLK is started on
* softdevice init.
*
*
* @param[in] PRESCALER Value of the RTC1 PRESCALER register. This will decide the
* timer tick rate. Set to 0 for no prescaling.
* @param[in] MAX_TIMERS Maximum number of timers that can be created at any given time.
* @param[in] OP_QUEUES_SIZE Size of queues holding timer operations that are pending execution.
* @param[in] SCHEDULER_FUNC Pointer to scheduler event handler
*
* @note Since this macro allocates a buffer, it must only be called once (it is OK to call it
* several times as long as it is from the same location, e.g. to do a reinitialization).
*/
/*lint -emacro(506, APP_TIMER_INIT) */ /* Suppress "Constant value Boolean */
#define APP_TIMER_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, SCHEDULER_FUNC) \
do \
{ \
static uint32_t APP_TIMER_BUF[CEIL_DIV(APP_TIMER_BUF_SIZE((MAX_TIMERS), \
(OP_QUEUES_SIZE) + 1), \
sizeof(uint32_t))]; \
uint32_t ERR_CODE = app_timer_init((PRESCALER), \
(MAX_TIMERS), \
(OP_QUEUES_SIZE) + 1, \
APP_TIMER_BUF, \
SCHEDULER_FUNC); \
APP_ERROR_CHECK(ERR_CODE); \
} while (0)
/**@brief Function for initializing the timer module.
*
* @note Normally initialization should be done using the APP_TIMER_INIT() macro, as that will both
* allocate the buffers needed by the timer module (including aligning the buffers correctly,
* and also take care of connecting the timer module to the scheduler (if specified).
*
* @param[in] prescaler Value of the RTC1 PRESCALER register. Set to 0 for no prescaling.
* @param[in] max_timers Maximum number of timers that can be created at any given time.
* @param[in] op_queues_size Size of queues holding timer operations that are pending
* execution. NOTE: Due to the queue implementation, this size must
* be one more than the size that is actually needed.
* @param[in] p_buffer Pointer to memory buffer for internal use in the app_timer
* module. The size of the buffer can be computed using the
* APP_TIMER_BUF_SIZE() macro. The buffer must be aligned to a
* 4 byte boundary.
* @param[in] evt_schedule_func Function for passing timeout events to the scheduler. Point to
* app_timer_evt_schedule() to connect to the scheduler. Set to NULL
* to make the timer module call the timeout handler directly from
* the timer interrupt handler.
*
* @retval NRF_SUCCESS Successful initialization.
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter (buffer not aligned to a 4 byte
* boundary or NULL).
*/
uint32_t app_timer_init(uint32_t prescaler,
uint8_t max_timers,
uint8_t op_queues_size,
void * p_buffer,
app_timer_evt_schedule_func_t evt_schedule_func);
/**@brief Function for creating a timer instance.
*
* @param[out] p_timer_id Id of the newly created timer.
* @param[in] mode Timer mode.
* @param[in] timeout_handler Function to be executed when the timer expires.
*
* @retval NRF_SUCCESS Timer was successfully created.
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter.
* @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized.
* @retval NRF_ERROR_NO_MEM Maximum number of timers has already been reached.
*
* @note This function does the timer allocation in the caller's context. It is also not protected
* by a critical region. Therefore care must be taken not to call it from several interrupt
* levels simultaneously.
*/
uint32_t app_timer_create(app_timer_id_t * p_timer_id,
app_timer_mode_t mode,
app_timer_timeout_handler_t timeout_handler);
/**@brief Function for starting a timer.
*
* @param[in] timer_id Id of timer to start.
* @param[in] timeout_ticks Number of ticks (of RTC1, including prescaling) to timeout event
* (minimum 5 ticks).
* @param[in] p_context General purpose pointer. Will be passed to the timeout handler when
* the timer expires.
*
* @retval NRF_SUCCESS Timer was successfully started.
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter.
* @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized, or timer
* has not been created.
* @retval NRF_ERROR_NO_MEM Timer operations queue was full.
*
* @note The minimum timeout_ticks value is 5.
* @note For multiple active timers, timeouts occurring in close proximity to each other (in the
* range of 1 to 3 ticks) will have a positive jitter of maximum 3 ticks.
* @note When calling this method on a timer which is already running, the second start operation
* will be ignored.
*/
uint32_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context);
/**@brief Function for stopping the specified timer.
*
* @param[in] timer_id Id of timer to stop.
*
* @retval NRF_SUCCESS Timer was successfully stopped.
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter.
* @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized, or timer
* has not been created.
* @retval NRF_ERROR_NO_MEM Timer operations queue was full.
*/
uint32_t app_timer_stop(app_timer_id_t timer_id);
/**@brief Function for stopping all running timers.
*
* @retval NRF_SUCCESS All timers were successfully stopped.
* @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized.
* @retval NRF_ERROR_NO_MEM Timer operations queue was full.
*/
uint32_t app_timer_stop_all(void);
/**@brief Function for returning the current value of the RTC1 counter.
*
* @param[out] p_ticks Current value of the RTC1 counter.
*
* @retval NRF_SUCCESS Counter was successfully read.
*/
uint32_t app_timer_cnt_get(uint32_t * p_ticks);
/**@brief Function for computing the difference between two RTC1 counter values.
*
* @param[in] ticks_to Value returned by app_timer_cnt_get().
* @param[in] ticks_from Value returned by app_timer_cnt_get().
* @param[out] p_ticks_diff Number of ticks from ticks_from to ticks_to.
*
* @retval NRF_SUCCESS Counter difference was successfully computed.
*/
uint32_t app_timer_cnt_diff_compute(uint32_t ticks_to,
uint32_t ticks_from,
uint32_t * p_ticks_diff);
#ifdef __cplusplus
}
#endif
#endif // APP_TIMER_H__
/** @} */