refactor(hal): graduate systimer hal driver into esp_hal_systimer

This commit is contained in:
Chen Chen
2026-01-28 17:15:49 +08:00
parent 41f15f5329
commit eeb24057c4
93 changed files with 1006 additions and 1006 deletions

View File

@@ -0,0 +1,7 @@
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
components/esp_hal_systimer/test_apps/systimer_rom_impl:
disable:
- if: SOC_SYSTIMER_SUPPORTED != 1
depends_components:
- esp_hal_systimer

View File

@@ -0,0 +1,29 @@
idf_build_get_property(target IDF_TARGET)
set(srcs)
set(public_include "include")
if(CONFIG_SOC_SYSTIMER_SUPPORTED)
list(APPEND public_include "${target}/include")
endif()
if(CONFIG_SOC_SYSTIMER_SUPPORTED)
if(CONFIG_HAL_SYSTIMER_USE_ROM_IMPL)
list(APPEND srcs "rom_patch.c")
# ESP32C2 revision < 2.0 needs additional ROM patches
if(CONFIG_IDF_TARGET_ESP32C2 AND (CONFIG_ESP32C2_REV_MIN_FULL LESS 200))
list(APPEND srcs "esp32c2/rom_patch_rev1.c")
endif()
else()
list(APPEND srcs "systimer_hal.c")
endif()
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${public_include}
REQUIRES soc hal esp_rom
LDFRAGMENTS linker.lf)
# Link the ROM SYSTIMER HAL implementation linker script if selected
if(CONFIG_HAL_SYSTIMER_USE_ROM_IMPL)
target_linker_script(${COMPONENT_LIB} INTERFACE "${target}/rom.systimer.ld")
endif()

View File

@@ -0,0 +1,12 @@
config HAL_SYSTIMER_USE_ROM_IMPL
bool "Use ROM implementation of SysTimer HAL driver"
depends on ESP_ROM_HAS_HAL_SYSTIMER
default y
help
Enable this flag to use HAL functions from ROM instead of ESP-IDF.
If keeping this as "n" in your project, you will have less free IRAM.
If making this as "y" in your project, you will increase free IRAM,
but you will lose the possibility to debug this module, and some new
features will be added and bugs will be fixed in the IDF source
but cannot be synced to ROM.

View File

@@ -0,0 +1,62 @@
# ESP Hardware Abstraction Layer for System Timer Peripheral
> [!NOTE]
> This component is currently in beta. Its API, behavior, and compatibility may change at any time and without notice; backward compatibility is not guaranteed. Use caution when integrating into production systems.
## Overview
The ESP Hardware Abstraction Layer for System Timer Peripheral (`esp_hal_systimer`) provides a unified interface to interact with the system timer (SYSTIMER) peripheral across all ESP chip families. This component abstracts the hardware-specific details of different SYSTIMER implementations, enabling consistent usage patterns regardless of the underlying hardware.
The SYSTIMER is a high-resolution timer used for:
- System time tracking
- FreeRTOS tick generation
- High-precision timing operations
- Event timer (ETM) trigger generation
## Architecture
The HAL architecture consists of two primary layers:
1. **HAL Layer (Upper)**: Defines the operational sequences and data structures required to interact with the SYSTIMER peripheral, including:
- Initialization and de-initialization functions
- Counter value operations
- Alarm configuration and management
- Time conversion utilities
- Clock source configuration
2. **Low-Level Layer (Bottom)**: Acts as a translation layer between the HAL and the register definitions in the `soc` component, handling:
- Register access abstractions
- Chip-specific register configurations
- Hardware feature compatibility
- Clock and prescaler settings
## Features
- Unified SYSTIMER interface across all ESP chip families
- Support for multiple counters and alarms
- High-resolution timing (typically 16MHz resolution)
- Flexible clock source configuration
- ETM (Event Timer Module) support where available
- Platform-specific optimizations
- IRAM-safe implementation for critical sections
- ROM implementation support for certain chips
- Chip-specific implementations contained in separate directories
## Usage
This component is primarily used by ESP-IDF system services such as:
- **esp_timer**: High-resolution timer implementation
- **FreeRTOS**: System tick generation
- **esp_hw_support**: System time and clock management
For advanced developers implementing custom timing solutions, the HAL functions can be used directly. However, please note that the interfaces provided by this component are internal to ESP-IDF and are subject to change.
## Dependencies
- `soc`: Provides chip-specific register definitions
- `hal`: Core hardware abstraction utilities and macros
- `esp_rom`: ROM function interfaces (when using ROM implementation)
## ROM Implementation
Some chips support using ROM-based SYSTIMER HAL implementations for reduced code size. This is controlled by the `CONFIG_HAL_SYSTIMER_USE_ROM_IMPL` configuration option. When enabled, the component uses ROM linker scripts to link against ROM functions instead of compiling the HAL implementation.

View File

