risc-v/esp32c3: Add support for MWDT0 and MWDT1

This commit is contained in:
Gustavo Henrique Nihei 2021-02-22 09:35:17 -03:00 committed by Abdelatif Guettouche
parent 7b8c72ec1b
commit 291a5755cc
16 changed files with 6311 additions and 11 deletions

View File

@ -104,6 +104,10 @@ config ESP32C3_CPU_FREQ_MHZ
menu "ESP32-C3 Peripheral Support"
config ESP32C3_WDT
bool
default n
config ESP32C3_GPIO_IRQ
bool "GPIO pin interrupts"
---help---
@ -119,6 +123,33 @@ config ESP32C3_UART1
default n
select UART1_SERIALDRIVER
config ESP32C3_MWDT0
bool "Main System Watchdog Timer (Group 0)"
default n
select ESP32C3_WDT
---help---
Includes MWDT0. This watchdog timer is part of the Group 0
timer submodule.
config ESP32C3_MWDT1
bool "Main System Watchdog Timer (Group 1)"
default n
select ESP32C3_WDT
---help---
Includes MWDT1. This watchdog timer is part of the Group 0
timer submodule.
config ESP32C3_RWDT
bool "RTC Watchdog Timer"
default n
select ESP32C3_WDT
---help---
Includes RWDT. This watchdog timer is from the RTC module.
When it is selected, if the developer sets it to reset on expiration
it will reset Main System and the RTC module. If you don't want
to have the RTC module reset, please, use the Timers' Module WDTs.
They will only reset Main System.
endmenu
endif # ARCH_CHIP_ESP32C3

View File

@ -53,3 +53,10 @@ CHIP_CSRCS = esp32c3_allocateheap.c esp32c3_start.c esp32c3_idle.c
CHIP_CSRCS += esp32c3_irq.c esp32c3_timerisr.c
CHIP_CSRCS += esp32c3_clockconfig.c esp32c3_gpio.c
CHIP_CSRCS += esp32c3_serial.c esp32c3_lowputc.c
ifeq ($(CONFIG_ESP32C3_WDT),y)
CHIP_CSRCS += esp32c3_wdt.c
ifeq ($(CONFIG_WATCHDOG),y)
CHIP_CSRCS += esp32c3_wdt_lowerhalf.c
endif
endif

View File

