Skip to content

Commit

Permalink
Implement Timer1 using Group0, Timer0.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikee47 committed Sep 22, 2021
1 parent 43f0bdd commit 4fa246b
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 65 deletions.
103 changes: 87 additions & 16 deletions Sming/Arch/Esp32/Components/driver/hw_timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,103 @@
****/

#include <driver/hw_timer.h>
#include <hal/timer_hal.h>
#include <esp_intr_alloc.h>

static struct {
hw_timer_callback_t func = nullptr;
void* arg = nullptr;
} nmi_callback;
namespace
{
struct TimerConfig {
timer_group_t group;
timer_idx_t index;
timer_hal_context_t hal;
intr_handle_t isr_handle;
hw_timer_callback_t callback;
void* arg;
bool autoload;
};

TimerConfig timer;

static void IRAM_ATTR nmi_handler()
void IRAM_ATTR timerIsr(void* arg)
{
nmi_callback.func(nmi_callback.arg);
auto& timer = *static_cast<TimerConfig*>(arg);

if(timer.callback != nullptr) {
timer.callback(arg);
}

timer_hal_clear_intr_status(&timer.hal);

if(timer.autoload) {
timer_hal_set_alarm_enable(&timer.hal, true);
} else {
timer_hal_set_counter_enable(&timer.hal, false);
}
}

} // namespace

void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg)
{
if(source_type == TIMER_NMI_SOURCE) {
if(arg == NULL) {
// ETS_FRC_TIMER1_NMI_INTR_ATTACH(reinterpret_cast<void (*)()>(callback));
} else {
nmi_callback.func = callback;
nmi_callback.arg = arg;
// ETS_FRC_TIMER1_NMI_INTR_ATTACH(nmi_handler);
}
} else {
// ETS_FRC_TIMER1_INTR_ATTACH(callback, arg);
if(timer.isr_handle != nullptr) {
hw_timer1_detach_interrupt();
}

if(callback == nullptr) {
return;
}

timer.callback = callback;

uint32_t status_reg{0};
uint32_t mask{0};
timer_hal_get_status_reg_mask_bit(&timer.hal, &status_reg, &mask);
esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[timer.group].t0_irq_id + timer.index,
ESP_INTR_FLAG_IRAM, status_reg, mask, timerIsr, &timer, &timer.isr_handle);
timer_hal_clear_intr_status(&timer.hal);
timer_hal_intr_enable(&timer.hal);
}

void hw_timer1_detach_interrupt(void)
{
timer_hal_intr_disable(&timer.hal);
esp_intr_free(timer.isr_handle);
timer.isr_handle = nullptr;
}

void hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load)
{
timer_hal_set_auto_reload(&timer.hal, auto_load);
timer_hal_set_divider(&timer.hal, 1 << div);
timer.autoload = auto_load;
}

void IRAM_ATTR hw_timer1_write(uint32_t ticks)
{
timer_hal_set_counter_value(&timer.hal, ticks);
timer_hal_set_counter_enable(&timer.hal, true);
}

void IRAM_ATTR hw_timer1_disable(void)
{
timer_hal_set_counter_enable(&timer.hal, false);
}

uint32_t hw_timer1_read(void)
{
uint64_t val{0};
timer_hal_get_counter_value(&timer.hal, &val);
return val;
}

void hw_timer_init(void)
{
timer.group = HW_TIMER1_GROUP;
timer.index = HW_TIMER1_INDEX;
timer_hal_init(&timer.hal, timer.group, timer.index);
timer_hal_set_counter_enable(&timer.hal, false);
timer_hal_set_alarm_enable(&timer.hal, true);
timer_hal_set_alarm_value(&timer.hal, 0);
timer_hal_set_level_int_enable(&timer.hal, true);
timer_hal_set_counter_increase(&timer.hal, false);
}
75 changes: 26 additions & 49 deletions Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

#pragma once

