1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_TIMER_H
8 #define _HARDWARE_TIMER_H
9 
10 #include "pico.h"
11 #include "hardware/structs/timer.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /** \file hardware/timer.h
18  *  \defgroup hardware_timer hardware_timer
19  *
20  * Low-level hardware timer API
21  *
22  * This API provides medium level access to the timer HW.
23  * See also \ref pico_time which provides higher levels functionality using the hardware timer.
24  *
25  * The timer peripheral on RP2040 supports the following features:
26  *  - single 64-bit counter, incrementing once per microsecond
27  *  - Latching two-stage read of counter, for race-free read over 32 bit bus
28  *  - Four alarms: match on the lower 32 bits of counter, IRQ on match.
29  *
30  * By default the timer uses a one microsecond reference that is generated in the Watchdog (see Section 4.8.2) which is derived
31  * from the clk_ref.
32  *
33  * The timer has 4 alarms, and can output a separate interrupt for each alarm. The alarms match on the lower 32 bits of the 64
34  * bit counter which means they can be fired a maximum of 2^32 microseconds into the future. This is equivalent to:
35  *  - 2^32 ÷ 10^6: ~4295 seconds
36  *  - 4295 ÷ 60: ~72 minutes
37  *
38  * The timer is expected to be used for short sleeps, if you want a longer alarm see the \ref hardware_rtc functions.
39  *
40  * \subsection timer_example Example
41  * \addtogroup hardware_timer
42  *
43  * \include hello_timer.c
44  *
45  * \see pico_time
46  */
47 
48 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_TIMER, Enable/disable assertions in the timer module, type=bool, default=0, group=hardware_timer
49 #ifndef PARAM_ASSERTIONS_ENABLED_TIMER
50 #define PARAM_ASSERTIONS_ENABLED_TIMER 0
51 #endif
52 
check_hardware_alarm_num_param(__unused uint alarm_num)53 static inline void check_hardware_alarm_num_param(__unused uint alarm_num) {
54     invalid_params_if(TIMER, alarm_num >= NUM_TIMERS);
55 }
56 
57 /*! \brief Return a 32 bit timestamp value in microseconds
58 *  \ingroup hardware_timer
59 *
60 * Returns the low 32 bits of the hardware timer.
61 * \note This value wraps roughly every 1 hour 11 minutes and 35 seconds.
62 *
63 * \return the 32 bit timestamp
64 */
time_us_32(void)65 static inline uint32_t time_us_32(void) {
66     return timer_hw->timerawl;
67 }
68 
69 /*! \brief Return the current 64 bit timestamp value in microseconds
70 *  \ingroup hardware_timer
71 *
72 * Returns the full 64 bits of the hardware timer. The \ref pico_time and other functions rely on the fact that this
73 * value monotonically increases from power up. As such it is expected that this value counts upwards and never wraps
74 * (we apologize for introducing a potential year 5851444 bug).
75 *
76 * \return the 64 bit timestamp
77 */
78 uint64_t time_us_64(void);
79 
80 /*! \brief Busy wait wasting cycles for the given (32 bit) number of microseconds
81  *  \ingroup hardware_timer
82  *
83  * \param delay_us delay amount in microseconds
84  */
85 void busy_wait_us_32(uint32_t delay_us);
86 
87 /*! \brief Busy wait wasting cycles for the given (64 bit) number of microseconds
88  *  \ingroup hardware_timer
89  *
90  * \param delay_us delay amount in microseconds
91  */
92 void busy_wait_us(uint64_t delay_us);
93 
94 /*! \brief Busy wait wasting cycles for the given number of milliseconds
95  *  \ingroup hardware_timer
96  *
97  * \param delay_ms delay amount in milliseconds
98  */
99 void busy_wait_ms(uint32_t delay_ms);
100 
101 /*! \brief Busy wait wasting cycles until after the specified timestamp
102  *  \ingroup hardware_timer
103  *
104  * \param t Absolute time to wait until
105  */
106 void busy_wait_until(absolute_time_t t);
107 
108 /*! \brief Check if the specified timestamp has been reached
109  *  \ingroup hardware_timer
110  *
111  * \param t Absolute time to compare against current time
112  * \return true if it is now after the specified timestamp
113  */
time_reached(absolute_time_t t)114 static inline bool time_reached(absolute_time_t t) {
115     uint64_t target = to_us_since_boot(t);
116     uint32_t hi_target = (uint32_t)(target >> 32u);
117     uint32_t hi = timer_hw->timerawh;
118     return (hi >= hi_target && (timer_hw->timerawl >= (uint32_t) target || hi != hi_target));
119 }
120 
121 /*! Callback function type for hardware alarms
122  *  \ingroup hardware_timer
123  *
124  * \param alarm_num the hardware alarm number
125  * \sa hardware_alarm_set_callback()
126  */
127 typedef void (*hardware_alarm_callback_t)(uint alarm_num);
128 
129 /*! \brief cooperatively claim the use of this hardware alarm_num
130  *  \ingroup hardware_timer
131  *
132  * This method hard asserts if the hardware alarm is currently claimed.
133  *
134  * \param alarm_num the hardware alarm to claim
135  * \sa hardware_claiming
136  */
137 void hardware_alarm_claim(uint alarm_num);
138 
139 /*! \brief cooperatively claim the use of this hardware alarm_num
140  *  \ingroup hardware_timer
141  *
142  * This method attempts to claim an unused hardware alarm
143  *
144  * \return alarm_num the hardware alarm claimed or -1 if requires was false, and none are available
145  * \sa hardware_claiming
146  */
147 int hardware_alarm_claim_unused(bool required);
148 
149 /*! \brief cooperatively release the claim on use of this hardware alarm_num
150  *  \ingroup hardware_timer
151  *
152  * \param alarm_num the hardware alarm to unclaim
153  * \sa hardware_claiming
154  */
155 void hardware_alarm_unclaim(uint alarm_num);
156 
157 /*! \brief Determine if a hardware alarm has been claimed
158  *  \ingroup hardware_timer
159  *
160  * \param alarm_num the hardware alarm number
161  * \return true if claimed, false otherwise
162  * \see hardware_alarm_claim
163  */
164 bool hardware_alarm_is_claimed(uint alarm_num);
165 
166 /*! \brief Enable/Disable a callback for a hardware timer on this core
167  *  \ingroup hardware_timer
168  *
169  * This method enables/disables the alarm IRQ for the specified hardware alarm on the
170  * calling core, and set the specified callback to be associated with that alarm.
171  *
172  * This callback will be used for the timeout set via hardware_alarm_set_target
173  *
174  * \note This will install the handler on the current core if the IRQ handler isn't already set.
175  * Therefore the user has the opportunity to call this up from the core of their choice
176  *
177  * \param alarm_num the hardware alarm number
178  * \param callback the callback to install, or NULL to unset
179  *
180  * \sa hardware_alarm_set_target()
181  */
182 void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
183 
184 /**
185  * \brief Set the current target for the specified hardware alarm
186  * \ingroup hardware_timer
187  *
188  * This will replace any existing target
189  *
190  * @param alarm_num the hardware alarm number
191  * @param t the target timestamp
192  * @return true if the target was "missed"; i.e. it was in the past, or occurred before a future hardware timeout could be set
193  */
194 bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
195 
196 /**
197  * \brief Cancel an existing target (if any) for a given hardware_alarm
198  * \ingroup hardware_timer
199  *
200  * @param alarm_num the hardware alarm number
201  */
202 void hardware_alarm_cancel(uint alarm_num);
203 
204 /**
205  * \brief Force and IRQ for a specific hardware alarm
206  * \ingroup hardware_timer
207  *
208  * This method will forcibly make sure the current alarm callback (if present) for the hardware
209  * alarm is called from an IRQ context after this call. If an actual callback is due at the same
210  * time then the callback may only be called once.
211  *
212  * Calling this method does not otherwise interfere with regular callback operations.
213  *
214  * @param alarm_num the hardware alarm number
215  */
216 void hardware_alarm_force_irq(uint alarm_num);
217 #ifdef __cplusplus
218 }
219 #endif
220 #endif
221