@ -0,0 +1,923 @@
/****************************************************************************
* arch/riscv/src/esp32c3/esp32c3_wdt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <stdbool.h>
#include "riscv_arch.h"
#include "hardware/esp32c3_rtccntl.h"
#include "hardware/esp32c3_tim.h"
#include "esp32c3_wdt.h"
#include "esp32c3_irq.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Check whether the provided device is a RTC Watchdog Timer */
#define IS_RWDT(dev) ((struct esp32c3_wdt_priv_s *)dev)->base == \
RTC_CNTL_OPTIONS0_REG
/****************************************************************************
* Private Types
****************************************************************************/
struct esp32c3_wdt_priv_s
{
struct esp32c3_wdt_ops_s *ops;
uint32_t base; /* WDT register base address */
uint8_t periph; /* Peripheral ID */
uint8_t irq; /* Interrupt ID */
int32_t cpuint; /* CPU interrupt assigned to this WDT */
bool inuse; /* Flag indicating if this WDT is in use */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* WDT registers access *****************************************************/
static void esp32c3_wdt_putreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t value);
static void esp32c3_wdt_modifyreg32(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t clearbits,
uint32_t setbits);
static uint32_t esp32c3_wdt_getreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset);
/* WDT operations ***********************************************************/
static void esp32c3_wdt_start(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_stop(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_enablewp(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_disablewp(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_pre(struct esp32c3_wdt_dev_s *dev,
uint16_t value);
static int32_t esp32c3_wdt_settimeout(struct esp32c3_wdt_dev_s *dev,
uint32_t value,
enum esp32c3_wdt_stage_e stage);
static void esp32c3_wdt_feed(struct esp32c3_wdt_dev_s *dev);
static int32_t esp32c3_wdt_config_stage(struct esp32c3_wdt_dev_s *dev,
enum esp32c3_wdt_stage_e stage,
enum esp32c3_wdt_stage_action_e cfg);
static void esp32c3_wdt_update_conf(struct esp32c3_wdt_dev_s *dev);
static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
xcpt_t handler, void *arg);
static void esp32c3_wdt_enableint(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_disableint(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_ackint(struct esp32c3_wdt_dev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
/* ESP32 WDT ops */
struct esp32c3_wdt_ops_s esp32c3_mwdt_ops =
{
.start = esp32c3_wdt_start,
.stop = esp32c3_wdt_stop,
.enablewp = esp32c3_wdt_enablewp,
.disablewp = esp32c3_wdt_disablewp,
.pre = esp32c3_wdt_pre,
.settimeout = esp32c3_wdt_settimeout,
.feed = esp32c3_wdt_feed,
.stg_conf = esp32c3_wdt_config_stage,
.upd_conf = esp32c3_wdt_update_conf,
.rtc_clk = NULL,
.setisr = esp32c3_wdt_setisr,
.enableint = esp32c3_wdt_enableint,
.disableint = esp32c3_wdt_disableint,
.ackint = esp32c3_wdt_ackint,
};
struct esp32c3_wdt_ops_s esp32c3_rwdt_ops =
{
.start = esp32c3_wdt_start,
.stop = esp32c3_wdt_stop,
.enablewp = esp32c3_wdt_enablewp,
.disablewp = esp32c3_wdt_disablewp,
.pre = NULL,
.settimeout = esp32c3_wdt_settimeout,
.feed = esp32c3_wdt_feed,
.stg_conf = esp32c3_wdt_config_stage,
.upd_conf = NULL,
.rtc_clk = NULL,
.setisr = esp32c3_wdt_setisr,
.enableint = esp32c3_wdt_enableint,
.disableint = esp32c3_wdt_disableint,
.ackint = esp32c3_wdt_ackint,
};
#ifdef CONFIG_ESP32C3_MWDT0
struct esp32c3_wdt_priv_s g_esp32c3_mwdt0_priv =
{
.ops = &esp32c3_mwdt_ops,
.base = TIMG_T0CONFIG_REG(0),
.periph = ESP32C3_PERIPH_TG0_WDT,
.irq = ESP32C3_IRQ_TG0_WDT,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP32C3_MWDT1
struct esp32c3_wdt_priv_s g_esp32c3_mwdt1_priv =
{
.ops = &esp32c3_mwdt_ops,
.base = TIMG_T0CONFIG_REG(1),
.periph = ESP32C3_PERIPH_TG1_WDT,
.irq = ESP32C3_IRQ_TG1_WDT,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP32C3_RWDT
struct esp32c3_wdt_priv_s g_esp32c3_rwdt_priv =
{
.ops = &esp32c3_rwdt_ops,
.base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32C3_PERIPH_RTC_CORE,
.irq = ESP32C3_IRQ_RTC_CORE,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_putreg
*
* Description:
* Write a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
* value - Value to written to the specified memory region.
*
****************************************************************************/
static void esp32c3_wdt_putreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t value)
{
DEBUGASSERT(dev);
putreg32(value, ((struct esp32c3_wdt_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: esp32c3_wdt_modifyreg32
*
* Description:
* Atomically modify a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
* clearbits - Bits to be cleared on the specified memory region.
* setbits - Bits to be set on the specified memory region.
*
****************************************************************************/
static void esp32c3_wdt_modifyreg32(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t clearbits,
uint32_t setbits)
{
DEBUGASSERT(dev);
modifyreg32(((struct esp32c3_wdt_priv_s *)dev)->base + offset,
clearbits, setbits);
}
/****************************************************************************
* Name: esp32c3_wdt_getreg
*
* Description:
* Read a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
*
* Returned Values:
* A 32-bit value from the provided memory region of the WDT device.
*
****************************************************************************/
static uint32_t esp32c3_wdt_getreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset)
{
DEBUGASSERT(dev);
return getreg32(((struct esp32c3_wdt_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: esp32c3_wdt_start
*
* Description:
* Release the counter.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_start(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, RTC_CNTL_WDT_EN);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, TIMG_WDT_EN);
}
}
/****************************************************************************
* Name: esp32c3_wdt_config_stage
*
* Description:
* Configure the action to be triggered by a stage on expiration.
*
* Parameters:
* dev - Pointer to the driver state structure.
* stage - WDT stage to be configured.
* cfg - Action to be executed on stage expiration.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_config_stage(struct esp32c3_wdt_dev_s *dev,
enum esp32c3_wdt_stage_e stage,
enum esp32c3_wdt_stage_action_e cfg)
{
int32_t ret = OK;
uint32_t mask;
DEBUGASSERT(dev);
switch (stage)
{
case ESP32C3_WDT_STAGE0:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG0_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG0_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG0_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG0_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE1:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG1_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG1_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG1_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG1_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE2:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG2_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG2_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG2_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG2_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE3:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG3_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG3_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG3_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG3_M, mask);
}
break;
}
default:
{
wderr("ERROR: unsupported stage %d\n", stage);
ret = -EINVAL;
goto errout;
}
}
errout:
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_update_conf
*
* Description:
* Update the Watchdog Timer configuration registers.
* Configuration registers for the MWDT are updated asynchronously.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_update_conf(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0,
TIMG_WDT_CONF_UPDATE_EN);
}
/****************************************************************************
* Name: esp32c3_wdt_stop
*
* Description:
* Disable the watchdog.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_stop(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_EN, 0);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_EN, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_enablewp
*
* Description:
* Enable write protection (WP) on registers against accidental writing.
* TRM recommends to change any WDT register through this sequence:
* - Disable WP
* - Do the op
* - Reenable WP
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_enablewp(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_WP_REG, 0);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_WP_REG, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_disablewp
*
* Description:
* Disable write protection (WP) on registers against accidental writing.
* TRM recommends to change any WDT register through this sequence:
* - Disable WP
* - Do the op
* - Reenable WP
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_disablewp(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_WP_REG, RTC_CNTL_WDT_WKEY_VALUE);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_WP_REG, TIMG_WDT_WKEY_VALUE);
}
}
/****************************************************************************
* Name: esp32c3_wdt_pre
*
* Description:
* Set a prescale value.
* The MWDT clock period is 12.5 ns * value (pre).
* NOTE: There's no prescaler register for RWDT and its source clock is
* clocked from the RTC slow clock.
*
* Parameters:
* dev - Pointer to the driver state structure.
* pre - Prescaler value to be configured.
*
****************************************************************************/
static void esp32c3_wdt_pre(struct esp32c3_wdt_dev_s *dev,
uint16_t pre)
{
uint32_t mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALE_S;
DEBUGASSERT(dev);
esp32c3_wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET,
TIMG_WDT_CLK_PRESCALE_M, mask);
}
/****************************************************************************
* Name: esp32c3_wdt_settimeout
*
* Description:
* Set the WDT timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
* value - Timeout value in number of WDT cycles.
* stage - Stage whose timeout value needs to be configured.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_settimeout(struct esp32c3_wdt_dev_s *dev,
uint32_t value,
enum esp32c3_wdt_stage_e stage)
{
int32_t ret = OK;
DEBUGASSERT(dev);
switch (stage)
{
case ESP32C3_WDT_STAGE0:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE0_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE0_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE1:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE1_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE1_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE2:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE2_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE2_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE3:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE3_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE3_TIMEOUT_OFFSET, value);
}
break;
}
default:
{
wderr("ERROR: unsupported stage %d\n", stage);
ret = -EINVAL;
goto errout;
}
}
errout:
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_feed
*
* Description:
* Feed the watchdog.
* The watchdog timer returns to stage 0 and its counter restarts from 0.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_feed(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_WDT_FEED);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_FEED_OFFSET, TIMG_WDT_FEED);
}
}
/****************************************************************************
* Name: esp32c3_wdt_setisr
*
* Description:
* Allocate a Level CPU Interrupt, connect the peripheral source to this
* Interrupt, register the callback and enable the interrupt.
* In case a NULL handler is provided, deallocate the interrupt and
* unregister the previously provided handler.
*
* Parameters:
* dev - Pointer to the driver state structure.
* handler - Callback to be invoked on watchdog timer interrupt.
* arg - Argument to be passed to the handler callback.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
xcpt_t handler,
void *arg)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
int32_t ret = OK;
DEBUGASSERT(dev);
wdt = (struct esp32c3_wdt_priv_s *)dev;
/* Disable interrupt when callback is removed. */
if (handler == NULL)
{
if (wdt->cpuint != -ENOMEM)
{
/* If a CPU Interrupt was previously allocated,
* then deallocate it.
*/
up_disable_irq(wdt->cpuint);
irq_detach(wdt->irq);
esp32c3_free_cpuint(wdt->periph);
}
}
/* Otherwise set callback and enable interrupt. */
else
{
if (wdt->cpuint != -ENOMEM)
{
/* Disable the provided CPU Interrupt to configure it. */
up_disable_irq(wdt->cpuint);
}
wdt->cpuint = esp32c3_request_irq(wdt->periph,
ESP32C3_INT_PRIO_DEF,
ESP32C3_INT_LEVEL);
if (wdt->cpuint < 0)
{
return wdt->cpuint;
}
/* Attach and enable the IRQ. */
ret = irq_attach(wdt->irq, handler, arg);
if (ret == OK)
{
/* Enable the CPU Interrupt that is linked to the WDT. */
up_enable_irq(wdt->cpuint);
}
}
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_enableint
*
* Description:
* Enable a Level Interrupt at timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_enableint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0,
RTC_CNTL_WDT_INT_ENA);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, 0,
TIMG_WDT_INT_ENA);
}
}
/****************************************************************************
* Name: esp32c3_wdt_disableint
*
* Description:
* Disable a Level Interrupt at timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_disableint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET,
RTC_CNTL_WDT_INT_ENA, 0);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET,
TIMG_WDT_INT_ENA, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_ackint
*
* Description:
* Acknowledge an interrupt.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_ackint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_WDT_INT_CLR);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_INT_CLR_REG_OFFSET, TIMG_WDT_INT_CLR);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_init
*
* Description:
* Initialize WDT device.
*
* Parameters:
* wdt_id - A Watchdog Timer instance to be initialized.
*
* Return Values:
* Pointer to the driver state structure.
*
****************************************************************************/
struct esp32c3_wdt_dev_s *esp32c3_wdt_init(enum esp32c3_wdt_inst_e wdt_id)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
/* Get WDT instance */
switch (wdt_id)
{
#ifdef CONFIG_ESP32C3_MWDT0
case ESP32C3_WDT_MWDT0:
{
wdt = &g_esp32c3_mwdt0_priv;
break;
}
#endif
#ifdef CONFIG_ESP32C3_MWDT1
case ESP32C3_WDT_MWDT1:
{
wdt = &g_esp32c3_mwdt1_priv;
break;
}
#endif
#ifdef CONFIG_ESP32C3_RWDT
case ESP32C3_WDT_RWDT:
{
wdt = &g_esp32c3_rwdt_priv;
break;
}
#endif
default:
{
wderr("ERROR: unsupported WDT %d\n", wdt_id);
goto errout;
}
}
/* If some code is using it then sends an error message,
* Otherwise, inform it has been used.
*/
if (wdt->inuse == true)
{
wderr("ERROR: WDT %d is already in use\n", wdt_id);
wdt = NULL;
}
else
{
wdt->inuse = true;
}
errout:
return (struct esp32c3_wdt_dev_s *)wdt;
}
/****************************************************************************
* Name: esp32c3_wdt_deinit
*
* Description:
* Deinitialize a WDT device.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
void esp32c3_wdt_deinit(struct esp32c3_wdt_dev_s *dev)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
DEBUGASSERT(dev);
wdt = (struct esp32c3_wdt_priv_s *)dev;
wdt->inuse = false;
}
/****************************************************************************
* Name: esp32c3_wdt_is_running
*
* Description:
* Check whether the WDT is already started.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
* Returned Values:
* true if the Watchdog Timer is already started, false otherwise.
*
****************************************************************************/
bool esp32c3_wdt_is_running(struct esp32c3_wdt_dev_s *dev)
{
uint32_t status = 0;
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
status = esp32c3_wdt_getreg(dev, RWDT_CONFIG0_OFFSET);
if (status & RTC_CNTL_WDT_EN)
{
return true;
}
}
else
{
status = esp32c3_wdt_getreg(dev, MWDT_CONFIG0_OFFSET);
if (status & TIMG_WDT_EN)
{
return true;
}
}
return false;
}

View File

@ -0,0 +1,147 @@
/****************************************************************************
* arch/riscv/src/esp32c3/esp32c3_wdt.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_H
#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/irq.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Helpers ******************************************************************/
#define ESP32C3_WDT_START(d) ((d)->ops->start(d))
#define ESP32C3_WDT_STOP(d) ((d)->ops->stop(d))
#define ESP32C3_WDT_LOCK(d) ((d)->ops->enablewp(d))
#define ESP32C3_WDT_UNLOCK(d) ((d)->ops->disablewp(d))
#define ESP32C3_MWDT_PRE(d, v) ((d)->ops->pre(d, v))
#define ESP32C3_WDT_STO(d, v, s) ((d)->ops->settimeout(d, v, s))
#define ESP32C3_WDT_FEED(d) ((d)->ops->feed(d))
#define ESP32C3_WDT_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c))
#define ESP32C3_MWDT_UPD_CONF(d) ((d)->ops->upd_conf(d))
#define ESP32C3_RWDT_CLK(d) ((d)->ops->rtc_clk(d))
#define ESP32C3_WDT_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg))
#define ESP32C3_WDT_ENABLEINT(d) ((d)->ops->enableint(d))
#define ESP32C3_WDT_DISABLEINT(d) ((d)->ops->disableint(d))
#define ESP32C3_WDT_ACKINT(d) ((d)->ops->ackint(d))
/****************************************************************************
* Public Types
****************************************************************************/
/* Instances of Watchdog Timer */
enum esp32c3_wdt_inst_e
{
ESP32C3_WDT_MWDT0 = 0, /* Main System Watchdog Timer (MWDT) of Timer Group 0 */
ESP32C3_WDT_MWDT1, /* Main System Watchdog Timer (MWDT) of Timer Group 1 */
ESP32C3_WDT_RWDT /* RTC Watchdog Timer (RWDT) */
};
/* Stages of a Watchdog Timer. A WDT has 4 stages. */
enum esp32c3_wdt_stage_e
{
ESP32C3_WDT_STAGE0 = 0, /* Stage 0 */
ESP32C3_WDT_STAGE1 = 1, /* Stage 1 */
ESP32C3_WDT_STAGE2 = 2, /* Stage 2 */
ESP32C3_WDT_STAGE3 = 3 /* Stage 3 */
};
/**
* Behavior of the WDT stage if it times out.
*
* @note These enum values should be compatible with the
* corresponding register field values.
*/
enum esp32c3_wdt_stage_action_e
{
ESP32C3_WDT_STAGE_ACTION_OFF = 0, /* Disabled. This stage will have no effects on the system. */
ESP32C3_WDT_STAGE_ACTION_INT = 1, /* Trigger an interrupt when the stage expires. */
ESP32C3_WDT_STAGE_ACTION_RESET_CPU = 2, /* Reset a CPU core when the stage expires. */
ESP32C3_WDT_STAGE_ACTION_RESET_SYSTEM = 3, /* Reset the main system when the stage expires.
* This includes the CPU and all peripherals.
* The RTC is an exception and will not be reset.
*/
ESP32C3_WDT_STAGE_ACTION_RESET_RTC = 4 /* Reset the main system and the RTC when the stage expires.
* ONLY AVAILABLE FOR RWDT.
*/
};
/* ESP32 WDT device */
struct esp32c3_wdt_dev_s
{
struct esp32c3_wdt_ops_s *ops;
};
/* ESP32 WDT ops */
/* This is a struct containing the pointers to the wdt operations */
struct esp32c3_wdt_ops_s
{
/* WDT tasks */
void (*start)(struct esp32c3_wdt_dev_s *dev);
void (*stop)(struct esp32c3_wdt_dev_s *dev);
/* WDT configuration */
void (*enablewp)(struct esp32c3_wdt_dev_s *dev);
void (*disablewp)(struct esp32c3_wdt_dev_s *dev);
void (*pre)(struct esp32c3_wdt_dev_s *dev, uint16_t value);
int32_t (*settimeout)(struct esp32c3_wdt_dev_s *dev,
uint32_t value,
enum esp32c3_wdt_stage_e stage);
void (*feed)(struct esp32c3_wdt_dev_s *dev);
int32_t (*stg_conf)(struct esp32c3_wdt_dev_s *dev,
enum esp32c3_wdt_stage_e stage,
enum esp32c3_wdt_stage_action_e conf);
void (*upd_conf)(struct esp32c3_wdt_dev_s *dev);
uint16_t (*rtc_clk)(struct esp32c3_wdt_dev_s *dev);
/* WDT interrupts */
int32_t (*setisr)(struct esp32c3_wdt_dev_s *dev, xcpt_t handler,
void * arg);
void (*enableint)(struct esp32c3_wdt_dev_s *dev);
void (*disableint)(struct esp32c3_wdt_dev_s *dev);
void (*ackint)(struct esp32c3_wdt_dev_s *dev);
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct esp32c3_wdt_dev_s *esp32c3_wdt_init(enum esp32c3_wdt_inst_e wdt_id);
void esp32c3_wdt_deinit(struct esp32c3_wdt_dev_s *dev);
bool esp32c3_wdt_is_running(struct esp32c3_wdt_dev_s *dev);
#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_H */

View File

@ -0,0 +1,746 @@
/****************************************************************************
* arch/riscv/src/esp32c3/esp32c3_wdt_lowerhalf.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <nuttx/timers/watchdog.h>
#include "riscv_arch.h"
#include "hardware/esp32c3_soc.h"
#include "esp32c3_wdt.h"
#include "esp32c3_wdt_lowerhalf.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* MWDT clock period in microseconds */
#define MWDT_CLK_PERIOD_US (500)
/* Number of MWDT cycles per microseconds */
#define MWDT_CYCLES_PER_MS (USEC_PER_MSEC / MWDT_CLK_PERIOD_US)
/* Convert MWDT timeout cycles to milliseconds */
#define MWDT_TIMEOUT_MS(t) ((t) * MWDT_CYCLES_PER_MS)
/* Maximum number of MWDT cycles supported for timeout */
#define MWDT_MAX_TIMEOUT_MS (UINT32_MAX / MWDT_CYCLES_PER_MS)
/* MWDT clock prescaler value */
#define MWDT_CLK_PRESCALER_VALUE (MWDT_CLK_PERIOD_US * NSEC_PER_USEC / 12.5)
/* Maximum number of cycles supported for a RWDT stage timeout */
#define RWDT_FULL_STAGE (UINT32_MAX)
/****************************************************************************
* Private Types
****************************************************************************/
typedef enum
{
RTC,
TIMER,
} wdt_peripherals_t;
/* This structure provides the private representation of the "lower-half"
* driver state structure. This structure must be cast-compatible with the
* well-known watchdog_lowerhalf_s structure.
*/
struct esp32c3_wdt_lowerhalf_s
{
const struct watchdog_ops_s *ops; /* Lower half operations */
struct esp32c3_wdt_dev_s *wdt; /* ESP32-C3 watchdog driver */
uint32_t timeout; /* The current timeout */
wdt_peripherals_t peripheral; /* Indicates if it is from RTC or Timer Module */
uint32_t lastreset; /* The last reset time */
bool started; /* True: Timer has been started */
xcpt_t handler; /* User Handler */
void *upper; /* Pointer to watchdog_upperhalf_s */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Interrupt handling *******************************************************/
static int esp32c3_wdt_handler(int irq, void *context, void *arg);
/* "Lower half" driver methods **********************************************/
static int esp32c3_wdt_start(struct watchdog_lowerhalf_s *lower);
static int esp32c3_wdt_stop(struct watchdog_lowerhalf_s *lower);
static int esp32c3_wdt_keepalive(struct watchdog_lowerhalf_s *lower);
static int esp32c3_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status);
static int esp32c3_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout);
static xcpt_t esp32c3_wdt_capture(struct watchdog_lowerhalf_s *lower,
xcpt_t handler);
/****************************************************************************
* Private Data
****************************************************************************/
/* "Lower half" driver methods */
static const struct watchdog_ops_s g_esp32c3_wdg_ops =
{
.start = esp32c3_wdt_start,
.stop = esp32c3_wdt_stop,
.keepalive = esp32c3_wdt_keepalive,
.getstatus = esp32c3_wdt_getstatus,
.settimeout = esp32c3_wdt_settimeout,
.capture = esp32c3_wdt_capture,
.ioctl = NULL,
};
#ifdef CONFIG_ESP32C3_MWDT0
/* MWDT0 lower-half */
static struct esp32c3_wdt_lowerhalf_s g_esp32c3_mwdt0_lowerhalf =
{
.ops = &g_esp32c3_wdg_ops,
};
#endif
#ifdef CONFIG_ESP32C3_MWDT1
/* MWDT1 lower-half */
static struct esp32c3_wdt_lowerhalf_s g_esp32c3_mwdt1_lowerhalf =
{
.ops = &g_esp32c3_wdg_ops,
};
#endif
#ifdef CONFIG_ESP32C3_RWDT
/* RWDT lower-half */
static struct esp32c3_wdt_lowerhalf_s g_esp32c3_rwdt_lowerhalf =
{
.ops = &g_esp32c3_wdg_ops,
};
#endif
/****************************************************************************
* Name: esp32c3_wdt_start
*
* Description:
* Start the watchdog timer, register a callback if there is one and
* enables interrupt, otherwise, configure it to reset system on
* expiration.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
*
* Returned Values:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int esp32c3_wdt_start(struct watchdog_lowerhalf_s *lower)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
int ret = OK;
irqstate_t flags;
wdinfo("Entry: started\n");
DEBUGASSERT(priv);
if (priv->started == true)
{
/* Return EBUSY to indicate that the timer was already running */
ret = -EBUSY;
goto errout;
}
/* If WDT was not started yet */
else
{
priv->started = true;
/* Unlock WDT */
ESP32C3_WDT_UNLOCK(priv->wdt);
/* No User Handler */
if (priv->handler == NULL)
{
/* Then configure it to reset on wdt expiration */
if (priv->peripheral == TIMER)
{
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_RESET_SYSTEM);
ESP32C3_MWDT_UPD_CONF(priv->wdt);
}
else
{
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_RESET_RTC);
}
}
/* User handler was already provided */
else
{
/* Then configure it to call the user handler on wdt expiration */
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_INT);
if (priv->peripheral == TIMER)
{
ESP32C3_MWDT_UPD_CONF(priv->wdt);
}
/* Set the lower half handler and enable interrupt */
flags = enter_critical_section();
ESP32C3_WDT_SETISR(priv->wdt, esp32c3_wdt_handler, priv);
leave_critical_section(flags);
ESP32C3_WDT_ENABLEINT(priv->wdt);
}
flags = enter_critical_section();
priv->lastreset = clock_systime_ticks();
ESP32C3_WDT_START(priv->wdt);
leave_critical_section(flags);
/* Lock it again */
ESP32C3_WDT_LOCK(priv->wdt);
}
errout:
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_stop
*
* Description:
* Stop the watchdog timer. In case a callback was previously configured,
* unregister and deallocate it.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
*
****************************************************************************/
static int esp32c3_wdt_stop(struct watchdog_lowerhalf_s *lower)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
irqstate_t flags;
/* Unlock WDT */
ESP32C3_WDT_UNLOCK(priv->wdt);
/* Disable the WDT */
ESP32C3_WDT_STOP(priv->wdt);
/* In case there is some callback registered, disable and deallocate */
if (priv->handler != NULL)
{
ESP32C3_WDT_DISABLEINT(priv->wdt);
flags = enter_critical_section();
ESP32C3_WDT_SETISR(priv->wdt, NULL, NULL);
leave_critical_section(flags);
}
/* Lock it again */
ESP32C3_WDT_LOCK(priv->wdt);
priv->started = false;
return OK;
}
/****************************************************************************
* Name: esp32c3_wdt_keepalive
*
* Description:
* Reset the watchdog timer, prevent any
* imminent watchdog timeouts. This is sometimes referred as "pinging"
* the watchdog timer or "petting the dog".
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
*
*
****************************************************************************/
static int esp32c3_wdt_keepalive(struct watchdog_lowerhalf_s *lower)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
irqstate_t flags;
wdinfo("Entry\n");
/* Unlock */
ESP32C3_WDT_UNLOCK(priv->wdt);
/* Feed the dog and updates the lastreset variable */
flags = enter_critical_section();
priv->lastreset = clock_systime_ticks();
ESP32C3_WDT_FEED(priv->wdt);
leave_critical_section(flags);
/* Lock */
ESP32C3_WDT_LOCK(priv->wdt);
return OK;
}
/****************************************************************************
* Name: esp32c3_wdt_getstatus
*
* Description:
* Get the current watchdog timer status
*
* Input Parameters:
* lower - A pointer the publicly visible representation of
* the "lower-half" driver state structure.
* status - The location to return the watchdog status information.
*
****************************************************************************/
static int esp32c3_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
uint32_t ticks;
uint32_t elapsed;
DEBUGASSERT(priv);
/* Flags */
status->flags = 0;
/* If no handler was settled, then RESET on expiration.
* Otherwise, call the user handler.
*/
if (priv->handler == NULL)
{
status->flags |= WDFLAGS_RESET;
}
else
{
status->flags |= WDFLAGS_CAPTURE;
}
if (priv->started)
{
status->flags |= WDFLAGS_ACTIVE;
}
/* Return the current timeout in milliseconds */
status->timeout = priv->timeout;
/* Get the elapsed time since the last ping */
ticks = clock_systime_ticks() - priv->lastreset;
elapsed = (uint32_t)TICK2MSEC(ticks);
if (elapsed < priv->timeout)
{
/* Return the approximate time until the watchdog timer expiration */
status->timeleft = priv->timeout - elapsed;
}
else
{
status->timeleft = 0;
}
return OK;
}
/****************************************************************************
* Name: esp32c3_wdt_settimeout
*
* Description:
* Set a new timeout value (and reset the watchdog timer)
*
* Input Parameters:
* lower - A pointer the publicly visible representation of
* the "lower-half" driver state structure.
* timeout - The new timeout value in milliseconds.
*
* Returned Values:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int esp32c3_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
uint16_t rtc_cycles = 0;
uint32_t rtc_ms_max = 0;
wdinfo("Entry: timeout=%"PRIu32"\n", timeout);
DEBUGASSERT(priv);
/* Unlock WDT */
ESP32C3_WDT_UNLOCK(priv->wdt);
/* Write the timeout value */
priv->timeout = timeout;
/* Watchdog from Timer Module */
if (priv->peripheral == TIMER)
{
/* Is this timeout a valid value for Timer's WDT? */
if (timeout == 0 || timeout > MWDT_MAX_TIMEOUT_MS)
{
wderr("ERROR: Cannot represent timeout=%"PRIu32" > %"PRIu32"\n",
timeout, MWDT_MAX_TIMEOUT_MS);
return -ERANGE;
}
else
{
ESP32C3_WDT_STO(priv->wdt, MWDT_TIMEOUT_MS(timeout),
ESP32C3_WDT_STAGE0);
ESP32C3_MWDT_UPD_CONF(priv->wdt);
}
}
/* Watchdog from RTC Module */
else
{
rtc_cycles = ESP32C3_RWDT_CLK(priv->wdt);
rtc_ms_max = (RWDT_FULL_STAGE / (uint32_t)rtc_cycles);
/* Is this timeout a valid value for RTC WDT? */
if (timeout == 0 || timeout > rtc_ms_max)
{
wderr("ERROR: Cannot represent timeout=%"PRIu32" > %"PRIu32"\n",
timeout, rtc_ms_max);
return -ERANGE;
}
else
{
timeout = timeout * rtc_cycles;
ESP32C3_WDT_STO(priv->wdt, timeout, ESP32C3_WDT_STAGE0);
}
}
/* Reset the wdt */
ESP32C3_WDT_FEED(priv->wdt);
/* Lock it again */
ESP32C3_WDT_LOCK(priv->wdt);
return OK;
}
/****************************************************************************
* Name: esp32c3_wdt_capture
*
* Description:
* Don't reset on watchdog timer timeout; instead, call this user provider
* timeout handler. NOTE: Providing handler==NULL will restore the reset
* behavior.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* newhandler - The new watchdog expiration function pointer. If this
* function pointer is NULL, then the reset-on-expiration
* behavior is restored,
*
* Returned Value:
* The previous watchdog expiration function pointer or NULL if there was
* no previous function pointer, i.e., if the previous behavior was
* reset-on-expiration (NULL is also returned if an error occurs).
*
****************************************************************************/
static xcpt_t esp32c3_wdt_capture(struct watchdog_lowerhalf_s *lower,
xcpt_t handler)
{
struct esp32c3_wdt_lowerhalf_s *priv =
(struct esp32c3_wdt_lowerhalf_s *)lower;
irqstate_t flags;
xcpt_t oldhandler;
DEBUGASSERT(priv);
wdinfo("Entry: handler=0x%" PRIxPTR "\n", (uintptr_t) handler);
/* Get the old handler to return it */
oldhandler = priv->handler;
ESP32C3_WDT_UNLOCK(priv->wdt);
flags = enter_critical_section();
/* Save the new user handler */
priv->handler = handler;
/* There is a user callback and the timer has already been started.
* The user wants to set a callback after starting the wdt or wants to
* change the callback function once a callback has already been settled.
*/
if (priv->handler != NULL && priv->started == true)
{
/* Deallocate the previous allocated interrupt
* If there is a previous allocated interrupt.
*/
if (oldhandler != NULL)
{
ESP32C3_WDT_SETISR(priv->wdt, NULL, NULL);
}
else
{
/* If it was previous configured to reset on timeout
* then change to interrupt.
*/
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_INT);
if (priv->peripheral == TIMER)
{
ESP32C3_MWDT_UPD_CONF(priv->wdt);
}
}
/* Set the lower half handler and enable interrupt */
ESP32C3_WDT_SETISR(priv->wdt, esp32c3_wdt_handler, priv);
ESP32C3_WDT_ENABLEINT(priv->wdt);
}
/* In case the user wants to disable the callback */
else
{
ESP32C3_WDT_DISABLEINT(priv->wdt);
ESP32C3_WDT_SETISR(priv->wdt, NULL, NULL);
/* Then configure it to reset on WDT expiration */
if (priv->peripheral == TIMER)
{
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_RESET_SYSTEM);
ESP32C3_MWDT_UPD_CONF(priv->wdt);
}
else
{
ESP32C3_WDT_STG_CONF(priv->wdt, ESP32C3_WDT_STAGE0,
ESP32C3_WDT_STAGE_ACTION_RESET_RTC);
}
}
leave_critical_section(flags);
ESP32C3_WDT_LOCK(priv->wdt);
return oldhandler;
}
/* Interrupt handling *******************************************************/
static int esp32c3_wdt_handler(int irq, void *context, void *arg)
{
struct esp32c3_wdt_lowerhalf_s *priv = arg;
/* Run the user callback */
priv->handler(irq, context, priv->upper);
/* Clear the Interrupt */
ESP32C3_WDT_UNLOCK(priv->wdt);
ESP32C3_WDT_ACKINT(priv->wdt);
ESP32C3_WDT_LOCK(priv->wdt);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_initialize
*
* Description:
* Initialize the watchdog timer. The watchdog timer is initialized
* and registered as 'devpath'.
*
* Input Parameters:
* devpath - The full path to the watchdog. This should
* be of the form /dev/watchdogX
* wdt - WDT instance to be initialized.
*
* Returned Values:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int esp32c3_wdt_initialize(const char *devpath, enum esp32c3_wdt_inst_e wdt)
{
struct esp32c3_wdt_lowerhalf_s *lower = NULL;
int ret = OK;
DEBUGASSERT(devpath);
switch (wdt)
{
#ifdef CONFIG_ESP32C3_MWDT0
case ESP32C3_WDT_MWDT0:
{
lower = &g_esp32c3_mwdt0_lowerhalf;
lower->peripheral = TIMER;
break;
}
#endif
#ifdef CONFIG_ESP32C3_MWDT1
case ESP32C3_WDT_MWDT1:
{
lower = &g_esp32c3_mwdt1_lowerhalf;
lower->peripheral = TIMER;
break;
}
#endif
#ifdef CONFIG_ESP32C3_RWDT
case ESP32C3_WDT_RWDT:
{
lower = &g_esp32c3_rwdt_lowerhalf;
lower->peripheral = RTC;
break;
}
#endif
default:
{
ret = -ENODEV;
goto errout;
}
}
/* Initialize the elements of lower half state structure */
lower->handler = NULL;
lower->timeout = 0;
lower->wdt = esp32c3_wdt_init(wdt);
if (lower->wdt == NULL)
{
ret = -EINVAL;
goto errout;
}
lower->started = esp32c3_wdt_is_running(lower->wdt);
ESP32C3_WDT_UNLOCK(lower->wdt);
/* If it is a Main System Watchdog Timer configure the Prescale to
* have a 500us period.
*/
if (lower->peripheral == TIMER)
{
ESP32C3_MWDT_PRE(lower->wdt, MWDT_CLK_PRESCALER_VALUE);
ESP32C3_MWDT_UPD_CONF(lower->wdt);
}
ESP32C3_WDT_LOCK(lower->wdt);
/* Register the watchdog driver as /dev/watchdogX. If the registration goes
* right the returned value from watchdog_register is a pointer to
* watchdog_upperhalf_s that can be either used with watchdog_unregister()
* or with the handler's arg.
*/
lower->upper = watchdog_register(devpath,
(struct watchdog_lowerhalf_s *)lower);
if (lower->upper == NULL)
{
/* The actual cause of the failure may have been a failure to allocate
* perhaps a failure to register the watchdog driver (such as if the
* 'devpath' were not unique). We know here but we return EEXIST to
* indicate the failure (implying the non-unique devpath).
*/
ret = -EEXIST;
goto errout;
}
errout:
return ret;
}

View File

@ -0,0 +1,58 @@
/****************************************************************************
* arch/riscv/src/esp32c3/esp32c3_wdt_lowerhalf.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_LOWERHALF_H
#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_LOWERHALF_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "esp32c3_wdt.h"
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_initialize
*
* Description:
* Initialize the watchdog timer. The watchdog timer is initialized
* and registered as 'devpath'.
*
* Input Parameters:
* devpath - The full path to the watchdog. This should
* be of the form /dev/watchdogX
* wdt - WDT instance to be initialized.
*
* Returned Values:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int esp32c3_wdt_initialize(const char *devpath, enum esp32c3_wdt_inst_e wdt);
#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_WDT_LOWERHALF_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,529 @@
/****************************************************************************
* arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_TIM_H
#define __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_TIM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "esp32c3_soc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Offset relative to each watchdog timer instance memory base */
#define MWDT_CONFIG0_OFFSET 0x0048
/* MWDT */
#define MWDT_CLK_PRESCALE_OFFSET 0x004c
#define MWDT_STAGE0_TIMEOUT_OFFSET 0x0050
#define MWDT_STAGE1_TIMEOUT_OFFSET 0x0054
#define MWDT_STAGE2_TIMEOUT_OFFSET 0x0058
#define MWDT_STAGE3_TIMEOUT_OFFSET 0x005c
#define MWDT_FEED_OFFSET 0x0060
#define MWDT_WP_REG 0x0064
#define MWDT_INT_ENA_REG_OFFSET 0x0070
#define MWDT_INT_CLR_REG_OFFSET 0x007c
/* The value that needs to be written to TIMG_WDT_WKEY to
* write-enable the WDT registers.
*/
#define TIMG_WDT_WKEY_VALUE 0x50D83AA1
/* Possible values for TIMG_WDT_STGx */
#define TIMG_WDT_STG_SEL_OFF 0
#define TIMG_WDT_STG_SEL_INT 1
#define TIMG_WDT_STG_SEL_RESET_CPU 2
#define TIMG_WDT_STG_SEL_RESET_SYSTEM 3
#define TIMG_WDT_RESET_LENGTH_100_NS 0
#define TIMG_WDT_RESET_LENGTH_200_NS 1
#define TIMG_WDT_RESET_LENGTH_300_NS 2
#define TIMG_WDT_RESET_LENGTH_400_NS 3
#define TIMG_WDT_RESET_LENGTH_500_NS 4
#define TIMG_WDT_RESET_LENGTH_800_NS 5
#define TIMG_WDT_RESET_LENGTH_1600_NS 6
#define TIMG_WDT_RESET_LENGTH_3200_NS 7
#define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)
/* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
#define TIMG_T0_EN (BIT(31))
#define TIMG_T0_EN_M (BIT(31))
#define TIMG_T0_EN_V 0x1
#define TIMG_T0_EN_S 31
/* TIMG_T0_INCREASE : R/W ;bitpos:[30] ;default: 1'h1 ; */
#define TIMG_T0_INCREASE (BIT(30))
#define TIMG_T0_INCREASE_M (BIT(30))
#define TIMG_T0_INCREASE_V 0x1
#define TIMG_T0_INCREASE_S 30
/* TIMG_T0_AUTORELOAD : R/W ;bitpos:[29] ;default: 1'h1 ; */
#define TIMG_T0_AUTORELOAD (BIT(29))
#define TIMG_T0_AUTORELOAD_M (BIT(29))
#define TIMG_T0_AUTORELOAD_V 0x1
#define TIMG_T0_AUTORELOAD_S 29
/* TIMG_T0_DIVIDER : R/W ;bitpos:[28:13] ;default: 16'h1 ; */
#define TIMG_T0_DIVIDER 0x0000FFFF
#define TIMG_T0_DIVIDER_M ((TIMG_T0_DIVIDER_V)<<(TIMG_T0_DIVIDER_S))
#define TIMG_T0_DIVIDER_V 0xFFFF
#define TIMG_T0_DIVIDER_S 13
/* TIMG_T0_DIVCNT_RST : WT ;bitpos:[12] ;default: 1'h0 ; */
#define TIMG_T0_DIVCNT_RST (BIT(12))
#define TIMG_T0_DIVCNT_RST_M (BIT(12))
#define TIMG_T0_DIVCNT_RST_V 0x1
#define TIMG_T0_DIVCNT_RST_S 12
/* TIMG_T0_ALARM_EN : R/W/SC ;bitpos:[10] ;default: 1'h0 ; */
#define TIMG_T0_ALARM_EN (BIT(10))
#define TIMG_T0_ALARM_EN_M (BIT(10))
#define TIMG_T0_ALARM_EN_V 0x1
#define TIMG_T0_ALARM_EN_S 10
/* TIMG_T0_USE_XTAL : R/W ;bitpos:[9] ;default: 1'd0 ; */
#define TIMG_T0_USE_XTAL (BIT(9))
#define TIMG_T0_USE_XTAL_M (BIT(9))
#define TIMG_T0_USE_XTAL_V 0x1
#define TIMG_T0_USE_XTAL_S 9
#define TIMG_T0LO_REG(i) (REG_TIMG_BASE(i) + 0x0004)
/* TIMG_T0_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
#define TIMG_T0_LO 0xFFFFFFFF
#define TIMG_T0_LO_M ((TIMG_T0_LO_V)<<(TIMG_T0_LO_S))
#define TIMG_T0_LO_V 0xFFFFFFFF
#define TIMG_T0_LO_S 0
#define TIMG_T0HI_REG(i) (REG_TIMG_BASE(i) + 0x0008)
/* TIMG_T0_HI : RO ;bitpos:[21:0] ;default: 22'h0 ; */
#define TIMG_T0_HI 0x003FFFFF
#define TIMG_T0_HI_M ((TIMG_T0_HI_V)<<(TIMG_T0_HI_S))
#define TIMG_T0_HI_V 0x3FFFFF
#define TIMG_T0_HI_S 0
#define TIMG_T0UPDATE_REG(i) (REG_TIMG_BASE(i) + 0x000c)
/* TIMG_T0_UPDATE : R/W/SC ;bitpos:[31] ;default: 1'h0 ; */
#define TIMG_T0_UPDATE (BIT(31))
#define TIMG_T0_UPDATE_M (BIT(31))
#define TIMG_T0_UPDATE_V 0x1
#define TIMG_T0_UPDATE_S 31
#define TIMG_T0ALARMLO_REG(i) (REG_TIMG_BASE(i) + 0x0010)
/* TIMG_T0_ALARM_LO : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
#define TIMG_T0_ALARM_LO 0xFFFFFFFF
#define TIMG_T0_ALARM_LO_M ((TIMG_T0_ALARM_LO_V)<<(TIMG_T0_ALARM_LO_S))
#define TIMG_T0_ALARM_LO_V 0xFFFFFFFF
#define TIMG_T0_ALARM_LO_S 0
#define TIMG_T0ALARMHI_REG(i) (REG_TIMG_BASE(i) + 0x0014)
/* TIMG_T0_ALARM_HI : R/W ;bitpos:[21:0] ;default: 22'h0 ; */
#define TIMG_T0_ALARM_HI 0x003FFFFF
#define TIMG_T0_ALARM_HI_M ((TIMG_T0_ALARM_HI_V)<<(TIMG_T0_ALARM_HI_S))
#define TIMG_T0_ALARM_HI_V 0x3FFFFF
#define TIMG_T0_ALARM_HI_S 0
#define TIMG_T0LOADLO_REG(i) (REG_TIMG_BASE(i) + 0x0018)
/* TIMG_T0_LOAD_LO : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
#define TIMG_T0_LOAD_LO 0xFFFFFFFF
#define TIMG_T0_LOAD_LO_M ((TIMG_T0_LOAD_LO_V)<<(TIMG_T0_LOAD_LO_S))
#define TIMG_T0_LOAD_LO_V 0xFFFFFFFF
#define TIMG_T0_LOAD_LO_S 0
#define TIMG_T0LOADHI_REG(i) (REG_TIMG_BASE(i) + 0x001c)
/* TIMG_T0_LOAD_HI : R/W ;bitpos:[21:0] ;default: 22'h0 ; */
#define TIMG_T0_LOAD_HI 0x003FFFFF
#define TIMG_T0_LOAD_HI_M ((TIMG_T0_LOAD_HI_V)<<(TIMG_T0_LOAD_HI_S))
#define TIMG_T0_LOAD_HI_V 0x3FFFFF
#define TIMG_T0_LOAD_HI_S 0
#define TIMG_T0LOAD_REG(i) (REG_TIMG_BASE(i) + 0x0020)
/* TIMG_T0_LOAD : WT ;bitpos:[31:0] ;default: 32'h0 ; */
#define TIMG_T0_LOAD 0xFFFFFFFF
#define TIMG_T0_LOAD_M ((TIMG_T0_LOAD_V)<<(TIMG_T0_LOAD_S))
#define TIMG_T0_LOAD_V 0xFFFFFFFF
#define TIMG_T0_LOAD_S 0
#define TIMG_WDTCONFIG0_REG(i) (REG_TIMG_BASE(i) + 0x0048)
/* TIMG_WDT_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
#define TIMG_WDT_EN (BIT(31))
#define TIMG_WDT_EN_M (BIT(31))
#define TIMG_WDT_EN_V 0x1
#define TIMG_WDT_EN_S 31
/* TIMG_WDT_STG0 : R/W ;bitpos:[30:29] ;default: 2'd0 ; */
#define TIMG_WDT_STG0 0x00000003
#define TIMG_WDT_STG0_M ((TIMG_WDT_STG0_V)<<(TIMG_WDT_STG0_S))
#define TIMG_WDT_STG0_V 0x3
#define TIMG_WDT_STG0_S 29
/* TIMG_WDT_STG1 : R/W ;bitpos:[28:27] ;default: 2'd0 ; */
#define TIMG_WDT_STG1 0x00000003
#define TIMG_WDT_STG1_M ((TIMG_WDT_STG1_V)<<(TIMG_WDT_STG1_S))
#define TIMG_WDT_STG1_V 0x3
#define TIMG_WDT_STG1_S 27
/* TIMG_WDT_STG2 : R/W ;bitpos:[26:25] ;default: 2'd0 ; */
#define TIMG_WDT_STG2 0x00000003
#define TIMG_WDT_STG2_M ((TIMG_WDT_STG2_V)<<(TIMG_WDT_STG2_S))
#define TIMG_WDT_STG2_V 0x3
#define TIMG_WDT_STG2_S 25
/* TIMG_WDT_STG3 : R/W ;bitpos:[24:23] ;default: 2'd0 ; */
#define TIMG_WDT_STG3 0x00000003
#define TIMG_WDT_STG3_M ((TIMG_WDT_STG3_V)<<(TIMG_WDT_STG3_S))
#define TIMG_WDT_STG3_V 0x3
#define TIMG_WDT_STG3_S 23
/* TIMG_WDT_CONF_UPDATE_EN : WT ;bitpos:[22] ;default: 1'h0 ; */
#define TIMG_WDT_CONF_UPDATE_EN (BIT(22))
#define TIMG_WDT_CONF_UPDATE_EN_M (BIT(22))
#define TIMG_WDT_CONF_UPDATE_EN_V 0x1
#define TIMG_WDT_CONF_UPDATE_EN_S 22
/* TIMG_WDT_USE_XTAL : R/W ;bitpos:[21] ;default: 1'h0 ; */
#define TIMG_WDT_USE_XTAL (BIT(21))
#define TIMG_WDT_USE_XTAL_M (BIT(21))
#define TIMG_WDT_USE_XTAL_V 0x1
#define TIMG_WDT_USE_XTAL_S 21
/* TIMG_WDT_CPU_RESET_LENGTH : R/W ;bitpos:[20:18] ;default: 3'h1 ; */
#define TIMG_WDT_CPU_RESET_LENGTH 0x00000007
#define TIMG_WDT_CPU_RESET_LENGTH_M ((TIMG_WDT_CPU_RESET_LENGTH_V)<<(TIMG_WDT_CPU_RESET_LENGTH_S))
#define TIMG_WDT_CPU_RESET_LENGTH_V 0x7
#define TIMG_WDT_CPU_RESET_LENGTH_S 18
/* TIMG_WDT_SYS_RESET_LENGTH : R/W ;bitpos:[17:15] ;default: 3'h1 ; */
#define TIMG_WDT_SYS_RESET_LENGTH 0x00000007
#define TIMG_WDT_SYS_RESET_LENGTH_M ((TIMG_WDT_SYS_RESET_LENGTH_V)<<(TIMG_WDT_SYS_RESET_LENGTH_S))
#define TIMG_WDT_SYS_RESET_LENGTH_V 0x7
#define TIMG_WDT_SYS_RESET_LENGTH_S 15
/* TIMG_WDT_FLASHBOOT_MOD_EN : R/W ;bitpos:[14] ;default: 1'h1 ; */
#define TIMG_WDT_FLASHBOOT_MOD_EN (BIT(14))
#define TIMG_WDT_FLASHBOOT_MOD_EN_M (BIT(14))
#define TIMG_WDT_FLASHBOOT_MOD_EN_V 0x1
#define TIMG_WDT_FLASHBOOT_MOD_EN_S 14
/* TIMG_WDT_PROCPU_RESET_EN : R/W ;bitpos:[13] ;default: 1'd0 ; */
#define TIMG_WDT_PROCPU_RESET_EN (BIT(13))
#define TIMG_WDT_PROCPU_RESET_EN_M (BIT(13))
#define TIMG_WDT_PROCPU_RESET_EN_V 0x1
#define TIMG_WDT_PROCPU_RESET_EN_S 13
/* TIMG_WDT_APPCPU_RESET_EN : R/W ;bitpos:[12] ;default: 1'd0 ; */
#define TIMG_WDT_APPCPU_RESET_EN (BIT(12))
#define TIMG_WDT_APPCPU_RESET_EN_M (BIT(12))
#define TIMG_WDT_APPCPU_RESET_EN_V 0x1
#define TIMG_WDT_APPCPU_RESET_EN_S 12
#define TIMG_WDTCONFIG1_REG(i) (REG_TIMG_BASE(i) + 0x004c)
/* TIMG_WDT_CLK_PRESCALE : R/W ;bitpos:[31:16] ;default: 16'h1 ; */
#define TIMG_WDT_CLK_PRESCALE 0x0000FFFF
#define TIMG_WDT_CLK_PRESCALE_M ((TIMG_WDT_CLK_PRESCALE_V)<<(TIMG_WDT_CLK_PRESCALE_S))
#define TIMG_WDT_CLK_PRESCALE_V 0xFFFF
#define TIMG_WDT_CLK_PRESCALE_S 16
/* TIMG_WDT_DIVCNT_RST : WT ;bitpos:[0] ;default: 1'b0 ; */
#define TIMG_WDT_DIVCNT_RST (BIT(0))
#define TIMG_WDT_DIVCNT_RST_M (BIT(0))
#define TIMG_WDT_DIVCNT_RST_V 0x1
#define TIMG_WDT_DIVCNT_RST_S 0
#define TIMG_WDTCONFIG2_REG(i) (REG_TIMG_BASE(i) + 0x0050)
/* TIMG_WDT_STG0_HOLD : R/W ;bitpos:[31:0] ;default: 32'd26000000 ; */
#define TIMG_WDT_STG0_HOLD 0xFFFFFFFF
#define TIMG_WDT_STG0_HOLD_M ((TIMG_WDT_STG0_HOLD_V)<<(TIMG_WDT_STG0_HOLD_S))
#define TIMG_WDT_STG0_HOLD_V 0xFFFFFFFF
#define TIMG_WDT_STG0_HOLD_S 0
#define TIMG_WDTCONFIG3_REG(i) (REG_TIMG_BASE(i) + 0x0054)
/* TIMG_WDT_STG1_HOLD : R/W ;bitpos:[31:0] ;default: 32'h7ffffff ; */
#define TIMG_WDT_STG1_HOLD 0xFFFFFFFF
#define TIMG_WDT_STG1_HOLD_M ((TIMG_WDT_STG1_HOLD_V)<<(TIMG_WDT_STG1_HOLD_S))
#define TIMG_WDT_STG1_HOLD_V 0xFFFFFFFF
#define TIMG_WDT_STG1_HOLD_S 0
#define TIMG_WDTCONFIG4_REG(i) (REG_TIMG_BASE(i) + 0x0058)
/* TIMG_WDT_STG2_HOLD : R/W ;bitpos:[31:0] ;default: 32'hfffff ; */
#define TIMG_WDT_STG2_HOLD 0xFFFFFFFF
#define TIMG_WDT_STG2_HOLD_M ((TIMG_WDT_STG2_HOLD_V)<<(TIMG_WDT_STG2_HOLD_S))
#define TIMG_WDT_STG2_HOLD_V 0xFFFFFFFF
#define TIMG_WDT_STG2_HOLD_S 0
#define TIMG_WDTCONFIG5_REG(i) (REG_TIMG_BASE(i) + 0x005c)
/* TIMG_WDT_STG3_HOLD : R/W ;bitpos:[31:0] ;default: 32'hfffff ; */
#define TIMG_WDT_STG3_HOLD 0xFFFFFFFF
#define TIMG_WDT_STG3_HOLD_M ((TIMG_WDT_STG3_HOLD_V)<<(TIMG_WDT_STG3_HOLD_S))
#define TIMG_WDT_STG3_HOLD_V 0xFFFFFFFF
#define TIMG_WDT_STG3_HOLD_S 0
#define TIMG_WDTFEED_REG(i) (REG_TIMG_BASE(i) + 0x0060)
/* TIMG_WDT_FEED : WT ;bitpos:[31:0] ;default: 32'h0 ; */
#define TIMG_WDT_FEED 0xFFFFFFFF
#define TIMG_WDT_FEED_M ((TIMG_WDT_FEED_V)<<(TIMG_WDT_FEED_S))
#define TIMG_WDT_FEED_V 0xFFFFFFFF
#define TIMG_WDT_FEED_S 0
#define TIMG_WDTWPROTECT_REG(i) (REG_TIMG_BASE(i) + 0x0064)
/* TIMG_WDT_WKEY : R/W ;bitpos:[31:0] ;default: 32'h50d83aa1 ; */
#define TIMG_WDT_WKEY 0xFFFFFFFF
#define TIMG_WDT_WKEY_M ((TIMG_WDT_WKEY_V)<<(TIMG_WDT_WKEY_S))
#define TIMG_WDT_WKEY_V 0xFFFFFFFF
#define TIMG_WDT_WKEY_S 0
#define TIMG_RTCCALICFG_REG(i) (REG_TIMG_BASE(i) + 0x0068)
/* TIMG_RTC_CALI_START : R/W ;bitpos:[31] ;default: 1'h0 ; */
#define TIMG_RTC_CALI_START (BIT(31))
#define TIMG_RTC_CALI_START_M (BIT(31))
#define TIMG_RTC_CALI_START_V 0x1
#define TIMG_RTC_CALI_START_S 31
/* TIMG_RTC_CALI_MAX : R/W ;bitpos:[30:16] ;default: 15'h1 ; */
#define TIMG_RTC_CALI_MAX 0x00007FFF
#define TIMG_RTC_CALI_MAX_M ((TIMG_RTC_CALI_MAX_V)<<(TIMG_RTC_CALI_MAX_S))
#define TIMG_RTC_CALI_MAX_V 0x7FFF
#define TIMG_RTC_CALI_MAX_S 16
/* TIMG_RTC_CALI_RDY : RO ;bitpos:[15] ;default: 1'h0 ; */
#define TIMG_RTC_CALI_RDY (BIT(15))
#define TIMG_RTC_CALI_RDY_M (BIT(15))
#define TIMG_RTC_CALI_RDY_V 0x1
#define TIMG_RTC_CALI_RDY_S 15
/* TIMG_RTC_CALI_CLK_SEL : R/W ;bitpos:[14:13] ;default: 2'h1 ; */
#define TIMG_RTC_CALI_CLK_SEL 0x00000003
#define TIMG_RTC_CALI_CLK_SEL_M ((TIMG_RTC_CALI_CLK_SEL_V)<<(TIMG_RTC_CALI_CLK_SEL_S))
#define TIMG_RTC_CALI_CLK_SEL_V 0x3
#define TIMG_RTC_CALI_CLK_SEL_S 13
/* TIMG_RTC_CALI_START_CYCLING : R/W ;bitpos:[12] ;default: 1'd1 ; */
#define TIMG_RTC_CALI_START_CYCLING (BIT(12))
#define TIMG_RTC_CALI_START_CYCLING_M (BIT(12))
#define TIMG_RTC_CALI_START_CYCLING_V 0x1
#define TIMG_RTC_CALI_START_CYCLING_S 12
#define TIMG_RTCCALICFG1_REG(i) (REG_TIMG_BASE(i) + 0x006c)
/* TIMG_RTC_CALI_VALUE : RO ;bitpos:[31:7] ;default: 25'h0 ; */
#define TIMG_RTC_CALI_VALUE 0x01FFFFFF
#define TIMG_RTC_CALI_VALUE_M ((TIMG_RTC_CALI_VALUE_V)<<(TIMG_RTC_CALI_VALUE_S))
#define TIMG_RTC_CALI_VALUE_V 0x1FFFFFF
#define TIMG_RTC_CALI_VALUE_S 7
/* TIMG_RTC_CALI_CYCLING_DATA_VLD : RO ;bitpos:[0] ;default: 1'b0 ; */
#define TIMG_RTC_CALI_CYCLING_DATA_VLD (BIT(0))
#define TIMG_RTC_CALI_CYCLING_DATA_VLD_M (BIT(0))
#define TIMG_RTC_CALI_CYCLING_DATA_VLD_V 0x1
#define TIMG_RTC_CALI_CYCLING_DATA_VLD_S 0
#define TIMG_INT_ENA_TIMERS_REG(i) (REG_TIMG_BASE(i) + 0x0070)
/* TIMG_WDT_INT_ENA : R/W ;bitpos:[1] ;default: 1'h0 ; */
#define TIMG_WDT_INT_ENA (BIT(1))
#define TIMG_WDT_INT_ENA_M (BIT(1))
#define TIMG_WDT_INT_ENA_V 0x1
#define TIMG_WDT_INT_ENA_S 1
/* TIMG_T0_INT_ENA : R/W ;bitpos:[0] ;default: 1'h0 ; */
#define TIMG_T0_INT_ENA (BIT(0))
#define TIMG_T0_INT_ENA_M (BIT(0))
#define TIMG_T0_INT_ENA_V 0x1
#define TIMG_T0_INT_ENA_S 0
#define TIMG_INT_RAW_TIMERS_REG(i) (REG_TIMG_BASE(i) + 0x0074)
/* TIMG_WDT_INT_RAW : R/SS/WTC ;bitpos:[1] ;default: 1'h0 ; */
#define TIMG_WDT_INT_RAW (BIT(1))
#define TIMG_WDT_INT_RAW_M (BIT(1))
#define TIMG_WDT_INT_RAW_V 0x1
#define TIMG_WDT_INT_RAW_S 1
/* TIMG_T0_INT_RAW : R/SS/WTC ;bitpos:[0] ;default: 1'h0 ; */
#define TIMG_T0_INT_RAW (BIT(0))
#define TIMG_T0_INT_RAW_M (BIT(0))
#define TIMG_T0_INT_RAW_V 0x1
#define TIMG_T0_INT_RAW_S 0
#define TIMG_INT_ST_TIMERS_REG(i) (REG_TIMG_BASE(i) + 0x0078)
/* TIMG_WDT_INT_ST : RO ;bitpos:[1] ;default: 1'h0 ; */
#define TIMG_WDT_INT_ST (BIT(1))
#define TIMG_WDT_INT_ST_M (BIT(1))
#define TIMG_WDT_INT_ST_V 0x1
#define TIMG_WDT_INT_ST_S 1
/* TIMG_T0_INT_ST : RO ;bitpos:[0] ;default: 1'h0 ; */
#define TIMG_T0_INT_ST (BIT(0))
#define TIMG_T0_INT_ST_M (BIT(0))
#define TIMG_T0_INT_ST_V 0x1
#define TIMG_T0_INT_ST_S 0
#define TIMG_INT_CLR_TIMERS_REG(i) (REG_TIMG_BASE(i) + 0x007c)
/* TIMG_WDT_INT_CLR : WT ;bitpos:[1] ;default: 1'h0 ; */
#define TIMG_WDT_INT_CLR (BIT(1))
#define TIMG_WDT_INT_CLR_M (BIT(1))
#define TIMG_WDT_INT_CLR_V 0x1
#define TIMG_WDT_INT_CLR_S 1
/* TIMG_T0_INT_CLR : WT ;bitpos:[0] ;default: 1'h0 ; */
#define TIMG_T0_INT_CLR (BIT(0))
#define TIMG_T0_INT_CLR_M (BIT(0))
#define TIMG_T0_INT_CLR_V 0x1
#define TIMG_T0_INT_CLR_S 0
#define TIMG_RTCCALICFG2_REG(i) (REG_TIMG_BASE(i) + 0x0080)
/* TIMG_RTC_CALI_TIMEOUT_THRES : R/W ;bitpos:[31:7] ;default: 25'h1ffffff ; */
/* description: timeout if cali value counts over threshold */
#define TIMG_RTC_CALI_TIMEOUT_THRES 0x01FFFFFF
#define TIMG_RTC_CALI_TIMEOUT_THRES_M ((TIMG_RTC_CALI_TIMEOUT_THRES_V)<<(TIMG_RTC_CALI_TIMEOUT_THRES_S))
#define TIMG_RTC_CALI_TIMEOUT_THRES_V 0x1FFFFFF
#define TIMG_RTC_CALI_TIMEOUT_THRES_S 7
/* TIMG_RTC_CALI_TIMEOUT_RST_CNT : R/W ;bitpos:[6:3] ;default: 4'd3 ; */
/* description: Cycles that release calibration timeout reset */
#define TIMG_RTC_CALI_TIMEOUT_RST_CNT 0x0000000F
#define TIMG_RTC_CALI_TIMEOUT_RST_CNT_M ((TIMG_RTC_CALI_TIMEOUT_RST_CNT_V)<<(TIMG_RTC_CALI_TIMEOUT_RST_CNT_S))
#define TIMG_RTC_CALI_TIMEOUT_RST_CNT_V 0xF
#define TIMG_RTC_CALI_TIMEOUT_RST_CNT_S 3
/* TIMG_RTC_CALI_TIMEOUT : RO ;bitpos:[0] ;default: 1'h0 ; */
/* description: timeout indicator */
#define TIMG_RTC_CALI_TIMEOUT (BIT(0))
#define TIMG_RTC_CALI_TIMEOUT_M (BIT(0))
#define TIMG_RTC_CALI_TIMEOUT_V 0x1
#define TIMG_RTC_CALI_TIMEOUT_S 0
#define TIMG_NTIMERS_DATE_REG(i) (REG_TIMG_BASE(i) + 0x00f8)
/* TIMG_NTIMERS_DATE : R/W ;bitpos:[27:0] ;default: 28'h2006191 ; */
#define TIMG_NTIMERS_DATE 0x0FFFFFFF
#define TIMG_NTIMERS_DATE_M ((TIMG_NTIMERS_DATE_V)<<(TIMG_NTIMERS_DATE_S))
#define TIMG_NTIMERS_DATE_V 0xFFFFFFF
#define TIMG_NTIMERS_DATE_S 0
#define TIMG_CLK_REG(i) (REG_TIMG_BASE(i) + 0x00fc)
/* TIMG_CLK_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
#define TIMG_CLK_EN (BIT(31))
#define TIMG_CLK_EN_M (BIT(31))
#define TIMG_CLK_EN_V 0x1
#define TIMG_CLK_EN_S 31
/* TIMG_TIMER_CLK_IS_ACTIVE : R/W ;bitpos:[30] ;default: 1'h1 ; */
#define TIMG_TIMER_CLK_IS_ACTIVE (BIT(30))
#define TIMG_TIMER_CLK_IS_ACTIVE_M (BIT(30))
#define TIMG_TIMER_CLK_IS_ACTIVE_V 0x1
#define TIMG_TIMER_CLK_IS_ACTIVE_S 30
/* TIMG_WDT_CLK_IS_ACTIVE : R/W ;bitpos:[29] ;default: 1'h1 ; */
#define TIMG_WDT_CLK_IS_ACTIVE (BIT(29))
#define TIMG_WDT_CLK_IS_ACTIVE_M (BIT(29))
#define TIMG_WDT_CLK_IS_ACTIVE_V 0x1
#define TIMG_WDT_CLK_IS_ACTIVE_S 29
#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_TIM_H */

View File

@ -96,6 +96,33 @@ Configurations
The pin is configured as a rising edge interrupt, so after issuing the
above command, connect it to 3.3V.
watchdog
--------
This configuration tests the watchdog timers. It includes the 2 MWDTS,
adds driver support, registers the WDTs as devices and includes the watchdog
example application.
To test it, just run the following command:
`nsh> wdog -i /dev/watchdogX`
Where X ix the watchdog instance.
watcher
-------
This configuration tests the watchdog timers in the capture mode.
It includes the 2 MWDTS, adds driver support, registers the WDTs as devices
and includes the watcher and watched example applications.
To test it, just run the following command:
```
nsh> watcher
nsh> watched
```
Building and flashing
=====================

View File

@ -0,0 +1,48 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_CMDPARMS is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c3-devkit"
CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
CONFIG_ARCH_CHIP="esp32c3"
CONFIG_ARCH_CHIP_ESP32C3=y
CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
CONFIG_ARCH_INTERRUPTSTACK=1536
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESP32C3_MWDT0=y
CONFIG_ESP32C3_MWDT1=y
CONFIG_EXAMPLES_WATCHDOG=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_MAX_TASKS=8
CONFIG_NFILE_DESCRIPTORS=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_NSH=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WATCHDOG=y

View File

@ -0,0 +1,51 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_CMDPARMS is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c3-devkit"
CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
CONFIG_ARCH_CHIP="esp32c3"
CONFIG_ARCH_CHIP_ESP32C3=y
CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
CONFIG_ARCH_INTERRUPTSTACK=1536
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_DRIVER_NOTE=y
CONFIG_ESP32C3_MWDT0=y
CONFIG_ESP32C3_MWDT1=y
CONFIG_EXAMPLES_WATCHER=y
CONFIG_FS_FAT=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_MAX_TASKS=8
CONFIG_NFILE_DESCRIPTORS=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_INSTRUMENTATION=y
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_NSH=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WATCHDOG=y

View File

@ -34,6 +34,10 @@ ifeq ($(CONFIG_DEV_GPIO),y)
CSRCS += esp32c3_gpio.c
endif
ifeq ($(CONFIG_WATCHDOG),y)
CSRCS += esp32c3_wdt.c
endif
SCRIPTIN = $(SCRIPTDIR)$(DELIM)esp32c3.template.ld
SCRIPTOUT = $(SCRIPTDIR)$(DELIM)esp32c3_out.ld

View File

@ -25,9 +25,7 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
@ -71,5 +69,21 @@ int esp32c3_bringup(void);
int esp32c3_gpio_init(void);
#endif
/****************************************************************************
* Name: board_wdt_init
*
* Description:
* Configure the timer driver.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_WATCHDOG
int board_wdt_init(void);
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_RISCV_ESP32C3_ESP32C3_DEVKIT_SRC_ESP32C3_DEVKIT_H */

View File

@ -22,15 +22,6 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
#include "esp32c3-devkit.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

View File

@ -85,6 +85,18 @@ int esp32c3_bringup(void)
}
#endif
#ifdef CONFIG_WATCHDOG
/* Configure watchdog timer */
ret = board_wdt_init();
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: Failed to initialize watchdog drivers: %d\n",
ret);
}
#endif
/* If we got here then perhaps not all initialization was successful, but
* at least enough succeeded to bring-up NSH with perhaps reduced
* capabilities.

View File

@ -0,0 +1,94 @@
/****************************************************************************
* boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_wdt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <debug.h>
#include "esp32c3_wdt_lowerhalf.h"
#include "esp32c3_wdt.h"
#include "esp32c3-devkit.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_wdt_init
*
* Description:
* Configure the watchdog timer driver.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int board_wdt_init(void)
{
int ret = OK;
#ifdef CONFIG_ESP32C3_MWDT0
ret = esp32c3_wdt_initialize("/dev/watchdog0", ESP32C3_WDT_MWDT0);
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: Failed to initialize watchdog driver: %d\n",
ret);
return ret;
}
#endif /* CONFIG_ESP32C3_MWDT0 */
#ifdef CONFIG_ESP32C3_MWDT1
ret = esp32c3_wdt_initialize("/dev/watchdog1", ESP32C3_WDT_MWDT1);
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: Failed to initialize watchdog driver: %d\n",
ret);
return ret;
}
#endif /* CONFIG_ESP32C3_MWDT1 */
#ifdef CONFIG_ESP32C3_RWDT
ret = esp32c3_wdt_initialize("/dev/watchdog2", ESP32C3_WDT_RWDT);
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: Failed to initialize watchdog driver: %d\n",
ret);
return ret;
}
#endif /* CONFIG_ESP32C3_RWDT */
return ret;
}