@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/system_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
(void)clk_src;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
SYSTEM.perip_clk_en0.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
SYSTEM.perip_rst_en0.systimer_rst = 1;
SYSTEM.perip_rst_en0.systimer_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
PROVIDE( systimer_hal_get_counter_value = 0x400002ac );
PROVIDE( systimer_hal_get_alarm_value = 0x400002bc );
PROVIDE( systimer_hal_enable_alarm_int = 0x400002c0 );
PROVIDE( systimer_hal_enable_counter = 0x400002cc );
PROVIDE( systimer_hal_select_alarm_mode = 0x400002d0 );
PROVIDE( systimer_hal_connect_alarm_counter = 0x400002d4 );
PROVIDE( systimer_hal_counter_can_stall_by_cpu = 0x400002d8 );
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* PROVIDE( systimer_hal_init = 0x400002a8 ); */
/* PROVIDE( systimer_hal_get_time = 0x400002b0 ); */
/* PROVIDE( systimer_hal_set_alarm_target = 0x400002b4 ); */
/* PROVIDE( systimer_hal_set_alarm_period = 0x400002b8 ); */
/* PROVIDE( systimer_hal_counter_value_advance = 0x400002c8 ); */

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief ROM patch for ESP32C2 revision < 2.0
*
* ESP32C2 early revisions (< 2.0) have incomplete systimer HAL implementations in ROM.
* The ROM provides only basic functions (get_counter_value, get_alarm_value, etc.),
* while the following functions need to be patched in flash:
* - systimer_hal_init
* - systimer_hal_deinit
* - systimer_hal_set_tick_rate_ops
* - systimer_hal_get_time
* - systimer_hal_set_alarm_target
* - systimer_hal_set_alarm_period
* - systimer_hal_counter_value_advance
*/
#include <stddef.h>
#include "hal/systimer_hal.h"
#include "hal/systimer_ll.h"
void systimer_hal_init(systimer_hal_context_t *hal)
{
hal->dev = &SYSTIMER;
systimer_ll_enable_clock(hal->dev, true);
}
void systimer_hal_deinit(systimer_hal_context_t *hal)
{
systimer_ll_enable_clock(hal->dev, false);
hal->dev = NULL;
}
void systimer_hal_set_tick_rate_ops(systimer_hal_context_t *hal, systimer_hal_tick_rate_ops_t *ops)
{
hal->ticks_to_us = ops->ticks_to_us;
hal->us_to_ticks = ops->us_to_ticks;
}
uint64_t systimer_hal_get_time(systimer_hal_context_t *hal, uint32_t counter_id)
{
return hal->ticks_to_us(systimer_hal_get_counter_value(hal, counter_id));
}
void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t target)
{
systimer_counter_value_t alarm = {
.val = hal->us_to_ticks(target),
};
systimer_ll_enable_alarm(hal->dev, alarm_id, false);
systimer_ll_set_alarm_target(hal->dev, alarm_id, alarm.val);
systimer_ll_apply_alarm_value(hal->dev, alarm_id);
systimer_ll_enable_alarm(hal->dev, alarm_id, true);
}
void systimer_hal_set_alarm_period(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t period)
{
systimer_ll_enable_alarm(hal->dev, alarm_id, false);
systimer_ll_set_alarm_period(hal->dev, alarm_id, hal->us_to_ticks(period));
systimer_ll_apply_alarm_value(hal->dev, alarm_id);
systimer_ll_enable_alarm(hal->dev, alarm_id, true);
}
void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t counter_id, int64_t time_us)
{
systimer_counter_value_t new_count = {
.val = systimer_hal_get_counter_value(hal, counter_id) + hal->us_to_ticks(time_us),
};
systimer_ll_set_counter_value(hal->dev, counter_id, new_count.val);
systimer_ll_apply_counter_value(hal->dev, counter_id);
}

View File

