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