1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <stdint.h> 16 #include "freertos/portmacro.h" 17 #include "esp_freertos_hooks.h" 18 #include "soc/soc_caps.h" 19 #include "hal/cpu_hal.h" 20 #include "esp_rom_sys.h" 21 22 #if CONFIG_IDF_TARGET_ESP32C3 23 #include "esp32c3/clk.h" 24 #elif CONFIG_IDF_TARGET_ESP32H2 25 #include "esp32h2/clk.h" 26 #endif 27 28 typedef enum { 29 PERF_TIMER_UNINIT = 0, // timer has not been initialized yet 30 PERF_TIMER_IDLE, // timer has been initialized but is not tracking elapsed time 31 PERF_TIMER_ACTIVE // timer is tracking elapsed time 32 } ccomp_timer_state_t; 33 34 typedef struct { 35 uint32_t last_ccount; // last CCOUNT value, updated every os tick 36 ccomp_timer_state_t state; // state of the timer 37 int64_t ccount; // accumulated processors cycles during the time when timer is active 38 } ccomp_timer_status_t; 39 40 // Each core has its independent timer 41 ccomp_timer_status_t s_status[SOC_CPU_CORES_NUM]; 42 43 static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED; 44 update_ccount(void)45static void IRAM_ATTR update_ccount(void) 46 { 47 if (s_status[cpu_hal_get_core_id()].state == PERF_TIMER_ACTIVE) { 48 int64_t new_ccount = cpu_hal_get_cycle_count(); 49 if (new_ccount > s_status[cpu_hal_get_core_id()].last_ccount) { 50 s_status[cpu_hal_get_core_id()].ccount += new_ccount - s_status[cpu_hal_get_core_id()].last_ccount; 51 } else { 52 // CCOUNT has wrapped around 53 s_status[cpu_hal_get_core_id()].ccount += new_ccount + (UINT32_MAX - s_status[cpu_hal_get_core_id()].last_ccount); 54 } 55 s_status[cpu_hal_get_core_id()].last_ccount = new_ccount; 56 } 57 } 58 ccomp_timer_impl_init(void)59esp_err_t ccomp_timer_impl_init(void) 60 { 61 s_status[cpu_hal_get_core_id()].state = PERF_TIMER_IDLE; 62 return ESP_OK; 63 } 64 ccomp_timer_impl_deinit(void)65esp_err_t ccomp_timer_impl_deinit(void) 66 { 67 s_status[cpu_hal_get_core_id()].state = PERF_TIMER_UNINIT; 68 return ESP_OK; 69 } 70 ccomp_timer_impl_start(void)71esp_err_t ccomp_timer_impl_start(void) 72 { 73 s_status[cpu_hal_get_core_id()].state = PERF_TIMER_ACTIVE; 74 s_status[cpu_hal_get_core_id()].last_ccount = cpu_hal_get_cycle_count(); 75 // Update elapsed cycles every OS tick 76 esp_register_freertos_tick_hook_for_cpu(update_ccount, cpu_hal_get_core_id()); 77 return ESP_OK; 78 } 79 ccomp_timer_impl_stop(void)80esp_err_t IRAM_ATTR ccomp_timer_impl_stop(void) 81 { 82 esp_deregister_freertos_tick_hook_for_cpu(update_ccount, cpu_hal_get_core_id()); 83 update_ccount(); 84 s_status[cpu_hal_get_core_id()].state = PERF_TIMER_IDLE; 85 return ESP_OK; 86 } 87 ccomp_timer_impl_get_time(void)88int64_t IRAM_ATTR ccomp_timer_impl_get_time(void) 89 { 90 update_ccount(); 91 int64_t cycles = s_status[cpu_hal_get_core_id()].ccount; 92 return (cycles * 1000000) / esp_clk_cpu_freq(); 93 } 94 ccomp_timer_impl_reset(void)95esp_err_t ccomp_timer_impl_reset(void) 96 { 97 s_status[cpu_hal_get_core_id()].ccount = 0; 98 s_status[cpu_hal_get_core_id()].last_ccount = 0; 99 return ESP_OK; 100 } 101 ccomp_timer_impl_is_init(void)102bool ccomp_timer_impl_is_init(void) 103 { 104 return s_status[cpu_hal_get_core_id()].state != PERF_TIMER_UNINIT; 105 } 106 ccomp_timer_impl_is_active(void)107bool IRAM_ATTR ccomp_timer_impl_is_active(void) 108 { 109 return s_status[cpu_hal_get_core_id()].state == PERF_TIMER_ACTIVE; 110 } 111 ccomp_timer_impl_lock(void)112void IRAM_ATTR ccomp_timer_impl_lock(void) 113 { 114 portENTER_CRITICAL(&s_lock); 115 } 116 ccomp_timer_impl_unlock(void)117void IRAM_ATTR ccomp_timer_impl_unlock(void) 118 { 119 portEXIT_CRITICAL(&s_lock); 120 } 121