@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/system_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
(void)clk_src;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
SYSTEM.perip_clk_en0.reg_systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
SYSTEM.perip_rst_en0.reg_systimer_rst = 1;
SYSTEM.perip_rst_en0.reg_systimer_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x400003d0; */
/* systimer_hal_deinit = 0x400003d4; */
systimer_hal_set_tick_rate_ops = 0x400003d8;
systimer_hal_get_counter_value = 0x400003dc;
systimer_hal_get_time = 0x400003e0;
systimer_hal_set_alarm_target = 0x400003e4;
systimer_hal_set_alarm_period = 0x400003e8;
systimer_hal_get_alarm_value = 0x400003ec;
systimer_hal_enable_alarm_int = 0x400003f0;
systimer_hal_on_apb_freq_update = 0x400003f4;
systimer_hal_counter_value_advance = 0x400003f8;
systimer_hal_enable_counter = 0x400003fc;
systimer_hal_select_alarm_mode = 0x40000400;
systimer_hal_connect_alarm_counter = 0x40000404;
systimer_hal_counter_can_stall_by_cpu = 0x40000408;

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x400003c0; */
/* systimer_hal_deinit = 0x400003c4; */
systimer_hal_set_tick_rate_ops = 0x400003c8;
systimer_hal_get_counter_value = 0x400003cc;
systimer_hal_get_time = 0x400003d0;
systimer_hal_set_alarm_target = 0x400003d4;
systimer_hal_set_alarm_period = 0x400003d8;
systimer_hal_get_alarm_value = 0x400003dc;
systimer_hal_enable_alarm_int = 0x400003e0;
systimer_hal_on_apb_freq_update = 0x400003e4;
systimer_hal_counter_value_advance = 0x400003e8;
systimer_hal_enable_counter = 0x400003ec;
systimer_hal_select_alarm_mode = 0x400003f0;
systimer_hal_connect_alarm_counter = 0x400003f4;
systimer_hal_counter_can_stall_by_cpu = 0x400003f8;

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x400003d0; */
/* systimer_hal_deinit = 0x400003d4; */
systimer_hal_set_tick_rate_ops = 0x400003d8;
systimer_hal_get_counter_value = 0x400003dc;
systimer_hal_get_time = 0x400003e0;
systimer_hal_set_alarm_target = 0x400003e4;
systimer_hal_set_alarm_period = 0x400003e8;
systimer_hal_get_alarm_value = 0x400003ec;
systimer_hal_enable_alarm_int = 0x400003f0;
systimer_hal_on_apb_freq_update = 0x400003f4;
systimer_hal_counter_value_advance = 0x400003f8;
systimer_hal_enable_counter = 0x400003fc;
systimer_hal_select_alarm_mode = 0x40000400;
systimer_hal_connect_alarm_counter = 0x40000404;
systimer_hal_counter_can_stall_by_cpu = 0x40000408;

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed to 2 when clock source is XTAL
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x400003b8; */
/* systimer_hal_deinit = 0x400003bc; */
systimer_hal_set_tick_rate_ops = 0x400003c0;
systimer_hal_get_counter_value = 0x400003c4;
systimer_hal_get_time = 0x400003c8;
systimer_hal_set_alarm_target = 0x400003cc;
systimer_hal_set_alarm_period = 0x400003d0;
systimer_hal_get_alarm_value = 0x400003d4;
systimer_hal_enable_alarm_int = 0x400003d8;
systimer_hal_on_apb_freq_update = 0x400003dc;
systimer_hal_counter_value_advance = 0x400003e0;
systimer_hal_enable_counter = 0x400003e4;
systimer_hal_select_alarm_mode = 0x400003e8;
systimer_hal_connect_alarm_counter = 0x400003ec;
systimer_hal_counter_can_stall_by_cpu = 0x400003f0;

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed to 2 when clock source is XTAL
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x400003b8; */
/* systimer_hal_deinit = 0x400003bc; */
systimer_hal_set_tick_rate_ops = 0x400003c0;
systimer_hal_get_counter_value = 0x400003c4;
systimer_hal_get_time = 0x400003c8;
systimer_hal_set_alarm_target = 0x400003cc;
systimer_hal_set_alarm_period = 0x400003d0;
systimer_hal_get_alarm_value = 0x400003d4;
systimer_hal_enable_alarm_int = 0x400003d8;
systimer_hal_on_apb_freq_update = 0x400003dc;
systimer_hal_counter_value_advance = 0x400003e0;
systimer_hal_enable_counter = 0x400003e4;
systimer_hal_select_alarm_mode = 0x400003e8;
systimer_hal_connect_alarm_counter = 0x400003ec;
systimer_hal_counter_can_stall_by_cpu = 0x400003f0;

View File

@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
PCR.systimer_func_clk_conf.systimer_func_clk_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (PCR.systimer_func_clk_conf.systimer_func_clk_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
PCR.systimer_conf.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
PCR.systimer_conf.systimer_rst_en = 1;
PCR.systimer_conf.systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ROM function interface esp32h4.rom.systimer.ld for esp32h4
*
*
* Generated from ../../rom/target/esp32h4/interface-esp32h4.yml md5sum bb9ee317148d3c5b10610936a3675a65
*
* Compatible with ROM where ECO version equal or greater to 0.
*
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x4000036c; */
/* systimer_hal_deinit = 0x40000370; */
systimer_hal_set_tick_rate_ops = 0x40000374;
systimer_hal_get_counter_value = 0x40000378;
systimer_hal_get_time = 0x4000037c;
systimer_hal_set_alarm_target = 0x40000380;
systimer_hal_set_alarm_period = 0x40000384;
systimer_hal_get_alarm_value = 0x40000388;
systimer_hal_enable_alarm_int = 0x4000038c;
systimer_hal_on_apb_freq_update = 0x40000390;
systimer_hal_counter_value_advance = 0x40000394;
systimer_hal_enable_counter = 0x40000398;
systimer_hal_select_alarm_mode = 0x4000039c;
systimer_hal_connect_alarm_counter = 0x400003a0;
systimer_hal_counter_can_stall_by_cpu = 0x400003a4;

View File

@@ -0,0 +1,225 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "hal/assert.h"
#include "soc/hp_sys_clkrst_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
HP_SYS_CLKRST.peri_clk_ctrl21.reg_systimer_clk_src_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define systimer_ll_set_clock_source(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
systimer_ll_set_clock_source(__VA_ARGS__); \
} while(0)
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (HP_SYS_CLKRST.peri_clk_ctrl21.reg_systimer_clk_src_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
HP_SYS_CLKRST.soc_clk_ctrl2.reg_systimer_apb_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_stimer = 1;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_stimer = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
/* The following ROM functions are commented out because they're patched in the rom_patch.c */
/* systimer_hal_init = 0x4fc00228; */
/* systimer_hal_deinit = 0x4fc0022c; */
systimer_hal_set_tick_rate_ops = 0x4fc00230;
systimer_hal_get_counter_value = 0x4fc00234;
systimer_hal_get_time = 0x4fc00238;
systimer_hal_set_alarm_target = 0x4fc0023c;
systimer_hal_set_alarm_period = 0x4fc00240;
systimer_hal_get_alarm_value = 0x4fc00244;
systimer_hal_enable_alarm_int = 0x4fc00248;
systimer_hal_on_apb_freq_update = 0x4fc0024c;
systimer_hal_counter_value_advance = 0x4fc00250;
systimer_hal_enable_counter = 0x4fc00254;
systimer_hal_select_alarm_mode = 0x4fc00258;
systimer_hal_connect_alarm_counter = 0x4fc0025c;
systimer_hal_counter_can_stall_by_cpu = 0x4fc00260;

View File

@@ -0,0 +1,220 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/system_reg.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 1 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 32 // Bit width of systimer high part
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
(void)clk_src;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
uint32_t reg_val = READ_PERI_REG(DPORT_PERIP_CLK_EN0_REG);
reg_val &= ~DPORT_SYSTIMER_CLK_EN_M;
reg_val |= enable << DPORT_SYSTIMER_CLK_EN_S;
WRITE_PERI_REG(DPORT_PERIP_CLK_EN0_REG, reg_val);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, DPORT_SYSTIMER_RST_M);
WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, 0);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
// ESP32-S2 only has one counter in systimer group
(void)dev;
(void)counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
(void)dev;
(void)counter_id;
(void)cpu_id;
(void)can;
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
(void)counter_id;
dev->update.timer_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
(void)counter_id;
return dev->update.timer_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
(void)counter_id;
dev->load_hi.timer_load_hi = value >> 32;
dev->load_lo.timer_load_lo = value;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->value_lo.timer_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->value_hi.timer_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->load.timer_load = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_step_for_pll(systimer_dev_t *dev, uint32_t step)
{
dev->step.timer_pll_step = step;
}
__attribute__((always_inline)) static inline void systimer_ll_set_step_for_xtal(systimer_dev_t *dev, uint32_t step)
{
dev->step.timer_xtal_step = step;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
// On esp32-s2, counter int the systimer is fixed connectred to other three alarm comparators
(void)dev;
(void)alarm_id;
(void)counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 30));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
(void)dev;
(void)alarm_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
dev->target_conf[alarm_id].target_work_en = en;
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_raw.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/system_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
(void)clk_src;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
SYSTEM.perip_clk_en0.systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
SYSTEM.perip_rst_en0.systimer_rst = 1;
SYSTEM.perip_rst_en0.systimer_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) do { \
(void)__DECLARE_RCC_RC_ATOMIC_ENV; \
systimer_ll_reset_register(__VA_ARGS__); \
} while(0)
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
PROVIDE( systimer_hal_get_counter_value = 0x40000e40 );
PROVIDE( systimer_hal_get_time = 0x40000e4c );
PROVIDE( systimer_hal_set_alarm_target = 0x40000e58 );
PROVIDE( systimer_hal_set_alarm_period = 0x40000e64 );
PROVIDE( systimer_hal_get_alarm_value = 0x40000e70 );
PROVIDE( systimer_hal_enable_alarm_int = 0x40000e7c );
PROVIDE( systimer_hal_on_apb_freq_update = 0x40000e88 );
PROVIDE( systimer_hal_counter_value_advance = 0x40000e94 );
PROVIDE( systimer_hal_enable_counter = 0x40000ea0 );
PROVIDE( systimer_hal_init = 0x40000eac );
PROVIDE( systimer_hal_select_alarm_mode = 0x40000eb8 );
PROVIDE( systimer_hal_connect_alarm_counter = 0x40000ec4 );

View File

@@ -0,0 +1,232 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/systimer_struct.h"
#include "soc/clk_tree_defs.h"
#include "hal/assert.h"
#include "soc/hp_sys_clkrst_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
// TODO: [ESP32S31] IDF-14693
/******************* SYSTIMER LL CAPS *************************/
#define SYSTIMER_LL_COUNTER_NUM 2 // Number of counter units
#define SYSTIMER_LL_ALARM_NUM 3 // Number of alarm units
#define SYSTIMER_LL_BIT_WIDTH_LO 32 // Bit width of systimer low part
#define SYSTIMER_LL_BIT_WIDTH_HI 20 // Bit width of systimer high part
#define SYSTIMER_LL_INT_LEVEL 1 // Systimer peripheral uses level interrupt
#define SYSTIMER_LL_ALARM_MISS_COMPENSATE 1 // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
#define SYSTIMER_LL_FIXED_DIVIDER 1 // Clock source divider is fixed: 2.5
/******************* Clock *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en)
{
dev->conf.clk_en = en;
}
// Set clock source: XTAL(default) or RC_FAST
static inline void systimer_ll_set_clock_source(soc_periph_systimer_clk_src_t clk_src)
{
HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_clk_src_sel = (clk_src == SYSTIMER_CLK_SRC_RC_FAST) ? 1 : 0;
}
static inline soc_periph_systimer_clk_src_t systimer_ll_get_clock_source(void)
{
return (HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_clk_src_sel == 1) ? SYSTIMER_CLK_SRC_RC_FAST : SYSTIMER_CLK_SRC_XTAL;
}
/**
* @brief Enable the sys clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_sys_clock(bool enable)
{
HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_sys_clock(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; systimer_ll_enable_sys_clock(__VA_ARGS__)
/**
* @brief Enable the bus clock for systimer module
*
* @param enable true to enable, false to disable
*/
static inline void systimer_ll_enable_bus_clock(bool enable)
{
HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_apb_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_enable_bus_clock(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; systimer_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the systimer module
*
* @param group_id Group ID
*/
static inline void systimer_ll_reset_register(void)
{
HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_rst_en = 1;
HP_SYS_CLKRST.systimer_ctrl0.reg_systimer_rst_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define systimer_ll_reset_register(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; systimer_ll_reset_register(__VA_ARGS__)
/********************** ETM *****************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_etm(systimer_dev_t *dev, bool en)
{
dev->conf.etm_en = en;
}
/******************* Counter *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (30 - counter_id);
} else {
dev->conf.val &= ~(1 << (30 - counter_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id);
} else {
dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_op[counter_id].timer_unit_update = 1;
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id)
{
return dev->unit_op[counter_id].timer_unit_value_valid;
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value)
{
dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32;
dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id)
{
(void)counter_id;
return dev->unit_val[counter_id].lo.timer_unit_value_lo;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id)
{
(void)counter_id;
return dev->unit_val[counter_id].hi.timer_unit_value_hi;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id)
{
dev->unit_load[counter_id].val = 0x01;
}
/******************* Alarm *************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value)
{
dev->target_val[alarm_id].hi.timer_target_hi = value >> 32;
dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF;
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id)
{
return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo;
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id)
{
dev->target_conf[alarm_id].target_timer_unit_sel = counter_id;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 0;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->target_conf[alarm_id].target_period_mode = 1;
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period)
{
HAL_ASSERT(period < (1 << 26));
dev->target_conf[alarm_id].target_period = period;
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
{
return dev->target_conf[alarm_id].target_period;
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
{
dev->comp_load[alarm_id].val = 0x01;
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->conf.val |= 1 << (24 - alarm_id);
} else {
dev->conf.val &= ~(1 << (24 - alarm_id));
}
}
/******************* Interrupt *************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en)
{
if (en) {
dev->int_ena.val |= 1 << alarm_id;
} else {
dev->int_ena.val &= ~(1 << alarm_id);
}
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id)
{
(void)alarm_id;
return dev->int_st.val & (1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id)
{
(void)alarm_id;
dev->int_clr.val |= 1 << alarm_id;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ROM function interface esp32s31.rom.systimer.ld for esp32s31
*
*
* Generated from ../../rom/target/esp32s31/interface-esp32s31.yml md5sum 0cb775308c66eebf0757e406021ad5be
*
* Compatible with ROM where ECO version equal or greater to 0.
*
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.
*/
/***************************************
Group hal_systimer
***************************************/
/* Functions */
systimer_hal_init = 0x2f800394;
systimer_hal_deinit = 0x2f800398;
systimer_hal_set_tick_rate_ops = 0x2f80039c;
systimer_hal_get_counter_value = 0x2f8003a0;
systimer_hal_get_time = 0x2f8003a4;
systimer_hal_set_alarm_target = 0x2f8003a8;
systimer_hal_set_alarm_period = 0x2f8003ac;
systimer_hal_get_alarm_value = 0x2f8003b0;
systimer_hal_enable_alarm_int = 0x2f8003b4;
systimer_hal_on_apb_freq_update = 0x2f8003b8;
systimer_hal_counter_value_advance = 0x2f8003bc;
systimer_hal_enable_counter = 0x2f8003c0;
systimer_hal_select_alarm_mode = 0x2f8003c4;
systimer_hal_connect_alarm_counter = 0x2f8003c8;
systimer_hal_counter_can_stall_by_cpu = 0x2f8003cc;

View File

@@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "hal/systimer_types.h"
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#if SOC_SYSTIMER_SUPPORTED
#include "hal/systimer_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct systimer_dev_t *systimer_soc_handle_t; // systimer SOC layer handle
// the definitions of the following functions are provided by esp_hw_support component, see esp_hw_support/port/${TARGET}/systimer.c
typedef uint64_t (*ticks_to_us_func_t)(uint64_t ticks); // prototype of function to convert ticks to microseconds
typedef uint64_t (*us_to_ticks_func_t)(uint64_t us); // prototype of function to convert microseconds to ticks
/**
* @brief systimer HAL context structure
*/
typedef struct {
systimer_soc_handle_t dev; /*!< systimer peripheral base address */
ticks_to_us_func_t ticks_to_us; /*!< function to convert ticks to microseconds */
us_to_ticks_func_t us_to_ticks; /*!< function to convert microseconds to ticks */
} systimer_hal_context_t;
/**
* @brief systimer HAL configuration structure
*/
typedef struct {
ticks_to_us_func_t ticks_to_us; /*!< function to convert ticks to microseconds */
us_to_ticks_func_t us_to_ticks; /*!< function to convert microseconds to ticks */
} systimer_hal_tick_rate_ops_t;
/**
* @brief Systimer clock source
*/
typedef soc_periph_systimer_clk_src_t systimer_clock_source_t;
/**
* @brief initialize systimer in HAL layer
*/
void systimer_hal_init(systimer_hal_context_t *hal);
/**
* @brief Deinitialize systimer HAL layer
*/
void systimer_hal_deinit(systimer_hal_context_t *hal);
/**
* @brief Set tick rate operation functions
*/
void systimer_hal_set_tick_rate_ops(systimer_hal_context_t *hal, systimer_hal_tick_rate_ops_t *ops);
/**
* @brief enable systimer counter
*/
void systimer_hal_enable_counter(systimer_hal_context_t *hal, uint32_t counter_id);
/**
* @brief get current counter value
*/
uint64_t systimer_hal_get_counter_value(systimer_hal_context_t *hal, uint32_t counter_id);
/**
* @brief get current time (in microseconds)
*/
uint64_t systimer_hal_get_time(systimer_hal_context_t *hal, uint32_t counter_id);
/*
* @brief set alarm target value (used in one-shot mode)
*/
void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t target);
/**
* @brief set alarm period value (used in period mode)
*/
void systimer_hal_set_alarm_period(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t period);
/**
* @brief get alarm time
*/
uint64_t systimer_hal_get_alarm_value(systimer_hal_context_t *hal, uint32_t alarm_id);
/**
* @brief enable alarm interrupt
*/
void systimer_hal_enable_alarm_int(systimer_hal_context_t *hal, uint32_t alarm_id);
/**
* @brief select alarm mode
*/
void systimer_hal_select_alarm_mode(systimer_hal_context_t *hal, uint32_t alarm_id, systimer_alarm_mode_t mode);
/**
* @brief update systimer step when apb clock gets changed
*/
void systimer_hal_on_apb_freq_update(systimer_hal_context_t *hal, uint32_t apb_ticks_per_us);
/**
* @brief move systimer counter value forward or backward
*/
void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t counter_id, int64_t time_us);
/**
* @brief connect alarm unit to selected counter
*/
void systimer_hal_connect_alarm_counter(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t counter_id);
/**
* @brief set if a counter should be stalled when CPU is halted by the debugger
*/
void systimer_hal_counter_can_stall_by_cpu(systimer_hal_context_t *hal, uint32_t counter_id, uint32_t cpu_id, bool can);
#if !SYSTIMER_LL_FIXED_DIVIDER
/**
* @brief set increase steps for systimer counter on different clock source
*/
void systimer_hal_set_steps_per_tick(systimer_hal_context_t *hal, int clock_source, uint32_t steps);
#endif
/**
* @brief Get Systimer clock source
*/
systimer_clock_source_t systimer_hal_get_clock_source(systimer_hal_context_t *hal);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#include "esp_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief The structure of the counter value in systimer
*
*/
#if SOC_SYSTIMER_SUPPORTED
#include "hal/systimer_ll.h"
typedef struct {
union {
struct {
uint64_t lo : SYSTIMER_LL_BIT_WIDTH_LO; /*!< Low part of counter value */
uint64_t hi : SYSTIMER_LL_BIT_WIDTH_HI; /*!< High part of counter value */
#if (SYSTIMER_LL_BIT_WIDTH_LO + SYSTIMER_LL_BIT_WIDTH_HI) < 64
uint64_t reserved: (64 - (SYSTIMER_LL_BIT_WIDTH_LO + SYSTIMER_LL_BIT_WIDTH_HI));
#endif
};
uint64_t val; /*!< counter value */
};
} systimer_counter_value_t;
/** @cond */
ESP_STATIC_ASSERT(sizeof(systimer_counter_value_t) == 8, "systimer_counter_value_t should occupy 8 bytes in memory");
/** @endcond */
#endif
/**
* @brief systimer alarm mode
*
*/
typedef enum {
SYSTIMER_ALARM_MODE_ONESHOT, /*!< systimer alarm oneshot mode */
SYSTIMER_ALARM_MODE_PERIOD, /*!< systimer alarm period mode */
} systimer_alarm_mode_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,6 @@
[mapping:esp_hal_systimer]
archive: libesp_hal_systimer.a
entries:
if SOC_SYSTIMER_SUPPORTED = y:
# All systimer HAL code must be in IRAM for ISR safety and cache-disabled operation
* (noflash)

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief ROM patch for systimer HAL
*
* Some chips have systimer HAL implementations in ROM that require patches.
* This file provides the necessary patches when ROM implementation is used.
*
* For chips with ESP_ROM_SYSTIMER_INIT_PATCH defined (e.g., ESP32-C5, ESP32-C6,
* ESP32-H2, ESP32-P4), the ROM systimer_hal_init/deinit functions do not
* enable ETM, so we need to patch them here.
*/
#include <stddef.h>
#include "esp_rom_caps.h"
#include "hal/systimer_hal.h"
#include "hal/systimer_ll.h"
#if ESP_ROM_SYSTIMER_INIT_PATCH
void systimer_hal_init(systimer_hal_context_t *hal)
{
hal->dev = &SYSTIMER;
systimer_ll_enable_clock(hal->dev, true);
systimer_ll_enable_etm(&SYSTIMER, true);
}
void systimer_hal_deinit(systimer_hal_context_t *hal)
{
systimer_ll_enable_etm(&SYSTIMER, false);
systimer_ll_enable_clock(hal->dev, false);
hal->dev = NULL;
}
#endif // ESP_ROM_SYSTIMER_INIT_PATCH

View File

@@ -0,0 +1,204 @@
/*
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <sys/param.h>
#include "soc/soc_caps.h"
#include "hal/systimer_hal.h"
#include "hal/systimer_types.h"
#include "hal/assert.h"
void systimer_hal_init(systimer_hal_context_t *hal)
{
hal->dev = &SYSTIMER;
systimer_ll_enable_clock(hal->dev, true);
#if SOC_SYSTIMER_SUPPORT_ETM
systimer_ll_enable_etm(&SYSTIMER, true);
#endif
}
void systimer_hal_deinit(systimer_hal_context_t *hal)
{
#if SOC_SYSTIMER_SUPPORT_ETM
systimer_ll_enable_etm(&SYSTIMER, false);
#endif
systimer_ll_enable_clock(hal->dev, false);
hal->dev = NULL;
}
systimer_clock_source_t systimer_hal_get_clock_source(systimer_hal_context_t *hal)
{
(void)hal;
return systimer_ll_get_clock_source();
}
void systimer_hal_set_tick_rate_ops(systimer_hal_context_t *hal, systimer_hal_tick_rate_ops_t *ops)
{
hal->ticks_to_us = ops->ticks_to_us;
hal->us_to_ticks = ops->us_to_ticks;
}
uint64_t systimer_hal_get_counter_value(systimer_hal_context_t *hal, uint32_t counter_id)
{
uint32_t lo, lo_start, hi;
/* Set the "update" bit and wait for acknowledgment */
systimer_ll_counter_snapshot(hal->dev, counter_id);
while (!systimer_ll_is_counter_value_valid(hal->dev, counter_id));
/* Read LO, HI, then LO again, check that LO returns the same value.
* This accounts for the case when an interrupt may happen between reading
* HI and LO values, and this function may get called from the ISR.
* In this case, the repeated read will return consistent values.
*/
lo_start = systimer_ll_get_counter_value_low(hal->dev, counter_id);
do {
lo = lo_start;
hi = systimer_ll_get_counter_value_high(hal->dev, counter_id);
lo_start = systimer_ll_get_counter_value_low(hal->dev, counter_id);
} while (lo_start != lo);
systimer_counter_value_t result = {
.lo = lo,
.hi = hi
};
return result.val;
}
uint64_t systimer_hal_get_time(systimer_hal_context_t *hal, uint32_t counter_id)
{
return hal->ticks_to_us(systimer_hal_get_counter_value(hal, counter_id));
}
#if SYSTIMER_LL_ALARM_MISS_COMPENSATE
void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t target)
{
systimer_counter_value_t alarm = {
.val = hal->us_to_ticks(target),
};
systimer_ll_enable_alarm(hal->dev, alarm_id, false);
systimer_ll_set_alarm_target(hal->dev, alarm_id, alarm.val);
systimer_ll_apply_alarm_value(hal->dev, alarm_id);
systimer_ll_enable_alarm(hal->dev, alarm_id, true);
}
#else // SYSTIMER_LL_ALARM_MISS_COMPENSATE
void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t timestamp)
{
int64_t offset = hal->us_to_ticks(1) * 2;
uint64_t now_time = systimer_hal_get_counter_value(hal, 0);
uint64_t timestamp_ticks = hal->us_to_ticks(timestamp);
systimer_counter_value_t alarm = { .val = MAX(timestamp_ticks, now_time + offset) };
do {
systimer_ll_enable_alarm(hal->dev, alarm_id, false);
systimer_ll_set_alarm_target(hal->dev, alarm_id, alarm.val);
systimer_ll_enable_alarm(hal->dev, alarm_id, true);
now_time = systimer_hal_get_counter_value(hal, 0);
int64_t delta = (int64_t)alarm.val - (int64_t)now_time;
if (delta <= 0 && !systimer_ll_is_alarm_int_fired(hal->dev, alarm_id)) {
// new alarm is less than the counter and the interrupt flag is not set
offset += -1 * delta + hal->us_to_ticks(1) * 2;
alarm.val = now_time + offset;
} else {
// finish if either (alarm > counter) or the interrupt flag is already set.
break;
}
} while (1);
}
#endif // SYSTIMER_LL_ALARM_MISS_COMPENSATE
void systimer_hal_set_alarm_period(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t period)
{
systimer_ll_enable_alarm(hal->dev, alarm_id, false);
systimer_ll_set_alarm_period(hal->dev, alarm_id, hal->us_to_ticks(period));
systimer_ll_apply_alarm_value(hal->dev, alarm_id);
systimer_ll_enable_alarm(hal->dev, alarm_id, true);
}
uint64_t systimer_hal_get_alarm_value(systimer_hal_context_t *hal, uint32_t alarm_id)
{
return systimer_ll_get_alarm_target(hal->dev, alarm_id);
}
void systimer_hal_enable_alarm_int(systimer_hal_context_t *hal, uint32_t alarm_id)
{
systimer_ll_enable_alarm_int(hal->dev, alarm_id, true);
}
void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t counter_id, int64_t time_us)
{
systimer_counter_value_t new_count = {
.val = systimer_hal_get_counter_value(hal, counter_id) + hal->us_to_ticks(time_us),
};
systimer_ll_set_counter_value(hal->dev, counter_id, new_count.val);
systimer_ll_apply_counter_value(hal->dev, counter_id);
}
void systimer_hal_enable_counter(systimer_hal_context_t *hal, uint32_t counter_id)
{
systimer_ll_enable_counter(hal->dev, counter_id, true);
}
void systimer_hal_select_alarm_mode(systimer_hal_context_t *hal, uint32_t alarm_id, systimer_alarm_mode_t mode)
{
switch (mode) {
case SYSTIMER_ALARM_MODE_ONESHOT:
systimer_ll_enable_alarm_oneshot(hal->dev, alarm_id);
break;
case SYSTIMER_ALARM_MODE_PERIOD:
systimer_ll_enable_alarm_period(hal->dev, alarm_id);
break;
default:
break;
}
}
void systimer_hal_connect_alarm_counter(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t counter_id)
{
systimer_ll_connect_alarm_counter(hal->dev, alarm_id, counter_id);
}
void systimer_hal_counter_can_stall_by_cpu(systimer_hal_context_t *hal, uint32_t counter_id, uint32_t cpu_id, bool can)
{
systimer_ll_counter_can_stall_by_cpu(hal->dev, counter_id, cpu_id, can);
}
#if !SYSTIMER_LL_FIXED_DIVIDER
void systimer_hal_set_steps_per_tick(systimer_hal_context_t *hal, int clock_source, uint32_t steps)
{
/* Configure the counter:
* - increment by 1 when running from PLL (80 ticks per microsecond),
* - increment by 2 when running from XTAL (40 ticks per microsecond).
* Note that if the APB frequency is derived from XTAL with divider != 1,
* XTAL_STEP needs to be adjusted accordingly. For example, if
* the APB frequency is XTAL/4 = 10 MHz, then XTAL_STEP should be set to 8.
* This is handled in systimer_hal_on_apb_freq_update function.
*/
switch (clock_source) {
case 0:
systimer_ll_set_step_for_xtal(hal->dev, steps);
break;
case 1:
systimer_ll_set_step_for_pll(hal->dev, steps);
default:
break;
}
}
void systimer_hal_on_apb_freq_update(systimer_hal_context_t *hal, uint32_t apb_ticks_per_us)
{
/* If this function was called when switching APB clock to PLL, don't need
* do anything: the SYSTIMER_TIMER_PLL_STEP is already correct.
* If this was called when switching APB clock to XTAL, need to adjust
* XTAL_STEP value accordingly.
*/
if (apb_ticks_per_us != hal->us_to_ticks(1)) {
HAL_ASSERT((hal->us_to_ticks(1) % apb_ticks_per_us) == 0 && "TICK_PER_US should be divisible by APB frequency (in MHz)");
systimer_ll_set_step_for_xtal(hal->dev, hal->us_to_ticks(1) / apb_ticks_per_us);
}
}
#endif // !SYSTIMER_LL_FIXED_DIVIDER

