From aa692309bf2e02018583f03c2e8b942d6a94d47d Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Mon, 13 May 2024 09:54:00 -0300 Subject: [PATCH] drivers: wdt: espressif: Add 32K Xtal Watchdog This WDT is responsible for monitoring the external 32.728 Hz crystal connected to pins XTAL_32K_P and XTAL_32K_N. If an oscillation failure is detected the hardware automatically switch to RTC_RC_SLOW clock source and triggers an interrupt. Signed-off-by: Lucas Tamborrino --- drivers/clock_control/clock_control_esp32.c | 13 +- drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig.esp32 | 7 + drivers/watchdog/xt_wdt_esp32.c | 176 ++++++++++++++++++ .../watchdog/espressif,esp32-xt-wdt.yaml | 17 ++ .../espressif/esp32c3/esp32c3_common.dtsi | 9 + .../espressif/esp32s2/esp32s2_common.dtsi | 8 + .../espressif/esp32s3/esp32s3_common.dtsi | 10 +- samples/boards/esp32/xt_wdt/CMakeLists.txt | 8 + samples/boards/esp32/xt_wdt/README.rst | 60 ++++++ samples/boards/esp32/xt_wdt/app.overlay | 13 ++ samples/boards/esp32/xt_wdt/prj.conf | 3 + samples/boards/esp32/xt_wdt/sample.yaml | 10 + samples/boards/esp32/xt_wdt/src/main.c | 69 +++++++ west.yml | 2 +- 15 files changed, 402 insertions(+), 4 deletions(-) create mode 100644 drivers/watchdog/xt_wdt_esp32.c create mode 100644 dts/bindings/watchdog/espressif,esp32-xt-wdt.yaml create mode 100644 samples/boards/esp32/xt_wdt/CMakeLists.txt create mode 100644 samples/boards/esp32/xt_wdt/README.rst create mode 100644 samples/boards/esp32/xt_wdt/app.overlay create mode 100644 samples/boards/esp32/xt_wdt/prj.conf create mode 100644 samples/boards/esp32/xt_wdt/sample.yaml create mode 100644 samples/boards/esp32/xt_wdt/src/main.c diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index 594763846de..c62402ed665 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -620,7 +620,6 @@ static int esp32_cpu_clock_configure(const struct esp32_cpu_clock_config *cpu_cf old_config.freq_mhz); uart_clock_src_hz = esp_clk_apb_freq(); - #if !defined(ESP_CONSOLE_UART_NONE) esp_rom_uart_set_clock_baudrate(ESP_CONSOLE_UART_NUM, uart_clock_src_hz, ESP_CONSOLE_UART_BAUDRATE); @@ -663,9 +662,11 @@ static int clock_control_esp32_configure(const struct device *dev, clock_control static int clock_control_esp32_init(const struct device *dev) { const struct esp32_clock_config *cfg = dev->config; + struct esp32_clock_data *data = dev->data; soc_reset_reason_t rst_reas; rtc_config_t rtc_cfg = RTC_CONFIG_DEFAULT(); bool ret; + uint32_t uart_clock_src_hz; rst_reas = esp_rom_get_reset_reason(0); #if !defined(CONFIG_SOC_SERIES_ESP32) @@ -685,6 +686,14 @@ static int clock_control_esp32_init(const struct device *dev) return ret; } +#if defined(CONFIG_SOC_SERIES_ESP32S3) + uart_clock_src_hz = (uint32_t)rtc_clk_xtal_freq_get() * MHZ(1); +#if !defined(ESP_CONSOLE_UART_NONE) + esp_rom_uart_set_clock_baudrate(ESP_CONSOLE_UART_NUM, uart_clock_src_hz, + ESP_CONSOLE_UART_BAUDRATE); +#endif +#endif + rtc_clk_fast_src_set(cfg->rtc.rtc_fast_clock_src); ret = esp32_select_rtc_slow_clk(cfg->rtc.rtc_slow_clock_src); @@ -714,7 +723,7 @@ static const struct esp32_cpu_clock_config esp32_cpu_clock_config0 = { static const struct esp32_rtc_clock_config esp32_rtc_clock_config0 = { .rtc_fast_clock_src = DT_PROP(DT_INST(0, espressif_esp32_rtc), fast_clk_src), - .rtc_slow_clock_src = DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src) + .rtc_slow_clock_src = DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src), }; static const struct esp32_clock_config esp32_clock_config0 = { diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index cfec0ef05fe..41f56d637db 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_WDOG_CMSDK_APB wdt_cmsdk_apb.c) zephyr_library_sources_ifdef(CONFIG_WDT_CC32XX wdt_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_WDT_CC13XX_CC26XX wdt_cc13xx_cc26xx.c) zephyr_library_sources_ifdef(CONFIG_WDT_ESP32 wdt_esp32.c) +zephyr_library_sources_ifdef(CONFIG_WDT_XT_ESP32 xt_wdt_esp32.c) zephyr_library_sources_ifdef(CONFIG_WDT_GECKO wdt_gecko.c) zephyr_library_sources_ifdef(CONFIG_WDT_ITE_IT8XXX2 wdt_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_IMX_WDOG wdt_mcux_imx_wdog.c) diff --git a/drivers/watchdog/Kconfig.esp32 b/drivers/watchdog/Kconfig.esp32 index 5fb736bf092..26bf28c2647 100644 --- a/drivers/watchdog/Kconfig.esp32 +++ b/drivers/watchdog/Kconfig.esp32 @@ -10,3 +10,10 @@ config WDT_ESP32 select HAS_WDT_DISABLE_AT_BOOT help Enable WDT driver for ESP32. + +config WDT_XT_ESP32 + bool "ESP32 Watchdog for External 32K Crystal Driver" + default y + depends on DT_HAS_ESPRESSIF_ESP32_XT_WDT_ENABLED + help + Enable WDT driver for ESP32. diff --git a/drivers/watchdog/xt_wdt_esp32.c b/drivers/watchdog/xt_wdt_esp32.c new file mode 100644 index 00000000000..7e0141d0266 --- /dev/null +++ b/drivers/watchdog/xt_wdt_esp32.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT espressif_esp32_xt_wdt + +#include +#include +#include + +#include +#include +#include +#include + +#ifndef CONFIG_SOC_SERIES_ESP32C3 +#include +#else +#include +#endif +#include +#include + +LOG_MODULE_REGISTER(xt_wdt_esp32, CONFIG_WDT_LOG_LEVEL); + +#ifdef CONFIG_SOC_SERIES_ESP32C3 +#define ISR_HANDLER isr_handler_t +#else +#define ISR_HANDLER intr_handler_t +#endif + +#define ESP32_XT_WDT_MAX_TIMEOUT 255 + +struct esp32_xt_wdt_data { + xt_wdt_hal_context_t hal; + wdt_callback_t callback; + uint32_t timeout; +}; + +struct esp32_xt_wdt_config { + const struct device *clock_dev; + const clock_control_subsys_t clock_subsys; + int irq_source; +}; + +static int esp32_xt_wdt_setup(const struct device *dev, uint8_t options) +{ + ARG_UNUSED(options); + struct esp32_xt_wdt_data *data = dev->data; + + xt_wdt_hal_config_t xt_wdt_hal_config = { + .timeout = data->timeout, + }; + + xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config); + xt_wdt_hal_enable(&data->hal, true); + + return 0; +} + +static int esp32_xt_wdt_disable(const struct device *dev) +{ + struct esp32_xt_wdt_data *data = dev->data; + + xt_wdt_hal_enable(&data->hal, false); + + return 0; +} + +static int esp32_xt_wdt_feed(const struct device *dev, int channel_id) +{ + ARG_UNUSED(dev); + ARG_UNUSED(channel_id); + + return -ENOSYS; +} + +static int esp32_xt_wdt_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct esp32_xt_wdt_data *data = dev->data; + + if (cfg->window.min != 0U || cfg->window.max == 0U || + cfg->window.max >= ESP32_XT_WDT_MAX_TIMEOUT) { + LOG_ERR("Invalid timeout configuration"); + return -EINVAL; + } + + data->timeout = cfg->window.max; + data->callback = cfg->callback; + + return 0; +} + +static void esp32_xt_wdt_isr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + const struct esp32_xt_wdt_config *cfg = dev->config; + struct esp32_xt_wdt_data *data = dev->data; + struct esp32_clock_config clk_cfg = {0}; + uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); + + REG_WRITE(RTC_CNTL_INT_CLR_REG, status); + + clk_cfg.rtc.rtc_slow_clock_src = ESP32_RTC_SLOW_CLK_SRC_RC_SLOW; + + clock_control_configure(cfg->clock_dev, + (clock_control_subsys_t)ESP32_CLOCK_CONTROL_SUBSYS_RTC_SLOW, + &clk_cfg); + + if (data->callback != NULL) { + data->callback(dev, 0); + } +} + +static int esp32_xt_wdt_init(const struct device *dev) +{ + const struct esp32_xt_wdt_config *cfg = dev->config; + struct esp32_xt_wdt_data *data = dev->data; + xt_wdt_hal_config_t xt_wdt_hal_config = { + .timeout = ESP32_XT_WDT_MAX_TIMEOUT, + }; + + xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config); + xt_wdt_hal_enable_backup_clk(&data->hal, + ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ/1000); + + int err = esp_intr_alloc(cfg->irq_source, 0, (ISR_HANDLER)esp32_xt_wdt_isr, (void *)dev, + NULL); + if (err) { + LOG_ERR("Failed to register ISR\n"); + return -EFAULT; + } + + REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); + REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); + + return 0; +} + +static const struct wdt_driver_api esp32_xt_wdt_api = { + .setup = esp32_xt_wdt_setup, + .disable = esp32_xt_wdt_disable, + .install_timeout = esp32_xt_wdt_install_timeout, + .feed = esp32_xt_wdt_feed +}; + +static struct esp32_xt_wdt_data esp32_xt_wdt_data0; + +static struct esp32_xt_wdt_config esp32_xt_wdt_config0 = { + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(0, offset), + .irq_source = DT_INST_IRQN(0), +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(xt_wdt), + &esp32_xt_wdt_init, + NULL, + &esp32_xt_wdt_data0, + &esp32_xt_wdt_config0, + POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &esp32_xt_wdt_api); + +#if !(defined(CONFIG_SOC_SERIES_ESP32S2) || \ + defined(CONFIG_SOC_SERIES_ESP32S3) || \ + defined(CONFIG_SOC_SERIES_ESP32C3)) +#error "XT WDT is not supported" +#else +BUILD_ASSERT((DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src) == + ESP32_RTC_SLOW_CLK_SRC_XTAL32K) || + (DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src) == + ESP32_RTC_SLOW_CLK_32K_EXT_OSC), + "XT WDT is only supported with XTAL32K or 32K_EXT_OSC as slow clock source"); +#endif diff --git a/dts/bindings/watchdog/espressif,esp32-xt-wdt.yaml b/dts/bindings/watchdog/espressif,esp32-xt-wdt.yaml new file mode 100644 index 00000000000..c20a4234cab --- /dev/null +++ b/dts/bindings/watchdog/espressif,esp32-xt-wdt.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: | + This watchdog timer can detect oscillation failure of the RTC_SLOW_CLK_SRC_XTAL32K. + When such a failure is detected the hardware automatically switch to + ESP32_RTC_SLOW_CLK_SRC_RC_SLOW. + + This feature is only available for ESP32S2,ESP32C3 and ESP32S3. + +compatible: "espressif,esp32-xt-wdt" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi index 7c0962bec7a..43f171f57a1 100644 --- a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi +++ b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi @@ -105,6 +105,15 @@ status = "okay"; }; + xt_wdt: xt_wdt@60008004 { + compatible = "espressif,esp32-xt-wdt"; + reg = <0x60008004 0x4>; + clocks = <&rtc ESP32_MODULE_MAX>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + rtc_timer: rtc_timer@60008004 { reg = <0x60008004 0xC>; compatible = "espressif,esp32-rtc-timer"; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi index e8491c338e7..3a88d973c47 100644 --- a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi +++ b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi @@ -94,7 +94,15 @@ slow-clk-src = ; #clock-cells = <1>; status = "okay"; + }; + xt_wdt: xt_wdt@3f408004 { + compatible = "espressif,esp32-xt-wdt"; + reg = <0x3f408004 0x4>; + clocks = <&rtc ESP32_MODULE_MAX>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; }; rtc_timer: rtc_timer@3f408004 { diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 62135a34ac3..284b74211fd 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -111,7 +111,15 @@ slow-clk-src = ; #clock-cells = <1>; status = "okay"; + }; + xt_wdt: xt_wdt@60021004 { + compatible = "espressif,esp32-xt-wdt"; + reg = <0x60021004 0x4>; + clocks = <&rtc ESP32_MODULE_MAX>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; }; rtc_timer: rtc_timer@60008004 { @@ -120,7 +128,7 @@ clocks = <&rtc ESP32_MODULE_MAX>; interrupts = ; interrupt-parent = <&intc>; - status = "okay"; + status = "disabled"; }; flash: flash-controller@60002000 { diff --git a/samples/boards/esp32/xt_wdt/CMakeLists.txt b/samples/boards/esp32/xt_wdt/CMakeLists.txt new file mode 100644 index 00000000000..899973e1b69 --- /dev/null +++ b/samples/boards/esp32/xt_wdt/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(xt_wdt_sample) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/esp32/xt_wdt/README.rst b/samples/boards/esp32/xt_wdt/README.rst new file mode 100644 index 00000000000..05f9052e0a8 --- /dev/null +++ b/samples/boards/esp32/xt_wdt/README.rst @@ -0,0 +1,60 @@ +.. _xt_wdt_sample: + +Espressif XT WDT Sample +####################### + +Overview +******** + +This sample shows how to work with XTAL32K Watchdog Timer (XT WDT) peripheral. +To properly run this sample, you need to have a board with an external 32.728 Hz +crystal oscillator connected to the XTAL_32K_P and XTAL_32K_N pins. + +The app will ask for the crystal removal to simulate a crystal failure and trigger +the XT WDT interrupt. Internally the hardware switch the RTC SLOW clock source from +ESP32_RTC_SLOW_CLK_SRC_XTAL32K to ESP32_RTC_SLOW_CLK_SRC_RC_SLOW (136 KHz for C3 and S3 / +9 KHz for S2). + +Supported SoCs +************** + +The following SoCs supports the XT WDT peripheral: + +* ESP32-C3 +* ESP32-S2 +* ESP32-S3 + +Building and Running +******************** + +Make sure you have your board connected over USB port and the external crystal is connected +to pins XTAL_32K_P and XTAL_32K_N. + +.. code-block:: console + + west build -p -b esp32s3_devkitm/esp32s3/procpu samples/boards/esp32/xt_wdt + west flash + +If using another supported Espressif board, replace the argument in the above +command with a proper board name (e.g., `esp32s2_saola`). + +Sample Output +============= + +To check output of this sample, run ``west espressif monitor`` or any other serial +console program (e.g., minicom, putty, screen, etc). +This example uses ``west espressif monitor``, which automatically detects the serial +port at ``/dev/ttyUSB0``: + +.. code-block:: console + + $ west espressif monitor + +.. code-block:: console + + *** Booting Zephyr OS build v3.6.0-3896-gb4a7f061524f *** + [00:00:01.287,000] xt_wdt_sample: XT WDT Sample on esp32s3_devkitm/esp32s3/procpu + [00:00:01.287,000] xt_wdt_sample: Current RTC SLOW clock rate: 32768 Hz + [00:00:01.287,000] xt_wdt_sample: Remove the external 32K crystal to trigger the watchdog + XT WDT callback + [00:00:03.554,000] xt_wdt_sample: Current RTC SLOW clock rate: 136000 Hz diff --git a/samples/boards/esp32/xt_wdt/app.overlay b/samples/boards/esp32/xt_wdt/app.overlay new file mode 100644 index 00000000000..8a95767c5e2 --- /dev/null +++ b/samples/boards/esp32/xt_wdt/app.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&rtc { + slow-clk-src = ; +}; + +&xt_wdt { + status = "okay"; +}; diff --git a/samples/boards/esp32/xt_wdt/prj.conf b/samples/boards/esp32/xt_wdt/prj.conf new file mode 100644 index 00000000000..b465d963948 --- /dev/null +++ b/samples/boards/esp32/xt_wdt/prj.conf @@ -0,0 +1,3 @@ +CONFIG_LOG=y +CONFIG_WATCHDOG=y +CONFIG_WDT_LOG_LEVEL_INF=y diff --git a/samples/boards/esp32/xt_wdt/sample.yaml b/samples/boards/esp32/xt_wdt/sample.yaml new file mode 100644 index 00000000000..01a159a61bb --- /dev/null +++ b/samples/boards/esp32/xt_wdt/sample.yaml @@ -0,0 +1,10 @@ +sample: + description: Application to test XT WDT + name: xt_wdt_sample +tests: + sample.board.esp32.xt_wdt: + platform_allow: + - esp32c3_devkitm + - esp32s2_saola + - esp32s3_devkitm/esp32s3/procpu + tags: esp32 diff --git a/samples/boards/esp32/xt_wdt/src/main.c b/samples/boards/esp32/xt_wdt/src/main.c new file mode 100644 index 00000000000..c2a3387d05c --- /dev/null +++ b/samples/boards/esp32/xt_wdt/src/main.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(xt_wdt_sample, CONFIG_WDT_LOG_LEVEL); + +K_SEM_DEFINE(wdt_sem, 0, 1); + +static const struct device *const clk_dev = DEVICE_DT_GET_ONE(espressif_esp32_rtc); +const struct device *const wdt = DEVICE_DT_GET_ONE(espressif_esp32_xt_wdt); + +static void wdt_callback(const struct device *wdt_dev, int channel_id) +{ + printk("XT WDT callback\n"); + k_sem_give(&wdt_sem); +} + +int main(void) +{ + uint32_t clk_rate = 0; + + if (!device_is_ready(clk_dev)) { + LOG_ERR("Clock device is not ready"); + return -EIO; + } + + if (!device_is_ready(wdt)) { + LOG_ERR("XT WDT device is not ready"); + return -EIO; + } + + LOG_INF("XT WDT Sample on %s", CONFIG_BOARD_TARGET); + + clock_control_get_rate(clk_dev, (clock_control_subsys_t)ESP32_CLOCK_CONTROL_SUBSYS_RTC_SLOW, + &clk_rate); + + LOG_INF("Current RTC SLOW clock rate: %d Hz", clk_rate); + + /* Set up the watchdog */ + struct wdt_timeout_cfg wdt_config = { + .window.max = 200, + .callback = wdt_callback, + }; + + wdt_install_timeout(wdt, &wdt_config); + + wdt_setup(wdt, 0); + + LOG_INF("Remove the external 32K crystal to trigger the watchdog"); + + k_sem_take(&wdt_sem, K_FOREVER); + + clock_control_get_rate(clk_dev, (clock_control_subsys_t)ESP32_CLOCK_CONTROL_SUBSYS_RTC_SLOW, + &clk_rate); + + LOG_INF("Current RTC SLOW clock rate: %d Hz", clk_rate); + + return 0; +} diff --git a/west.yml b/west.yml index 266824891d4..04bdf09ed4c 100644 --- a/west.yml +++ b/west.yml @@ -157,7 +157,7 @@ manifest: groups: - hal - name: hal_espressif - revision: b5f5fa6d08780c0077407150c6685d6c9d70262c + revision: 5191505f915c0b1c706222f4709925a453e0e858 path: modules/hal/espressif west-commands: west/west-commands.yml groups: