From 7fbb68f4eaf0d0b611f0bd0f9908eb3745366bc7 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 7 Mar 2019 16:06:15 +0800 Subject: [PATCH] feat(esp8266): Add API to get microseconds --- components/esp8266/include/driver/soc.h | 68 ++++++++++++++++ components/esp8266/include/esp_timer.h | 7 ++ components/esp8266/source/esp_timer.c | 27 +++++++ .../esp8266/include/freertos/FreeRTOSConfig.h | 2 + .../port/esp8266/include/freertos/portmacro.h | 2 + components/freertos/port/esp8266/port.c | 22 +++++ components/newlib/newlib/port/time.c | 81 +++---------------- 7 files changed, 139 insertions(+), 70 deletions(-) create mode 100644 components/esp8266/include/driver/soc.h diff --git a/components/esp8266/include/driver/soc.h b/components/esp8266/include/driver/soc.h new file mode 100644 index 00000000..10d9b88b --- /dev/null +++ b/components/esp8266/include/driver/soc.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_TICKS_MAX UINT32_MAX + +typedef uint32_t esp_tick_t; +typedef uint32_t esp_irqflag_t; + +static inline esp_tick_t soc_get_ticks(void) +{ + esp_tick_t ticks; + + __asm__ __volatile__( + "rsr %0, ccount\n" + : "=a"(ticks) + : + : "memory" + ); + + return ticks; +} + +static inline esp_irqflag_t soc_save_local_irq(void) +{ + esp_irqflag_t flag; + + __asm__ __volatile__( + "rsil %0, 1\n" + : "=a"(flag) + : + : "memory" + ); + + return flag; +} + +static inline void soc_restore_local_irq(esp_irqflag_t flag) +{ + __asm__ __volatile__( + "wsr %0, ps\n" + : + : "a"(flag) + : "memory" + ); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp8266/include/esp_timer.h b/components/esp8266/include/esp_timer.h index c6b606c0..5e1d01af 100644 --- a/components/esp8266/include/esp_timer.h +++ b/components/esp8266/include/esp_timer.h @@ -187,6 +187,13 @@ esp_err_t esp_timer_stop(esp_timer_handle_t timer); */ esp_err_t esp_timer_delete(esp_timer_handle_t timer); +/** + * @brief Get time in microseconds since RTOS starts + * @return number of microseconds since RTOS starts starts (this normally + * happens much early during application startup). + */ +int64_t esp_timer_get_time(); + #ifdef __cplusplus } #endif diff --git a/components/esp8266/source/esp_timer.c b/components/esp8266/source/esp_timer.c index a2e1ccc2..9caa0fab 100644 --- a/components/esp8266/source/esp_timer.c +++ b/components/esp8266/source/esp_timer.c @@ -18,6 +18,7 @@ #include "FreeRTOS.h" #include "freertos/task.h" #include "freertos/timers.h" +#include "driver/soc.h" #define ESP_TIMER_HZ CONFIG_FREERTOS_HZ @@ -198,3 +199,29 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) return os_ret == pdPASS ? ESP_OK : ESP_ERR_INVALID_STATE; } + +int64_t esp_timer_get_time() +{ + extern esp_tick_t g_cpu_ticks; + extern uint64_t g_os_ticks; + + esp_irqflag_t flag; + esp_tick_t diff_ticks, ticks; + uint64_t time; + + flag = soc_save_local_irq(); + + time = g_os_ticks * portTICK_PERIOD_MS * 1000; + ticks = soc_get_ticks(); + if (ticks >= g_cpu_ticks) { + diff_ticks = ticks - g_cpu_ticks; + } else { + diff_ticks = ESP_TICKS_MAX - g_cpu_ticks + ticks; + } + + time += diff_ticks / (_xt_tick_divisor * configTICK_RATE_HZ / (1000 * 1000)); + + soc_restore_local_irq(flag); + + return (int64_t)time; +} diff --git a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h index 25f5e585..09a542be 100644 --- a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h @@ -164,5 +164,7 @@ uint32_t esp_get_time(void); #endif /* CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS */ +#define traceINCREASE_TICK_COUNT(_ticks) esp_increase_tick_cnt(_ticks) + #endif /* FREERTOS_CONFIG_H */ diff --git a/components/freertos/port/esp8266/include/freertos/portmacro.h b/components/freertos/port/esp8266/include/freertos/portmacro.h index 709c7771..31fbdc36 100644 --- a/components/freertos/port/esp8266/include/freertos/portmacro.h +++ b/components/freertos/port/esp8266/include/freertos/portmacro.h @@ -201,6 +201,8 @@ uint32_t xPortGetTickRateHz(void); void _xt_enter_first_task(void); +void esp_increase_tick_cnt(const TickType_t ticks); + /* API compatible with esp-idf */ #define xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, tskNO_AFFINITY) \ xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask) diff --git a/components/freertos/port/esp8266/port.c b/components/freertos/port/esp8266/port.c index 3b7ad057..acccca2d 100644 --- a/components/freertos/port/esp8266/port.c +++ b/components/freertos/port/esp8266/port.c @@ -45,6 +45,7 @@ #include "esp8266/eagle_soc.h" #include "rom/ets_sys.h" #include "esp8266/rom_functions.h" +#include "driver/soc.h" #define PORT_ASSERT(x) do { if (!(x)) {ets_printf("%s %u\n", "rtos_port", __LINE__); while(1){}; }} while (0) @@ -58,6 +59,9 @@ unsigned cpu_sr; variable. */ static uint32_t uxCriticalNesting = 0; +esp_tick_t g_cpu_ticks = 0; +uint64_t g_os_ticks = 0; + void vPortEnterCritical(void); void vPortExitCritical(void); @@ -137,8 +141,23 @@ void TASK_SW_ATTR SoftIsrHdl(void* arg) ETS_NMI_UNLOCK(); } +void esp_increase_tick_cnt(const TickType_t ticks) +{ + esp_irqflag_t flag; + + flag = soc_save_local_irq(); + + g_cpu_ticks = soc_get_ticks(); + g_os_ticks += ticks; + + soc_restore_local_irq(flag); +} + void TASK_SW_ATTR xPortSysTickHandle(void) { + g_cpu_ticks = soc_get_ticks(); + g_os_ticks++; + if (xTaskIncrementTick() != pdFALSE) { vTaskSwitchContext(); } @@ -169,6 +188,9 @@ portBASE_TYPE xPortStartScheduler(void) vTaskSwitchContext(); + /* Get ticks before RTOS starts */ + g_cpu_ticks = soc_get_ticks(); + /* Restore the context of the first task that is going to run. */ _xt_enter_first_task(); diff --git a/components/newlib/newlib/port/time.c b/components/newlib/newlib/port/time.c index 59684d09..075b168e 100644 --- a/components/newlib/newlib/port/time.c +++ b/components/newlib/newlib/port/time.c @@ -23,94 +23,37 @@ #include "FreeRTOS.h" #include "task.h" - -extern uint32_t esp_get_time(); +#include "driver/soc.h" static uint64_t s_boot_time; -static os_timer_t microsecond_overflow_timer; -static uint32_t microsecond_last_overflow_tick; -static uint32_t microsecond_overflow_count; - -static bool microsecond_overflow_timer_start_flag = false; - -static void microsecond_overflow_tick(void* arg) +static inline void set_boot_time(uint64_t time_us) { - uint32_t m = esp_get_time(); - - vPortEnterCritical(); - - if (m < microsecond_last_overflow_tick) { - microsecond_overflow_count ++; - } - - microsecond_last_overflow_tick = m; - - vPortExitCritical(); -} - -/* Start a timer which period is 60s to check the overflow of microsecond. */ -static void microsecond_overflow_set_check_timer(void) -{ - if (microsecond_overflow_timer_start_flag == false) { - os_timer_disarm(µsecond_overflow_timer); - os_timer_setfn(µsecond_overflow_timer, (os_timer_func_t*)microsecond_overflow_tick, 0); - os_timer_arm(µsecond_overflow_timer, 60 * 1000, 1); - - microsecond_overflow_timer_start_flag = true; - } -} - -static void set_boot_time(uint64_t time_us) -{ - vPortEnterCritical(); + esp_irqflag_t flag; + flag = soc_save_local_irq(); s_boot_time = time_us; - - vPortExitCritical(); + soc_restore_local_irq(flag); } -static uint64_t get_boot_time() +static inline uint64_t get_boot_time() { uint64_t result; + esp_irqflag_t flag; - vPortEnterCritical(); - + flag = soc_save_local_irq(); result = s_boot_time; - - vPortExitCritical(); + soc_restore_local_irq(flag); return result; } -static uint64_t get_time_since_boot() -{ - uint32_t m; - uint32_t c; - uint64_t microseconds; - - m = esp_get_time(); - - vPortEnterCritical(); - - c = microsecond_overflow_count + ((m < microsecond_last_overflow_tick) ? 1 : 0); - - vPortExitCritical(); - - microseconds = c * (1LL << 32) + m; - - return microseconds; -} - int _gettimeofday_r(struct _reent* r, struct timeval* tv, void* tz) { (void) tz; - /* ToDo: This can be moved to system start up. */ - microsecond_overflow_set_check_timer(); - if (tv) { - uint64_t microseconds = get_boot_time() + get_time_since_boot(); + uint64_t microseconds = get_boot_time() + (uint64_t)esp_timer_get_time(); tv->tv_sec = microseconds / 1000000; tv->tv_usec = microseconds % 1000000; } @@ -122,11 +65,9 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) { (void) tz; - microsecond_overflow_set_check_timer(); - if (tv) { uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec; - uint64_t since_boot = get_time_since_boot(); + uint64_t since_boot = (uint64_t)esp_timer_get_time(); set_boot_time(now - since_boot); }