View File

@@ -0,0 +1,9 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
project(systimer_rom_impl)

View File

@@ -0,0 +1,26 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# esp_hal_systimer ROM implementation test app
This test app verifies that the systimer HAL is correctly linked from either ROM or the component implementation, depending on `CONFIG_HAL_SYSTIMER_USE_ROM_IMPL`.
## Configurations
- **rom_impl**: Builds with `CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=y`, tests that `systimer_hal_get_counter_value` is in ROM.
- **no_rom_impl**: Builds with `CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=n`, tests that the function is not in ROM.
## Building and running
```bash
idf.py set-target <target>
idf.py build flash monitor
```
To run with pytest:
```bash
idf.py set-target <target>
idf.py build
pytest --target=<target>
```

View File

@@ -0,0 +1,7 @@
set(srcs "test_app_main.c")
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity esp_hal_systimer
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "hal/systimer_hal.h"
static bool fn_in_rom(void *fn)
{
const int fnaddr = (int)fn;
return (fnaddr >= SOC_IROM_MASK_LOW && fnaddr < SOC_IROM_MASK_HIGH);
}
#if CONFIG_HAL_SYSTIMER_USE_ROM_IMPL
TEST_CASE("Test that systimer implementation from ROM is used", "[systimer-rom-impl]")
{
TEST_ASSERT_TRUE(fn_in_rom(systimer_hal_get_counter_value));
}
#else
TEST_CASE("Test that systimer implementation from ROM is NOT used", "[systimer-rom-impl]")
{
TEST_ASSERT_FALSE(fn_in_rom(systimer_hal_get_counter_value));
}
#endif // CONFIG_HAL_SYSTIMER_USE_ROM_IMPL
#define TEST_MEMORY_LEAK_THRESHOLD (-100)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
from pytest_embedded_idf.utils import soc_filtered_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'no_rom_impl',
'rom_impl',
],
indirect=True,
)
@idf_parametrize('target', soc_filtered_targets('SOC_SYSTIMER_SUPPORTED == 1'), indirect=['target'])
def test_esp_hal_systimer_rom_impl(dut: Dut) -> None:
dut.run_all_single_board_cases()

View File

@@ -0,0 +1 @@
CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=n

View File

@@ -0,0 +1 @@
CONFIG_HAL_SYSTIMER_USE_ROM_IMPL=y