From b0612300567e250d5efbd385b9e4a059cfc60442 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 16 Aug 2019 19:20:06 +0800 Subject: [PATCH] feat(esp8266): refactor CCOMPARE timer and system time by microseconds old: CCOMPARE timer triggers when CCOUNT increase to equal to CCOMPARE, then ISR will increase integer of "_xt_tick_divisor" to CCOMPARE and wait for next interrupt triggering now: CCOMPARE timer triggers when CCOUNT increase to equal to CCOMPARE, then ISR will reset CCOUNT to be 0 and reset CCOMPARE to be integer of "_xt_tick_divisor", then wait for next interrupt triggering Using the new method, we may get the CCOUNT value without considing if it has overflowed. System running microseconds = g_os_ticks * microseconds per tick + CCOUNT. --- components/esp8266/include/driver/soc.h | 24 ++++----- .../esp8266/include/esp8266/eagle_soc.h | 12 +++++ components/esp8266/source/esp_timer.c | 23 +-------- components/freertos/freertos/tasks.c | 2 +- .../esp8266/include/freertos/FreeRTOSConfig.h | 5 +- components/freertos/port/esp8266/port.c | 51 ++++++++++++++----- components/log/log.c | 29 ++++++----- 7 files changed, 85 insertions(+), 61 deletions(-) diff --git a/components/esp8266/include/driver/soc.h b/components/esp8266/include/driver/soc.h index d2a7c3f1..c319b0f7 100644 --- a/components/esp8266/include/driver/soc.h +++ b/components/esp8266/include/driver/soc.h @@ -26,20 +26,6 @@ extern "C" { 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; @@ -102,6 +88,16 @@ static inline uint32_t soc_get_ccount(void) return ticks; } +static inline void soc_set_ccount(uint32_t ticks) +{ + __asm__ __volatile__( + "wsr %0, ccount\n" + : + : "a"(ticks) + : "memory" + ); +} + static inline void soc_clear_int_mask(uint32_t mask) { __asm__ __volatile__( diff --git a/components/esp8266/include/esp8266/eagle_soc.h b/components/esp8266/include/esp8266/eagle_soc.h index 0a83c636..1c2d2ac9 100644 --- a/components/esp8266/include/esp8266/eagle_soc.h +++ b/components/esp8266/include/esp8266/eagle_soc.h @@ -94,6 +94,18 @@ #define APB_CLK_FREQ CPU_CLK_FREQ #define UART_CLK_FREQ APB_CLK_FREQ #define TIMER_CLK_FREQ (APB_CLK_FREQ >> 8) // divided by 256 + +#define FREQ_1MHZ (1000 * 1000) +#define FREQ_1KHZ (1000) + +#define CPU_FREQ_160MHZ (160 * 1000 * 1000) +#define CPU_FREQ_80MHz (80 * 1000 * 1000) + +#define CPU_160M_TICKS_PRT_MS (CPU_FREQ_160MHZ / FREQ_1MHZ) +#define CPU_80M_TICKS_PRT_MS (CPU_FREQ_80MHz / FREQ_1KHZ) + +#define CPU_160M_TICKS_PRT_US (CPU_FREQ_160MHZ / FREQ_1MHZ) +#define CPU_80M_TICKS_PRT_US (CPU_FREQ_80MHz / FREQ_1MHZ) //}} //Peripheral device base address define{{ diff --git a/components/esp8266/source/esp_timer.c b/components/esp8266/source/esp_timer.c index 9caa0fab..645f9379 100644 --- a/components/esp8266/source/esp_timer.c +++ b/components/esp8266/source/esp_timer.c @@ -202,26 +202,7 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) int64_t esp_timer_get_time() { - extern esp_tick_t g_cpu_ticks; - extern uint64_t g_os_ticks; + extern uint64_t g_esp_os_us; - 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; + return (int64_t)g_esp_os_us; } diff --git a/components/freertos/freertos/tasks.c b/components/freertos/freertos/tasks.c index 68cd1539..28d5f406 100644 --- a/components/freertos/freertos/tasks.c +++ b/components/freertos/freertos/tasks.c @@ -2522,7 +2522,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than 1. */ #if ( configUSE_TICKLESS_IDLE != 0 ) - void vTaskStepTick( const TickType_t xTicksToJump ) + void IRAM_ATTR vTaskStepTick( const TickType_t xTicksToJump ) { /* Correct the tick count value after a period during which the tick was suppressed. Note this does *not* call the tick hook function for diff --git a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h index a971d282..47d48c5a 100644 --- a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h @@ -158,8 +158,11 @@ NVIC value of 255. */ #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() #ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK +#ifndef __ASSEMBLER__ +extern uint64_t g_esp_os_cpu_clk; +#define portGET_RUN_TIME_COUNTER_VALUE() g_esp_os_cpu_clk +#endif /* Fine resolution time */ -#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount() #elif defined(CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER) /* Coarse resolution time (us) */ #ifndef __ASSEMBLER__ diff --git a/components/freertos/port/esp8266/port.c b/components/freertos/port/esp8266/port.c index b0c314d3..f82347cc 100644 --- a/components/freertos/port/esp8266/port.c +++ b/components/freertos/port/esp8266/port.c @@ -63,8 +63,10 @@ int __g_is_task_overflow; variable. */ static uint32_t uxCriticalNesting = 0; -esp_tick_t g_cpu_ticks = 0; -uint64_t g_os_ticks = 0; +uint32_t g_esp_boot_ccount; +uint64_t g_esp_os_ticks; +uint64_t g_esp_os_us; +uint64_t g_esp_os_cpu_clk; void vPortEnterCritical(void); void vPortExitCritical(void); @@ -134,20 +136,46 @@ void esp_increase_tick_cnt(const TickType_t ticks) flag = soc_save_local_irq(); - g_cpu_ticks = soc_get_ticks(); - g_os_ticks += ticks; + g_esp_os_ticks += ticks; soc_restore_local_irq(flag); } -void TASK_SW_ATTR xPortSysTickHandle(void *p) +void IRAM_ATTR xPortSysTickHandle(void *p) { - const uint32_t cpu_clk_cnt = soc_get_ccount() + _xt_tick_divisor; + uint32_t us; + uint32_t ticks; + uint32_t ccount; - soc_set_ccompare(cpu_clk_cnt); + /** + * System or application may close interrupt too long, such as the operation of read/write/erase flash. + * And then the "ccount" value may be overflow. + * + * So add code here to calibrate system time. + */ + if (_xt_tick_divisor == (CPU_FREQ_80MHz / XT_TICK_PER_SEC)) { + ccount = soc_get_ccount(); + us = ccount / CPU_80M_TICKS_PRT_US; + } else { + ccount = soc_get_ccount(); + us = ccount / CPU_160M_TICKS_PRT_US; + } + g_esp_os_us += us; + g_esp_os_cpu_clk += ccount; - g_cpu_ticks = soc_get_ticks(); - g_os_ticks++; + soc_set_ccount(0); + soc_set_ccompare(_xt_tick_divisor); + + ticks = us / 1000 / portTICK_PERIOD_MS; + if (!ticks) { + ets_printf("\r\nERROR: CCOMPARE timer period"); + ticks = 1; + } + + g_esp_os_ticks += ticks; + if (ticks > 1) { + vTaskStepTick(ticks - 1); + } if (xTaskIncrementTick() != pdFALSE) { vTaskSwitchContext(); @@ -186,13 +214,12 @@ portBASE_TYPE xPortStartScheduler(void) /* Initialize system tick timer interrupt and schedule the first tick. */ _xt_tick_divisor = xtbsp_clock_freq_hz() / XT_TICK_PER_SEC; + g_esp_boot_ccount = soc_get_ccount(); + soc_set_ccount(0); _xt_tick_timer_init(); 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/log/log.c b/components/log/log.c index 1b52d487..13599c7f 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -29,6 +29,10 @@ #include "esp_log.h" #include "esp_system.h" +#ifndef BOOTLOADER_BUILD +#include "FreeRTOS.h" +#endif + #ifdef CONFIG_LOG_COLORS #define LOG_COLOR_HEAD "\033[0;%dm" #define LOG_BOLD_HEAD "\033[1;%dm" @@ -55,7 +59,18 @@ static const char s_log_prefix[ESP_LOG_MAX] = { uint32_t IRAM_ATTR esp_log_early_timestamp() { - return xthal_get_ccount() / ((CRYSTAL_USED * 2) * 1000); +#ifndef BOOTLOADER_BUILD + extern uint64_t g_esp_os_us; + extern uint64_t g_esp_boot_ccount; + + const uint32_t ticks_per_ms = _xt_tick_divisor * configTICK_RATE_HZ / 1000; + const uint32_t ms = g_esp_os_us / 1000 + g_esp_boot_ccount / ((CRYSTAL_USED * 2) * 1000); +#else + const uint32_t ticks_per_ms = ((CRYSTAL_USED * 2) * 1000); + const uint32_t ms = 0; +#endif + + return soc_get_ccount() / ticks_per_ms + ms; } #ifndef BOOTLOADER_BUILD @@ -190,16 +205,6 @@ static int esp_log_write_str(const char *s) return ret; } -uint32_t esp_log_timestamp() -{ - static uint32_t base = 0; - - if (base == 0) { - base = esp_log_early_timestamp(); - } - - return base + clock() * (1000 / CLOCKS_PER_SEC); -} #endif /** @@ -262,7 +267,7 @@ void esp_log_write(esp_log_level_t level, const char *tag, const char *fmt, ... } #endif prefix = level >= ESP_LOG_MAX ? 'N' : s_log_prefix[level]; - ret = asprintf(&pbuf, "%c (%d) %s: ", prefix, esp_log_timestamp(), tag); + ret = asprintf(&pbuf, "%c (%d) %s: ", prefix, esp_log_early_timestamp(), tag); if (ret < 0) goto out; ret = esp_log_write_str(pbuf);