diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index b7991075d09c..5719dfda8925 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -49,6 +49,7 @@ INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/$(CPU) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include/$(CPU) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/include diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index a2fabfc1a0f4..ea6c55f81a97 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -504,18 +504,28 @@ typedef struct { * configured here. * @{ */ + #ifdef MODULE_ESP_HW_COUNTER -/** hardware ccount/ccompare registers are used for timer implementation */ +/** Hardware ccount/ccompare registers are used for timer implementation */ #define TIMER_NUMOF (2) #define TIMER_CHANNEL_NUMOF (1) #else -/** hardware timer modules are used for timer implementation (default) */ -#define TIMER_NUMOF (3) +/** + * @brief Hardware timer modules are used for timer implementation (default) + * + * Since one timer is used for the system time, there is one timer less than + * the total number of timers. + */ +#define TIMER_NUMOF (SOC_TIMER_GROUP_TOTAL_TIMERS - 1) #define TIMER_CHANNEL_NUMOF (1) #endif -/** Timer used for system time */ -#define TIMER_SYSTEM TIMERG0.hw_timer[0] +/** Timer group used for system time */ +#define TIMER_SYSTEM_GROUP TIMER_GROUP_0 +/** Index of the timer in the timer timer group used for system time */ +#define TIMER_SYSTEM_INDEX TIMER_0 +/** System time interrupt source */ +#define TIMER_SYSTEM_INT_SRC ETS_TG0_T0_LEVEL_INTR_SOURCE /** @} */ diff --git a/cpu/esp32/periph/rtt_hw_rtc.c b/cpu/esp32/periph/rtt_hw_rtc.c index 16bf5bcf1673..5694942b13cf 100644 --- a/cpu/esp32/periph/rtt_hw_rtc.c +++ b/cpu/esp32/periph/rtt_hw_rtc.c @@ -33,10 +33,16 @@ /* ESP-IDF headers */ #include "esp_attr.h" #include "esp_sleep.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" #include "rom/ets_sys.h" -#include "soc/dport_reg.h" +#include "soc/periph_defs.h" #include "soc/rtc_cntl_struct.h" + +#if __xtensa__ +#include "soc/dport_reg.h" #include "xtensa/xtensa_api.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -77,27 +83,34 @@ static void _rtc_poweron(void) intr_matrix_set(PRO_CPU_NUM, ETS_RTC_CORE_INTR_SOURCE, CPU_INUM_RTT); /* set interrupt handler and enable the CPU interrupt */ - xt_set_interrupt_handler(CPU_INUM_RTT, _rtc_isr, NULL); - xt_ints_on(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, _rtc_isr, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_RTT)); } static void _rtc_poweroff(void) { /* reset interrupt handler and disable the CPU interrupt */ - xt_ints_off(BIT(CPU_INUM_RTT)); - xt_set_interrupt_handler(CPU_INUM_RTT, NULL, NULL); + intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, NULL, NULL); } uint64_t _rtc_get_counter(void) { /* trigger timer register update */ RTCCNTL.time_update.update = 1; +#if defined(MCU_ESP32) /* wait until values in registers are valid */ while (!RTCCNTL.time_update.valid) { ets_delay_us(1); } /* read the time from 48-bit counter and return */ return (((uint64_t)RTCCNTL.time1.val) << 32) + RTCCNTL.time0; +#elif defined(MCU_ESP32C3) + /* read the time from 48-bit counter and return */ + return (((uint64_t)RTCCNTL.time_high0.val) << 32) + RTCCNTL.time_low0; +#else +#error "MCU implementation is missing" +#endif } static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) @@ -109,8 +122,9 @@ static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) /* use computed time difference directly to set the RTC counter alarm */ uint64_t rtc_alarm = (rtc_counter + rtt_diff) & RTT_HW_COUNTER_MAX; - DEBUG("%s alarm=%u rtt_diff=%u rtc_alarm=%llu @rtc=%llu\n", - __func__, alarm, rtt_diff, rtc_alarm, rtc_counter); + DEBUG("%s alarm=%" PRIu32 " rtt_diff=%" PRIu32 + " rtc_alarm=%" PRIu64 " @rtc=%" PRIu64 "\n", + __func__, alarm, rtt_diff, rtc_alarm, rtc_counter); /* save the alarm configuration for interrupt handling */ _rtc_alarm.alarm_set = alarm; @@ -121,8 +135,13 @@ static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) RTCCNTL.slp_timer0 = rtc_alarm & 0xffffffff; RTCCNTL.slp_timer1.slp_val_hi = rtc_alarm >> 32; +#if __xtensa__ DEBUG("%s %08x%08x \n", __func__, RTCCNTL.slp_timer1.slp_val_hi, RTCCNTL.slp_timer0); +#else + DEBUG("%s %08x%08x \n", __func__, + (unsigned)RTCCNTL.slp_timer1.slp_val_hi, (unsigned)RTCCNTL.slp_timer0); +#endif /* enable RTC timer alarm */ RTCCNTL.slp_timer1.main_timer_alarm_en = 1; @@ -168,10 +187,10 @@ static void IRAM _rtc_isr(void *arg) /* save the lower 32 bit of the current counter value */ uint32_t counter = _rtc_get_counter(); - DEBUG("%s %u\n", __func__, counter); + DEBUG("%s %" PRIu32 "\n", __func__, counter); if (_rtc_alarm.alarm_cb) { - DEBUG("%s alarm %u\n", __func__, counter); + DEBUG("%s alarm %" PRIu32 "\n", __func__, counter); rtt_cb_t alarm_cb = _rtc_alarm.alarm_cb; void *alarm_arg = _rtc_alarm.alarm_arg; diff --git a/cpu/esp32/periph/rtt_hw_sys.c b/cpu/esp32/periph/rtt_hw_sys.c index 0bb66c7a0086..1deb9094e755 100644 --- a/cpu/esp32/periph/rtt_hw_sys.c +++ b/cpu/esp32/periph/rtt_hw_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Gunar Schorcht + * Copyright (C) 2022 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -32,20 +32,28 @@ /* ESP-IDF headers */ #include "esp_attr.h" #include "esp_sleep.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/timer_hal.h" #include "rom/ets_sys.h" +#include "soc/periph_defs.h" #include "soc/timer_group_struct.h" + +#if __xtensa__ #include "xtensa/xtensa_api.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" -#define TIMER_SYSTEM_GROUP TIMERG0 -#define TIMER_SYSTEM_INT_MASK BIT(0) -#define TIMER_SYSTEM_INT_SRC ETS_TG0_T0_LEVEL_INTR_SOURCE +#define TIMER_SYSTEM_INT_MASK BIT(TIMER_SYSTEM_INDEX) #define SYS_US_TO_TICKS(us) ((((uint64_t)us) << 15) / US_PER_SEC) #define SYS_TICKS_TO_US(cnt) (((uint64_t)cnt * US_PER_SEC) >> 15) +/* system timer is defined and initialized in syscalls.c */ +extern timer_hal_context_t sys_timer; + typedef struct { uint32_t alarm_set; /**< alarm set at interface */ rtt_cb_t alarm_cb; /**< alarm callback */ @@ -77,15 +85,15 @@ static void _sys_poweron(void) intr_matrix_set(PRO_CPU_NUM, TIMER_SYSTEM_INT_SRC, CPU_INUM_RTT); /* set interrupt handler and enable the CPU interrupt */ - xt_set_interrupt_handler(CPU_INUM_RTT, _sys_isr, NULL); - xt_ints_on(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, _sys_isr, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_RTT)); } static void _sys_poweroff(void) { /* reset interrupt handler and disable the CPU interrupt */ - xt_ints_off(BIT(CPU_INUM_RTT)); - xt_set_interrupt_handler(CPU_INUM_RTT, NULL, NULL); + intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, NULL, NULL); } static uint64_t _sys_get_counter(void) @@ -108,8 +116,8 @@ static void _sys_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) uint64_t _sys_time = system_get_time_64(); uint64_t _sys_alarm_time = _sys_time + _sys_diff; - DEBUG("%s alarm=%u rtt_diff=%u " - "sys_diff=%llu sys_alarm=%llu @sys_time=%llu\n", __func__, + DEBUG("%s alarm=%" PRIu32 " rtt_diff=%" PRIu32 " " + "sys_diff=%" PRIu64 " sys_alarm=%" PRIu64 " @sys_time=%" PRIu64 "\n", __func__, alarm, rtt_diff, _sys_diff, _sys_alarm_time, _sys_time); /* save the alarm configuration for interrupt handling */ @@ -118,27 +126,24 @@ static void _sys_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) _sys_alarm.alarm_arg = arg; /* set the timer value */ - TIMER_SYSTEM.alarm_high = (uint32_t)(_sys_alarm_time >> 32); - TIMER_SYSTEM.alarm_low = (uint32_t)(_sys_alarm_time & 0xffffffff); + timer_hal_set_alarm_value(&sys_timer, _sys_alarm_time); /* clear the bit in status and set the bit in interrupt enable */ - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_ena.val |= TIMER_SYSTEM_INT_MASK; + timer_hal_clear_intr_status(&sys_timer); + timer_hal_intr_enable(&sys_timer); /* enable the timer alarm */ - TIMER_SYSTEM.config.level_int_en = 1; - TIMER_SYSTEM.config.alarm_en = 1; + timer_hal_set_alarm_enable(&sys_timer, true); } static void _sys_clear_alarm(void) { /* disable alarms first */ - TIMER_SYSTEM.config.level_int_en = 0; - TIMER_SYSTEM.config.alarm_en = 0; + timer_hal_intr_disable(&sys_timer); + timer_hal_set_alarm_enable(&sys_timer, false); - /* clear the bit in interrupt enable and status register */ - TIMER_SYSTEM_GROUP.int_ena.val &= ~TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; + /* clear the bit in interrupt status register */ + timer_hal_clear_intr_status(&sys_timer); /* reset the alarm configuration for interrupt handling */ _sys_alarm.alarm_set = 0; @@ -156,7 +161,7 @@ static void _sys_save_counter(void) critical_exit(); - DEBUG("%s rtc_time_saved=%llu sys_time_saved=%llu\n", __func__, + DEBUG("%s rtc_time_saved=%" PRIu64 " sys_time_saved=%" PRIu64 "\n", __func__, _rtc_counter_saved, _sys_counter_saved); } @@ -171,34 +176,36 @@ static void _sys_restore_counter(bool in_init) critical_exit(); - DEBUG("%s rtc_time_saved=%llu rtc_time_diff=%llu " - "sys_time_saved=%llu sys_time_offset=%llu\n", __func__, + DEBUG("%s rtc_time_saved=%" PRIu64 " rtc_time_diff=%" PRIu64 " " + "sys_time_saved=%" PRIu64 " sys_time_offset=%" PRIu64 "\n", __func__, _rtc_counter_saved, _rtc_time_diff, _sys_counter_saved, _sys_counter_offset); } static void IRAM _sys_isr(void *arg) { - if (!(TIMER_SYSTEM_GROUP.int_st_timers.val & TIMER_SYSTEM_INT_MASK)) { + uint32_t int_status; + + timer_hal_get_intr_status(&sys_timer, &int_status); + if (!(int_status & TIMER_SYSTEM_INT_MASK)) { /* return in case of another timer interrupt */ return; } /* disable alarms first */ - TIMER_SYSTEM.config.level_int_en = 0; - TIMER_SYSTEM.config.alarm_en = 0; + timer_hal_intr_disable(&sys_timer); + timer_hal_set_alarm_enable(&sys_timer, false); - /* clear the bit in interrupt enable and status register */ - TIMER_SYSTEM_GROUP.int_ena.val &= ~TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; + /* clear the bit in interrupt status register */ + timer_hal_clear_intr_status(&sys_timer); /* save the lower 32 bit of the current counter value */ uint32_t counter = _sys_get_counter(); - DEBUG("%s %u\n", __func__, counter); + DEBUG("%s %" PRIu32 "\n", __func__, counter); if (_sys_alarm.alarm_cb) { - DEBUG("%s alarm %u\n", __func__, counter); + DEBUG("%s alarm %" PRIu32 "\n", __func__, counter); rtt_cb_t alarm_cb = _sys_alarm.alarm_cb; void *alarm_arg = _sys_alarm.alarm_arg; diff --git a/cpu/esp32/syscalls.c b/cpu/esp32/syscalls.c index 7a7e8c5ea29e..f2c742f86826 100644 --- a/cpu/esp32/syscalls.c +++ b/cpu/esp32/syscalls.c @@ -30,11 +30,17 @@ #include "sys/lock.h" #include "timex.h" +#include "esp_rom_caps.h" #include "hal/interrupt_controller_types.h" #include "hal/interrupt_controller_ll.h" +#include "hal/timer_hal.h" +#include "hal/wdt_hal.h" +#include "hal/wdt_types.h" #include "rom/ets_sys.h" #include "rom/libc_stubs.h" +#include "soc/periph_defs.h" #include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_struct.h" #include "soc/timer_group_reg.h" #include "soc/timer_group_struct.h" @@ -244,12 +250,19 @@ static struct syscall_stub_table s_stub_table = #endif /* CONFIG_NEWLIB_NANO_FORMAT */ }; +timer_hal_context_t sys_timer = { + .dev = TIMER_LL_GET_HW(TIMER_SYSTEM_GROUP), + .idx = TIMER_SYSTEM_INDEX, +}; + void IRAM syscalls_init_arch(void) { - /* enable the system timer in us (TMG0 is enabled by default) */ - TIMER_SYSTEM.config.divider = rtc_clk_apb_freq_get() / MHZ; - TIMER_SYSTEM.config.autoreload = 0; - TIMER_SYSTEM.config.enable = 1; + /* initialize and enable the system timer in us (TMG0 is enabled by default) */ + timer_hal_init(&sys_timer, TIMER_SYSTEM_GROUP, TIMER_SYSTEM_INDEX); + timer_hal_set_divider(&sys_timer, rtc_clk_apb_freq_get() / MHZ); + timer_hal_set_counter_increase(&sys_timer, true); + timer_hal_set_auto_reload(&sys_timer, false); + timer_hal_set_counter_enable(&sys_timer, true); #if defined(MCU_ESP32) syscall_table_ptr_pro = &s_stub_table; @@ -263,10 +276,7 @@ void IRAM syscalls_init_arch(void) uint32_t system_get_time(void) { - /* latch 64 bit timer value before read */ - TIMER_SYSTEM.update = 0; - /* read the current timer value */ - return TIMER_SYSTEM.cnt_low; + return system_get_time_64(); } uint32_t system_get_time_ms(void) @@ -276,58 +286,68 @@ uint32_t system_get_time_ms(void) int64_t system_get_time_64(void) { - uint64_t ret; - /* latch 64 bit timer value before read */ - TIMER_SYSTEM.update = 0; - /* read the current timer value */ - ret = TIMER_SYSTEM.cnt_low; - ret += ((uint64_t)TIMER_SYSTEM.cnt_high) << 32; + uint64_t ret; + timer_hal_get_counter_value(&sys_timer, &ret); return ret; } +wdt_hal_context_t mwdt; +wdt_hal_context_t rwdt; + static IRAM void system_wdt_int_handler(void *arg) { - TIMERG0.int_clr_timers.wdt=1; /* clear interrupt */ - system_wdt_feed(); + wdt_hal_handle_intr(&mwdt); + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_feed(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void IRAM system_wdt_feed(void) { - DEBUG("%s\n", __func__); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_feed=1; /* reset MWDT */ - TIMERG0.wdt_wprotect=0; /* enable write protection */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_feed(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void system_wdt_init(void) { - /* disable boot watchdogs */ - TIMERG0.wdt_config0.flashboot_mod_en = 0; - RTCCNTL.wdt_config0.flashboot_mod_en = 0; - - /* enable system watchdog */ - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_INT; /* stage0 timeout: interrupt */ - TIMERG0.wdt_config0.stg1 = TIMG_WDT_STG_SEL_RESET_SYSTEM; /* stage1 timeout: sys reset */ - TIMERG0.wdt_config0.sys_reset_length = 7; /* sys reset signal length: 3.2 us */ - TIMERG0.wdt_config0.cpu_reset_length = 7; /* sys reset signal length: 3.2 us */ - TIMERG0.wdt_config0.edge_int_en = 0; - TIMERG0.wdt_config0.level_int_en = 1; - - /* MWDT clock = 80 * 12,5 ns = 1 us */ - TIMERG0.wdt_config1.clk_prescale = 80; - - /* define stage timeouts */ - TIMERG0.wdt_config2 = 2 * US_PER_SEC; /* stage 0: 2 s (interrupt) */ - TIMERG0.wdt_config3 = 4 * US_PER_SEC; /* stage 1: 4 s (sys reset) */ - - TIMERG0.wdt_config0.en = 1; /* enable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ - - DEBUG("%s TIMERG0 wdt_config0=%08x wdt_config1=%08x wdt_config2=%08x\n", - __func__, TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val, - TIMERG0.wdt_config2); + /* initialize and disable boot watchdogs MWDT and RWDT (the prescaler for + * MWDT is the APB clock in MHz to get a microsecond tick, for RWDT it is + * not applicable) */ + wdt_hal_init(&mwdt, WDT_MWDT0, rtc_clk_apb_freq_get()/MHZ, true); + wdt_hal_init(&rwdt, WDT_RWDT, 0, false); + + /* disable write protection for MWDT and RWDT */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_write_protect_disable(&rwdt); + + /* configure stages */ + wdt_hal_config_stage(&mwdt, WDT_STAGE0, 2 * US_PER_SEC, WDT_STAGE_ACTION_INT); + wdt_hal_config_stage(&mwdt, WDT_STAGE1, 2 * US_PER_SEC, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&mwdt, WDT_STAGE2, 0, WDT_STAGE_ACTION_OFF); + wdt_hal_config_stage(&mwdt, WDT_STAGE3, 0, WDT_STAGE_ACTION_OFF); + + /* enable the watchdog */ + wdt_hal_enable(&mwdt); + + /* enable write protection for MWDT and RWDT */ + wdt_hal_write_protect_enable(&mwdt); + wdt_hal_write_protect_enable(&rwdt); + +#if defined(MCU_ESP32) + DEBUG("%s TIMERG0 wdtconfig0=%08x wdtconfig1=%08x wdtconfig2=%08x " + "wdtconfig3=%08x wdtconfig4=%08x regclk=%08x\n", __func__, + TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val, + TIMERG0.wdt_config2, TIMERG0.wdt_config3, + TIMERG0.wdt_config4, TIMERG0.clk.val); +#else + DEBUG("%s TIMERG0 wdtconfig0=%08"PRIx32" wdtconfig1=%08"PRIx32 + " wdtconfig2=%08"PRIx32" wdtconfig3=%08"PRIx32 + " wdtconfig4=%08"PRIx32" regclk=%08"PRIx32"\n", __func__, + TIMERG0.wdtconfig0.val, TIMERG0.wdtconfig1.val, + TIMERG0.wdtconfig2.val, TIMERG0.wdtconfig3.val, + TIMERG0.wdtconfig4.val, TIMERG0.regclk.val); +#endif /* route WDT peripheral interrupt source to CPU_INUM_WDT */ intr_matrix_set(PRO_CPU_NUM, ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT); @@ -339,17 +359,15 @@ void system_wdt_init(void) void system_wdt_stop(void) { intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_WDT)); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.en = 0; /* disable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_disable(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void system_wdt_start(void) { - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.en = 1; /* disable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_enable(&mwdt); + wdt_hal_write_protect_enable(&mwdt); intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_WDT)); }