1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 /** 21 * @addtogroup OSKernel 22 * @{ 23 * @defgroup OSCPUTime High Resolution Timers 24 * @{ 25 */ 26 27 #ifndef H_OS_CPUTIME_ 28 #define H_OS_CPUTIME_ 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #include "syscfg/syscfg.h" 35 #include "hal/hal_timer.h" 36 #include "os/os.h" 37 38 /* 39 * NOTE: these definitions allow one to override the cputime frequency used. 40 * The reason these definitions exist is to make the code more 41 * efficient/smaller when CPUTIME counts at 1 MHz. 42 * 43 * For those who want a different cputime frequency, you can set the config 44 * definition for OS_CPUTIME_FREQ to the desired frequency in your project, 45 * target or bsp. 46 */ 47 #if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 1000000) 48 49 #define OS_CPUTIME_FREQ_1MHZ 50 51 #elif MYNEWT_VAL(OS_CPUTIME_FREQ) == 256 || \ 52 MYNEWT_VAL(OS_CPUTIME_FREQ) == 512 || \ 53 MYNEWT_VAL(OS_CPUTIME_FREQ) == 1024 || \ 54 MYNEWT_VAL(OS_CPUTIME_FREQ) == 2048 || \ 55 MYNEWT_VAL(OS_CPUTIME_FREQ) == 4096 || \ 56 MYNEWT_VAL(OS_CPUTIME_FREQ) == 8192 || \ 57 MYNEWT_VAL(OS_CPUTIME_FREQ) == 16384 || \ 58 MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 || \ 59 MYNEWT_VAL(OS_CPUTIME_FREQ) == 65536 || \ 60 MYNEWT_VAL(OS_CPUTIME_FREQ) == 131072 || \ 61 MYNEWT_VAL(OS_CPUTIME_FREQ) == 262144 || \ 62 MYNEWT_VAL(OS_CPUTIME_FREQ) == 524288 63 64 #define OS_CPUTIME_FREQ_PWR2 65 66 #elif MYNEWT_VAL(OS_CPUTIME_FREQ) > 1000000 67 68 #define OS_CPUTIME_FREQ_HIGH 69 70 #else 71 72 #error "Invalid OS_CPUTIME_FREQ value. Value must be one of a) a power of 2" \ 73 ">= 256Hz, or b) any value >= 1MHz" 74 75 #endif 76 77 #if defined(OS_CPUTIME_FREQ_HIGH) 78 /* CPUTIME data. */ 79 struct os_cputime_data 80 { 81 uint32_t ticks_per_usec; /* number of ticks per usec */ 82 }; 83 extern struct os_cputime_data g_os_cputime; 84 #endif 85 86 /* Helpful macros to compare cputimes */ 87 /** evaluates to true if t1 is before t2 in time */ 88 #define CPUTIME_LT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) < 0) 89 /** evaluates to true if t1 is after t2 in time */ 90 #define CPUTIME_GT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) > 0) 91 /** evaluates to true if t1 is after t2 in time */ 92 #define CPUTIME_GEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) >= 0) 93 /** evaluates to true if t1 is on or after t2 in time */ 94 #define CPUTIME_LEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) <= 0) 95 96 /** 97 * Initialize the cputime module. This must be called after os_init is called 98 * and before any other timer API are used. This should be called only once 99 * and should be called before the hardware timer is used. 100 * 101 * @param clock_freq The desired cputime frequency, in hertz (Hz). 102 * 103 * @return int 0 on success; -1 on error. 104 */ 105 int os_cputime_init(uint32_t clock_freq); 106 107 /** 108 * Returns the low 32 bits of cputime. 109 * 110 * @return uint32_t The lower 32 bits of cputime 111 */ 112 uint32_t os_cputime_get32(void); 113 114 #if !defined(OS_CPUTIME_FREQ_PWR2) 115 /** 116 * Converts the given number of nanoseconds into cputime ticks. 117 * Not defined if OS_CPUTIME_FREQ_PWR2 is defined. 118 * 119 * @param usecs The number of nanoseconds to convert to ticks 120 * 121 * @return uint32_t The number of ticks corresponding to 'nsecs' 122 */ 123 uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs); 124 125 /** 126 * Convert the given number of ticks into nanoseconds. 127 * Not defined if OS_CPUTIME_FREQ_PWR2 is defined. 128 * 129 * @param ticks The number of ticks to convert to nanoseconds. 130 * 131 * @return uint32_t The number of nanoseconds corresponding to 'ticks' 132 */ 133 uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks); 134 135 /** 136 * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. 137 * Not defined if OS_CPUTIME_FREQ_PWR2 is defined. 138 * 139 * 140 * @param nsecs The number of nanoseconds to wait. 141 */ 142 void os_cputime_delay_nsecs(uint32_t nsecs); 143 #endif 144 145 #if defined(OS_CPUTIME_FREQ_1MHZ) 146 #define os_cputime_usecs_to_ticks(x) (x) 147 #define os_cputime_ticks_to_usecs(x) (x) 148 #else 149 150 /** 151 * Converts the given number of microseconds into cputime ticks. 152 * 153 * @param usecs The number of microseconds to convert to ticks 154 * 155 * @return uint32_t The number of ticks corresponding to 'usecs' 156 */ 157 uint32_t os_cputime_usecs_to_ticks(uint32_t usecs); 158 159 /** 160 * Convert the given number of ticks into microseconds. 161 * 162 * @param ticks The number of ticks to convert to microseconds. 163 * 164 * @return uint32_t The number of microseconds corresponding to 'ticks' 165 */ 166 uint32_t os_cputime_ticks_to_usecs(uint32_t ticks); 167 #endif 168 169 /** 170 * Wait until the number of ticks has elapsed. This is a blocking delay. 171 * 172 * @param ticks The number of ticks to wait. 173 */ 174 void os_cputime_delay_ticks(uint32_t ticks); 175 176 /** 177 * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. 178 * 179 * @param usecs The number of usecs to wait. 180 */ 181 void os_cputime_delay_usecs(uint32_t usecs); 182 183 /** 184 * Initialize a CPU timer, using the given HAL timer. 185 * 186 * @param timer The timer to initialize. Cannot be NULL. 187 * @param fp The timer callback function. Cannot be NULL. 188 * @param arg Pointer to data object to pass to timer. 189 */ 190 void os_cputime_timer_init(struct hal_timer *timer, hal_timer_cb fp, 191 void *arg); 192 193 /** 194 * Start a cputimer that will expire at 'cputime'. If cputime has already 195 * passed, the timer callback will still be called (at interrupt context). 196 * 197 * NOTE: This must be called when the timer is stopped. 198 * 199 * @param timer Pointer to timer to start. Cannot be NULL. 200 * @param cputime The cputime at which the timer should expire. 201 * 202 * @return int 0 on success; EINVAL if timer already started or timer struct 203 * invalid 204 * 205 */ 206 int os_cputime_timer_start(struct hal_timer *timer, uint32_t cputime); 207 208 /** 209 * Sets a cpu timer that will expire 'usecs' microseconds from the current 210 * cputime. 211 * 212 * NOTE: This must be called when the timer is stopped. 213 * 214 * @param timer Pointer to timer. Cannot be NULL. 215 * @param usecs The number of usecs from now at which the timer will expire. 216 * 217 * @return int 0 on success; EINVAL if timer already started or timer struct 218 * invalid 219 */ 220 int os_cputime_timer_relative(struct hal_timer *timer, uint32_t usecs); 221 222 /** 223 * Stops a cputimer from running. The timer is removed from the timer queue 224 * and interrupts are disabled if no timers are left on the queue. Can be 225 * called even if timer is not running. 226 * 227 * @param timer Pointer to cputimer to stop. Cannot be NULL. 228 */ 229 void os_cputime_timer_stop(struct hal_timer *timer); 230 231 #ifdef __cplusplus 232 } 233 #endif 234 235 #endif /* H_OS_CPUTIME_ */ 236 237 /** 238 * @} OSCPUTime 239 * @} OSKernel 240 */ 241