#include <esp_systemapi.h>
#include <esp_timer.h>
#include <esp_attr.h>
#include <sming_attr.h>
#include <cstdint>

#define HW_TIMER_BASE_CLK APB_CLK_FREQ

Expand All @@ -23,21 +24,28 @@

/*************************************
*
* FRC1 timer
*
* This is a 23-bit countdown timer
* Timer1
*
* Used to implement HardwareTimer class.
*
*************************************/

// Timer group/index to use: available on all ESP32 variants
#define HW_TIMER1_GROUP TIMER_GROUP_0
#define HW_TIMER1_INDEX TIMER_0

/**
* @brief Maximum timer interval in ticks
* @note The corresponding time interval depends on the prescaler in use:
*
* /1 - 26.84s
* /16 - 429.50s
* /256 - 6871.95s
*
* /1 - 0.1048s
* /16 - 1.677s
* /256 - 26.84s
* ESP32 supports a wide range of prescalers and uses 54-bit counter value.
* Limiting the range 31 bits avoids issues with overflows and moving to 64-bit calculations.
*/
#define MAX_HW_TIMER1_INTERVAL 0x7fffff
#define MAX_HW_TIMER1_INTERVAL 0x7fffffff

/**
* @brief Minimum hardware interval in microseconds
Expand Down Expand Up @@ -67,7 +75,7 @@ typedef enum {

/**
* @brief Attach an interrupt for the timer
* @param source_type
* @param source_type Ignored, uses APB clock source
* @param callback Callback function invoked via timer interrupt
* @param arg Passed to callback function
*/
Expand All @@ -76,65 +84,32 @@ void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw
/**
* @brief Enable the timer
* @param div
* @param intr_type
* @param intr_type Ignored, always level-triggered
* @param auto_load
*/
inline void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load)
{
#ifdef FRC_TIMER_ENABLED
uint32_t ctrl = (div & 0x0C) | (intr_type & 0x01) | FRC_TIMER_ENABLE;
if(auto_load) {
ctrl |= FRC_TIMER_AUTOLOAD;
}

REG_WRITE(FRC_TIMER_CTRL_REG(0), ctrl);
// TM1_EDGE_INT_ENABLE();
// ETS_FRC1_INTR_ENABLE();
#endif
}
void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load);

/**
* @brief Set the timer interval
* @param ticks
*/
__forceinline void IRAM_ATTR hw_timer1_write(uint32_t ticks)
{
#ifdef FRC_TIMER_ENABLED
REG_WRITE(FRC_TIMER_LOAD_REG(0), ticks);
#endif
}
void IRAM_ATTR hw_timer1_write(uint32_t ticks);

/**
* @brief Disable the timer
*/
__forceinline void IRAM_ATTR hw_timer1_disable(void)
{
// TM1_EDGE_INT_DISABLE();
// ETS_FRC1_INTR_DISABLE();
}
void IRAM_ATTR hw_timer1_disable(void);

/**
* @brief Detach interrupt from the timer
*/
__forceinline void IRAM_ATTR hw_timer1_detach_interrupt(void)
{
hw_timer1_disable();
// ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
// ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
}
void IRAM_ATTR hw_timer1_detach_interrupt(void);

/**
* @brief Get timer1 count
* @retval uint32_t Current count value, counts from initial value down to 0
*/
__forceinline uint32_t hw_timer1_read(void)
{
#ifdef FRC_TIMER_ENABLED
return REG_READ(FRC_TIMER_COUNT_REG(0));
#else
return 0;
#endif
}
uint32_t hw_timer1_read(void);

/*************************************
*
Expand All @@ -144,6 +119,8 @@ __forceinline uint32_t hw_timer1_read(void)

constexpr uint32_t HW_TIMER2_CLK = 1000000;

extern "C" int64_t esp_timer_get_time(void);

/**
* @brief Read current timer2 value
* @retval uint32_t
Expand Down

0 comments on commit 4fa246b

Please sign in to comment.