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