1 /*
2 * Copyright (c) 2016-2020, Texas Instruments Incorporated
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 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /** ============================================================================
33 * @file ClockP.h
34 *
35 * @brief Clock interface for the RTOS Porting Interface
36 *
37 * The ClockP module can be used to schedule functions that run at intervals
38 * specified in the underlying kernel's system ticks. ClockP instances are
39 * one-shot. The one-shot function will be run once
40 * after the specified period has elapsed since calling ClockP_start().
41 *
42 * The ClockP module can also be used to obtain the period of the kernel's
43 * system tick in microseconds. This is useful for determining the number of
44 * ticks needed for setting a Clock object's period.
45 *
46 * When using the TI-RTOS kernel, ClockP functions are run at software
47 * interrupt level. With FreeRTOS, the ClockP functions are run by a timer
48 * service task with priority configured by the application.
49 *
50 * A common use case is to post a semaphore in the clock function. There is a
51 * specific API for this: Semaphore_postFromClock(). This must be used in a
52 * clock function (instead of Semaphore_post).
53 *
54 * ============================================================================
55 */
56
57 #ifndef ti_dpl_ClockP__include
58 #define ti_dpl_ClockP__include
59
60 #include <stdint.h>
61 #include <stdbool.h>
62 #include <stddef.h>
63
64 #include <zephyr/kernel.h>
65
66 #ifdef __cplusplus
67 extern "C" {
68 #endif
69
70 #define US_PER_S 1000000UL
71 #define MS_PER_S 1000UL
72
73 /* Divide and round up. */
74 #define CLOCKP_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
75
76 /* Divide and round to the closest value (only works if both, n and d, are
77 * positive).
78 */
79 #define CLOCKP_DIV_ROUND(n, d) (((n) + ((d) / 2)) / (d))
80
81 /*!
82 * @brief Prototype for a ClockP function.
83 */
84 typedef void (*ClockP_Fxn)(uintptr_t arg);
85
86 /*!
87 * @brief Number of bytes greater than or equal to the size of any RTOS
88 * ClockP object.
89 *
90 * nortos: 32 (biggest of the HW-specific ClockP instance structs)
91 * SysBIOS: 36
92 * Zephyr: Modified to match size of ClockP_Obj
93 */
94 #define ClockP_STRUCT_SIZE (sizeof(struct k_timer) + \
95 sizeof(ClockP_Fxn) + sizeof(uintptr_t) + \
96 sizeof(uint32_t) * 2) + sizeof(bool)
97
98 /*!
99 * @brief ClockP structure.
100 *
101 * Opaque structure that should be large enough to hold any of the
102 * RTOS specific ClockP objects.
103 */
104 typedef union ClockP_Struct {
105 uint32_t dummy; /*!< Align object */
106 char data[ClockP_STRUCT_SIZE];
107 } ClockP_Struct;
108
109 /*!
110 * @brief Frequency-in-hertz struct
111 */
112 typedef struct {
113 uint32_t hi; /*!< most significant 32-bits of frequency */
114 uint32_t lo; /*!< least significant 32-bits of frequency */
115 } ClockP_FreqHz;
116
117 /*!
118 * @brief Status codes for ClockP APIs
119 */
120 typedef enum {
121 ClockP_OK = 0,
122 ClockP_FAILURE = -1
123 } ClockP_Status;
124
125 /*!
126 * @brief Opaque client reference to an instance of a ClockP
127 *
128 * A ClockP_Handle returned from the ::ClockP_create represents that instance.
129 * and then is used in the other instance based functions (e.g. ::ClockP_start,
130 * ::ClockP_stop, etc.).
131 */
132 typedef void *ClockP_Handle;
133
134 #define ClockP_handle(x) ((ClockP_Handle)(x))
135
136 /*!
137 * @brief Basic ClockP Parameters
138 *
139 * Structure that contains the parameters passed into ::ClockP_create
140 * when creating a ClockP instance. The ::ClockP_Params_init function should
141 * be used to initialize the fields to default values before the application
142 * sets the fields manually. The ClockP default parameters are noted in
143 * ClockP_Params_init.
144 * The default startFlag is false, meaning the user will have to call
145 * ClockP_start(). If startFlag is true, the clock instance will be
146 * started automatically when it is created.
147 *
148 * The default value of period is 0, indicating a one-shot clock object.
149 * A non-zero period indicates the clock function will be called
150 * periodically at the period rate (in system clock ticks), after the
151 * clock is initially started and set to expire with the 'timeout'
152 * argument.
153 */
154 typedef struct {
155 bool startFlag; /*!< Start immediately after instance is created. */
156 uint32_t period; /*!< Period of clock object in system ticks. */
157 uintptr_t arg; /*!< Argument passed into the clock function. */
158 } ClockP_Params;
159
160
161 /*!
162 * @brief Function to construct a clock object.
163 *
164 * @param clockP Pointer to ClockP_Struct object.
165 * @param timeout The startup timeout, if supported by the RTOS.
166 * @param clockFxn Function called when timeout or period expires.
167 *
168 * @param params Pointer to the instance configuration parameters. NULL
169 * denotes to use the default parameters. The ClockP default
170 * parameters are noted in ::SwiP_Params_init.
171 *
172 * @return A ClockP_Handle on success or a NULL on an error
173 */
174 extern ClockP_Handle ClockP_construct(ClockP_Struct *clockP,
175 ClockP_Fxn clockFxn,
176 uint32_t timeout,
177 ClockP_Params *params);
178
179 /*!
180 * @brief Function to destruct a clock object
181 *
182 * @param clockP Pointer to a ClockP_Struct object that was passed to
183 * ClockP_construct().
184 *
185 * @return
186 */
187 extern void ClockP_destruct(ClockP_Struct *clockP);
188
189 /*!
190 * @brief Function to create a clock object.
191 *
192 * @param clockFxn Function called when timeout or period expires.
193 * @param timeout The startup timeout, if supported by the RTOS.
194 * @param params Pointer to the instance configuration parameters. NULL
195 * denotes to use the default parameters. The ClockP default
196 * parameters are noted in ::ClockP_Params_init.
197 *
198 * @return A ClockP_Handle on success or a NULL on an error. This handle can
199 * be passed to ClockP_start()
200 */
201 extern ClockP_Handle ClockP_create(ClockP_Fxn clockFxn,
202 uint32_t timeout,
203 ClockP_Params *params);
204
205 /*!
206 * @brief Function to delete a clock.
207 *
208 * @param handle A ClockP_Handle returned from ::ClockP_create
209 */
210 extern void ClockP_delete(ClockP_Handle handle);
211
212 /*!
213 * @brief Get CPU frequency in Hz
214 *
215 * @param freq Pointer to the FreqHz structure
216 */
217 extern void ClockP_getCpuFreq(ClockP_FreqHz *freq);
218
219 /*!
220 * @brief Get the system tick frequency in Hz (ticks per second).
221 *
222 * @note This is a Zephyr specific addition to TI's original clock API to
223 * support precision timing.
224 *
225 * @return The kernel's system tick frequency in Hz.
226 */
227 extern uint32_t ClockP_getSystemTickFreq();
228
229 /*!
230 * @brief Convert system ticks to milliseconds (rounded).
231 *
232 * @note This is a Zephyr specific addition to TI's original clock API to
233 * support precision timing.
234 *
235 * @return Ticks converted to milliseconds and rounded to the closest integer
236 * value. If the value cannot be represented with 32 bits, ~0 is returned.
237 */
ClockP_convertSystemTicksToMsRound(uint32_t ticks)238 static inline uint32_t ClockP_convertSystemTicksToMsRound(uint32_t ticks)
239 {
240 uint64_t ms = CLOCKP_DIV_ROUND((uint64_t)ticks * MS_PER_S, ClockP_getSystemTickFreq());
241
242 if(unlikely(ms > (uint32_t)ms))
243 {
244 return UINT32_MAX;
245 }
246
247 return ms;
248 }
249
250 /*!
251 * @brief Convert milliseconds to system ticks (rounded).
252 *
253 * @note This is a Zephyr specific addition to TI's original clock API to
254 * support precision timing.
255 *
256 * @return Milliseconds converted to ticks and rounded to the closest integer
257 * value. If the value cannot be represented with 32 bits, ~0 is returned.
258 */
ClockP_convertMsToSystemTicksRound(uint32_t ms)259 static inline uint32_t ClockP_convertMsToSystemTicksRound(uint32_t ms)
260 {
261 uint64_t ticks;
262
263 if(ms == 0)
264 {
265 return 0;
266 }
267
268 ticks = CLOCKP_DIV_ROUND_UP((uint64_t)ms * ClockP_getSystemTickFreq(), MS_PER_S);
269
270 if (unlikely(ticks > (uint32_t)ticks))
271 {
272 return UINT32_MAX;
273 }
274
275 return ticks;
276 }
277
278 /*!
279 * @brief Convert system ticks to microseconds (rounded).
280 *
281 * @note This is a Zephyr specific addition to TI's original clock API to
282 * support precision timing.
283 *
284 * @return Ticks converted to microseconds and rounded to the closest integer
285 * value. If the value cannot be represented with 32 bits, ~0 is returned.
286 */
ClockP_convertSystemTicksToUsRound(uint32_t ticks)287 static inline uint32_t ClockP_convertSystemTicksToUsRound(uint32_t ticks)
288 {
289 uint64_t us = CLOCKP_DIV_ROUND((uint64_t)ticks * US_PER_S, ClockP_getSystemTickFreq());
290
291 if(unlikely(us > (uint32_t)us))
292 {
293 return UINT32_MAX;
294 }
295
296 return us;
297 }
298
299 /*!
300 * @brief Convert microseconds to system ticks (rounded down).
301 *
302 * @note This is a Zephyr specific addition to TI's original clock API to
303 * support precision timing.
304 *
305 * @return Microseconds converted to ticks and rounded down. If the value
306 * cannot be represented with 32 bits, ~0 is returned.
307 */
ClockP_convertUsToSystemTicksFloor(uint32_t us)308 static inline uint32_t ClockP_convertUsToSystemTicksFloor(uint32_t us)
309 {
310 uint64_t ticks;
311
312 if(us == 0)
313 {
314 return 0;
315 }
316
317 ticks = ((uint64_t)us * ClockP_getSystemTickFreq()) / US_PER_S;
318
319 if (unlikely(ticks > (uint32_t)ticks))
320 {
321 return UINT32_MAX;
322 }
323
324 return ticks;
325 }
326
327 /*!
328 * @brief Convert microseconds to system ticks (rounded up).
329 *
330 * @note This is a Zephyr specific addition to TI's original clock API to
331 * support precision timing.
332 *
333 * @return Microseconds converted to ticks and rounded up. If the value cannot
334 * be represented with 32 bits, ~0 is returned.
335 */
ClockP_convertUsToSystemTicksCeil(uint32_t us)336 static inline uint32_t ClockP_convertUsToSystemTicksCeil(uint32_t us)
337 {
338 uint64_t ticks;
339
340 if(us == 0)
341 {
342 return 0;
343 }
344
345 ticks = CLOCKP_DIV_ROUND_UP((uint64_t)us * ClockP_getSystemTickFreq(), US_PER_S);
346
347 if (unlikely(ticks > (uint32_t)ticks))
348 {
349 return UINT32_MAX;
350 }
351
352 return ticks;
353 }
354
355 /*!
356 * @brief Convert microseconds to system ticks (rounded).
357 *
358 * @note This is a Zephyr specific addition to TI's original clock API to
359 * support precision timing.
360 *
361 * @return Microseconds converted to ticks and rounded to the closest integer.
362 * If the value cannot be represented with 32 bits, ~0 is returned.
363 */
ClockP_convertUsToSystemTicksRound(uint32_t us)364 static inline uint32_t ClockP_convertUsToSystemTicksRound(uint32_t us)
365 {
366 uint64_t ticks;
367
368 if(us == 0)
369 {
370 return 0;
371 }
372
373 ticks = CLOCKP_DIV_ROUND((uint64_t)us * ClockP_getSystemTickFreq(), US_PER_S);
374
375 if (unlikely(ticks > (uint32_t)ticks))
376 {
377 return UINT32_MAX;
378 }
379
380 return ticks;
381 }
382
383 /*!
384 * @brief Get the system tick period in microseconds.
385 *
386 * @warning This may be rounded down to the next matching integer which amounts
387 * to ~17250 ppm error if equal to the LF clock (32768 Hz). Use one of the
388 * from/to tick conversion helpers above if precise timing is needed.
389 *
390 * @return The kernel's system tick period in microseconds.
391 */
392 extern uint32_t ClockP_getSystemTickPeriod();
393
394 /*!
395 * @brief Get the current tick value
396 *
397 * The value returned will wrap back to zero after it reaches the max
398 * value that can be stored in 32 bits.
399 *
400 * @return Time in system clock ticks
401 */
402 extern uint32_t ClockP_getSystemTicks();
403
404 /*!
405 * @brief Get number of ClockP tick periods expected to expire between
406 * now and the next interrupt from the timer peripheral
407 *
408 * Returns the number of ClockP tick periods that are expected to expore
409 * between now and the next interrupt from the timer peripheral.
410 *
411 * Used internally by PowerCC26XX module
412 *
413 * @return count in ticks
414 */
415 extern uint32_t ClockP_getTicksUntilInterrupt();
416
417 /*!
418 * @brief Get timeout of clock instance.
419 *
420 * Returns the remaining time in clock ticks if the instance has
421 * been started. If the clock is not active, the initial timeout value
422 * is returned.
423 *
424 * @return remaining timeout in clock ticks.
425 *
426 * Cannot change the initial timeout if the clock has been started.
427 */
428 extern uint32_t ClockP_getTimeout(ClockP_Handle handle);
429
430 /*!
431 * @brief Determine if a clock object is currently active (i.e., running)
432 *
433 * Returns true if the clock object is currently active, otherwise
434 * returns false.
435 *
436 * @return active state
437 */
438 extern bool ClockP_isActive(ClockP_Handle handle);
439
440 /*!
441 * @brief Initialize params structure to default values.
442 *
443 * The default parameters are:
444 * - name: NULL
445 * - arg: 0
446 *
447 * @param params Pointer to the instance configuration parameters.
448 */
449 extern void ClockP_Params_init(ClockP_Params *params);
450
451 /*!
452 * @brief Set the initial timeout
453 *
454 * @param timeout Initial timeout in ClockP ticks
455 *
456 * Cannot change the initial timeout if the clock has been started.
457 */
458 extern void ClockP_setTimeout(ClockP_Handle handle, uint32_t timeout);
459
460 /*!
461 * @brief Function to start a clock.
462 *
463 * @param handle A ClockP_Handle returned from ::ClockP_create
464 */
465 extern void ClockP_start(ClockP_Handle handle);
466
467 /*!
468 * @brief Function to stop a clock.
469 *
470 * @param handle A ClockP_Handle returned from ::ClockP_create
471 *
472 * It is ok to call ClockP_stop() for a clock that has not been started.
473 *
474 * @return Status of the functions
475 * - ClockP_OK: Stopped the clock function successfully
476 * - ClockP_FAILURE: The API failed.
477 */
478 extern void ClockP_stop(ClockP_Handle handle);
479
480 extern void ClockP_timestamp(ClockP_Handle handle);
481
482 /*!
483 * @brief Set delay in microseconds
484 *
485 * @param usec A duration in micro seconds
486 *
487 * @return ClockP_OK
488 */
489 extern void ClockP_usleep(uint32_t usec);
490
491 /*!
492 * @brief Set delay in seconds
493 *
494 * @param sec A duration in seconds
495 *
496 * @return ClockP_OK
497 */
498 extern void ClockP_sleep(uint32_t sec);
499
500
501 #ifdef __cplusplus
502 }
503 #endif
504
505 #endif /* ti_dpl_ClockP__include */
506