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 <lucas.tamborrino@espressif.com>
This commit is contained in:
Lucas Tamborrino 2024-05-13 09:54:00 -03:00 committed by David Leach
commit aa692309bf
15 changed files with 402 additions and 4 deletions

View file

@ -620,7 +620,6 @@ static int esp32_cpu_clock_configure(const struct esp32_cpu_clock_config *cpu_cf
old_config.freq_mhz); old_config.freq_mhz);
uart_clock_src_hz = esp_clk_apb_freq(); uart_clock_src_hz = esp_clk_apb_freq();
#if !defined(ESP_CONSOLE_UART_NONE) #if !defined(ESP_CONSOLE_UART_NONE)
esp_rom_uart_set_clock_baudrate(ESP_CONSOLE_UART_NUM, uart_clock_src_hz, esp_rom_uart_set_clock_baudrate(ESP_CONSOLE_UART_NUM, uart_clock_src_hz,
ESP_CONSOLE_UART_BAUDRATE); 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) static int clock_control_esp32_init(const struct device *dev)
{ {
const struct esp32_clock_config *cfg = dev->config; const struct esp32_clock_config *cfg = dev->config;
struct esp32_clock_data *data = dev->data;
soc_reset_reason_t rst_reas; soc_reset_reason_t rst_reas;
rtc_config_t rtc_cfg = RTC_CONFIG_DEFAULT(); rtc_config_t rtc_cfg = RTC_CONFIG_DEFAULT();
bool ret; bool ret;
uint32_t uart_clock_src_hz;
rst_reas = esp_rom_get_reset_reason(0); rst_reas = esp_rom_get_reset_reason(0);
#if !defined(CONFIG_SOC_SERIES_ESP32) #if !defined(CONFIG_SOC_SERIES_ESP32)
@ -685,6 +686,14 @@ static int clock_control_esp32_init(const struct device *dev)
return ret; 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); rtc_clk_fast_src_set(cfg->rtc.rtc_fast_clock_src);
ret = esp32_select_rtc_slow_clk(cfg->rtc.rtc_slow_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 = { 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_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 = { static const struct esp32_clock_config esp32_clock_config0 = {

View file

@ -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_CC32XX wdt_cc32xx.c)
zephyr_library_sources_ifdef(CONFIG_WDT_CC13XX_CC26XX wdt_cc13xx_cc26xx.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_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_GECKO wdt_gecko.c)
zephyr_library_sources_ifdef(CONFIG_WDT_ITE_IT8XXX2 wdt_ite_it8xxx2.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) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_IMX_WDOG wdt_mcux_imx_wdog.c)

View file

@ -10,3 +10,10 @@ config WDT_ESP32
select HAS_WDT_DISABLE_AT_BOOT select HAS_WDT_DISABLE_AT_BOOT
help help
Enable WDT driver for ESP32. 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.

View file

@ -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 <soc/rtc_cntl_reg.h>
#include <hal/xt_wdt_hal.h>
#include <rom/ets_sys.h>
#include <string.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/esp32_clock_control.h>
#ifndef CONFIG_SOC_SERIES_ESP32C3
#include <zephyr/drivers/interrupt_controller/intc_esp32.h>
#else
#include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
#endif
#include <zephyr/device.h>
#include <zephyr/logging/log.h>
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

View file

@ -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

View file

@ -105,6 +105,15 @@
status = "okay"; status = "okay";
}; };
xt_wdt: xt_wdt@60008004 {
compatible = "espressif,esp32-xt-wdt";
reg = <0x60008004 0x4>;
clocks = <&rtc ESP32_MODULE_MAX>;
interrupts = <RTC_CORE_INTR_SOURCE>;
interrupt-parent = <&intc>;
status = "disabled";
};
rtc_timer: rtc_timer@60008004 { rtc_timer: rtc_timer@60008004 {
reg = <0x60008004 0xC>; reg = <0x60008004 0xC>;
compatible = "espressif,esp32-rtc-timer"; compatible = "espressif,esp32-rtc-timer";

View file

@ -94,7 +94,15 @@
slow-clk-src = <ESP32_RTC_SLOW_CLK_SRC_RC_SLOW>; slow-clk-src = <ESP32_RTC_SLOW_CLK_SRC_RC_SLOW>;
#clock-cells = <1>; #clock-cells = <1>;
status = "okay"; status = "okay";
};
xt_wdt: xt_wdt@3f408004 {
compatible = "espressif,esp32-xt-wdt";
reg = <0x3f408004 0x4>;
clocks = <&rtc ESP32_MODULE_MAX>;
interrupts = <RTC_CORE_INTR_SOURCE>;
interrupt-parent = <&intc>;
status = "disabled";
}; };
rtc_timer: rtc_timer@3f408004 { rtc_timer: rtc_timer@3f408004 {

View file

@ -111,7 +111,15 @@
slow-clk-src = <ESP32_RTC_SLOW_CLK_SRC_RC_SLOW>; slow-clk-src = <ESP32_RTC_SLOW_CLK_SRC_RC_SLOW>;
#clock-cells = <1>; #clock-cells = <1>;
status = "okay"; status = "okay";
};
xt_wdt: xt_wdt@60021004 {
compatible = "espressif,esp32-xt-wdt";
reg = <0x60021004 0x4>;
clocks = <&rtc ESP32_MODULE_MAX>;
interrupts = <RTC_CORE_INTR_SOURCE>;
interrupt-parent = <&intc>;
status = "disabled";
}; };
rtc_timer: rtc_timer@60008004 { rtc_timer: rtc_timer@60008004 {
@ -120,7 +128,7 @@
clocks = <&rtc ESP32_MODULE_MAX>; clocks = <&rtc ESP32_MODULE_MAX>;
interrupts = <RTC_CORE_INTR_SOURCE>; interrupts = <RTC_CORE_INTR_SOURCE>;
interrupt-parent = <&intc>; interrupt-parent = <&intc>;
status = "okay"; status = "disabled";
}; };
flash: flash-controller@60002000 { flash: flash-controller@60002000 {

View file

@ -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)

View file

@ -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] <inf> xt_wdt_sample: XT WDT Sample on esp32s3_devkitm/esp32s3/procpu
[00:00:01.287,000] <inf> xt_wdt_sample: Current RTC SLOW clock rate: 32768 Hz
[00:00:01.287,000] <inf> xt_wdt_sample: Remove the external 32K crystal to trigger the watchdog
XT WDT callback
[00:00:03.554,000] <inf> xt_wdt_sample: Current RTC SLOW clock rate: 136000 Hz

View file

@ -0,0 +1,13 @@
/*
* Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
&rtc {
slow-clk-src = <ESP32_RTC_SLOW_CLK_SRC_XTAL32K>;
};
&xt_wdt {
status = "okay";
};

View file

@ -0,0 +1,3 @@
CONFIG_LOG=y
CONFIG_WATCHDOG=y
CONFIG_WDT_LOG_LEVEL_INF=y

View file

@ -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

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <zephyr/devicetree.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/clock_control/esp32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
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;
}

View file

@ -157,7 +157,7 @@ manifest:
groups: groups:
- hal - hal
- name: hal_espressif - name: hal_espressif
revision: b5f5fa6d08780c0077407150c6685d6c9d70262c revision: 5191505f915c0b1c706222f4709925a453e0e858
path: modules/hal/espressif path: modules/hal/espressif
west-commands: west/west-commands.yml west-commands: west/west-commands.yml
groups: groups: