Skip to content

TIMER refactoring #7904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor using GPtimer
  • Loading branch information
P-R-O-C-H-Y committed Feb 28, 2023
commit 15a68e6bfdda7526d51bdeb12909b9089f85871c
302 changes: 93 additions & 209 deletions cores/esp32/esp32-hal-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,261 +13,145 @@
// limitations under the License.

#include "esp32-hal-timer.h"
#include "driver/timer.h"
#include "driver/gptimer.h"
#include "soc/soc_caps.h"
#include "clk_tree.h"

typedef union {
struct {
uint32_t reserved0: 10;
uint32_t alarm_en: 1; /*When set alarm is enabled*/
uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/
uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/
uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/
uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
};
uint32_t val;
} timer_cfg_t;

#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS

typedef struct hw_timer_s
{
uint8_t group;
uint8_t num;
} hw_timer_t;

// Works for all chips
static hw_timer_t timer_dev[4] = {
{0,0}, {1,0}, {0,1}, {1,1}
};

// NOTE: (in IDF 5.0 there wont be need to know groups/numbers
// timer_init() will list thru all timers and return free timer handle)


inline uint64_t timerRead(hw_timer_t *timer){
inline uint64_t timerRead(hw_timer_t timer_handle){

uint64_t value;
timer_get_counter_value(timer->group, timer->num,&value);
gptimer_get_raw_count(timer_handle, &value);
return value;
}

uint64_t timerAlarmRead(hw_timer_t *timer){
uint64_t value;
timer_get_alarm_value(timer->group, timer->num, &value);
return value;
}

void timerWrite(hw_timer_t *timer, uint64_t val){
timer_set_counter_value(timer->group, timer->num, val);
}

void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
timer_set_alarm_value(timer->group, timer->num, alarm_value);
timerSetAutoReload(timer,autoreload);
}

void timerSetConfig(hw_timer_t *timer, uint32_t config){
timer_cfg_t cfg;
cfg.val = config;
timer_set_alarm(timer->group, timer->num, cfg.alarm_en);
timerSetDivider(timer,cfg.divider);
timerSetAutoReload(timer,cfg.autoreload);
timerSetCountUp(timer, cfg.increase);

if (cfg.enable) {
timerStart(timer);
}
else{
timerStop(timer);
}
return;
}

uint32_t timerGetConfig(hw_timer_t *timer){
timer_config_t timer_cfg;
timer_get_config(timer->group, timer->num,&timer_cfg);

//Translate to default uint32_t
timer_cfg_t cfg;
cfg.alarm_en = timer_cfg.alarm_en;
cfg.autoreload = timer_cfg.auto_reload;
cfg.divider = timer_cfg.divider;
cfg.edge_int_en = timer_cfg.intr_type;
cfg.level_int_en = !timer_cfg.intr_type;
cfg.enable = timer_cfg.counter_en;
cfg.increase = timer_cfg.counter_dir;

return cfg.val;
}

void timerSetCountUp(hw_timer_t *timer, bool countUp){
timer_set_counter_mode(timer->group, timer->num,countUp);
}

bool timerGetCountUp(hw_timer_t *timer){
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.increase;
}

void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
timer_set_auto_reload(timer->group, timer->num,autoreload);
}

bool timerGetAutoReload(hw_timer_t *timer){
timer_cfg_t config;
config.val= timerGetConfig(timer);
return config.autoreload;
}

// Set divider from 2 to 65535
void timerSetDivider(hw_timer_t *timer, uint16_t divider){
if(divider < 2)
{
log_e("Timer divider must be set in range of 2 to 65535");
return;
}
timer_set_divider(timer->group, timer->num,divider);
}

uint16_t timerGetDivider(hw_timer_t *timer){
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.divider;
}

void timerStart(hw_timer_t *timer){
timer_start(timer->group, timer->num);
void timerWrite(hw_timer_t timer_handle, uint64_t val){
gptimer_set_raw_count(timer_handle, val);
}

void timerStop(hw_timer_t *timer){
timer_pause(timer->group, timer->num);
}

void timerRestart(hw_timer_t *timer){
timerWrite(timer,0);
void timerAlarmWrite(hw_timer_t timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count){
esp_err_t err = ESP_OK;
gptimer_alarm_config_t alarm_cfg = {
.alarm_count = alarm_value,
.reload_count = reload_count,
.flags.auto_reload_on_alarm = autoreload,
};
err = gptimer_set_alarm_action(timer, &alarm_cfg);
if (err != ESP_OK){
log_e("Timer Alarm Write failed, error num=%d", err);
}
}

bool timerStarted(hw_timer_t *timer){
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.enable;
uint32_t timerGetResolution(hw_timer_t timer_handle){
uint32_t resolution;
gptimer_get_resolution(timer_handle, &resolution);
return resolution;
}

void timerAlarmEnable(hw_timer_t *timer){
timer_set_alarm(timer->group, timer->num,true);
void timerStart(hw_timer_t timer_handle){
gptimer_start(timer_handle);
}

void timerAlarmDisable(hw_timer_t *timer){
timer_set_alarm(timer->group, timer->num,false);
void timerStop(hw_timer_t timer_handle){
gptimer_stop(timer_handle);
}

bool timerAlarmEnabled(hw_timer_t *timer){
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.alarm_en;
void timerRestart(hw_timer_t timer_handle){
gptimer_set_raw_count(timer_handle,0);
}

static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
hw_timer_t * timer = (hw_timer_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
timerStop(timer);
} else {
old_apb /= 1000000;
new_apb /= 1000000;
uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb;
timerSetDivider(timer,divider);
timerStart(timer);
hw_timer_t timerBegin(uint32_t resolution, bool countUp){

esp_err_t err = ESP_OK;
hw_timer_t timer_handle;
uint32_t counter_src_hz = 0;
uint32_t divider = 0;
soc_periph_gptimer_clk_src_t clk;

soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS;
for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++){
clk = gptimer_clks[i];
clk_tree_src_get_freq_hz(clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz);
divider = counter_src_hz / resolution;
if((divider >= 2) && (divider <= 65536)){
break;
}
else divider = 0;
}
}

hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num >= NUM_OF_TIMERS)
{
log_e("Timer number %u exceeds available number of Timers.", num);
if(divider == 0){
log_e("Resolution cannot be reached with any clock source, aborting!");
return NULL;
}

hw_timer_t * timer = &timer_dev[num]; //Get Timer group/num from 0-3 number

timer_config_t config = {
.divider = divider,
.counter_dir = countUp,
.counter_en = TIMER_PAUSE,
.alarm_en = TIMER_ALARM_DIS,
.auto_reload = false,
gptimer_config_t config = {
.clk_src = clk,
.direction = countUp,
.resolution_hz = resolution,
.flags.intr_shared = true,
};

timer_init(timer->group, timer->num, &config);
timer_set_counter_value(timer->group, timer->num, 0);
timerStart(timer);
addApbChangeCallback(timer, _on_apb_change);
return timer;
err = gptimer_new_timer(&config, &timer_handle);
if (err != ESP_OK){
log_e("Failed to create a new GPTimer, error num=%d", err);
return NULL;
}
gptimer_enable(timer_handle);
gptimer_start(timer_handle);
return timer_handle;
}

void timerEnd(hw_timer_t *timer){
removeApbChangeCallback(timer, _on_apb_change);
timer_deinit(timer->group, timer->num);
void timerEnd(hw_timer_t timer_handle){
esp_err_t err = ESP_OK;
gptimer_disable(timer_handle);
err = gptimer_del_timer(timer_handle);
if (err != ESP_OK){
log_e("Failed to destroy GPTimer, error num=%d", err);
}
}

bool IRAM_ATTR timerFnWrapper(void *arg){
bool IRAM_ATTR timerFnWrapper(hw_timer_t timer, const gptimer_alarm_event_data_t *edata, void *arg){
void (*fn)(void) = arg;
fn();

// some additional logic or handling may be required here to approriately yield or not
return false;
}

void timerAttachInterruptFlag(hw_timer_t *timer, void (*fn)(void), bool edge, int intr_alloc_flags){
if(edge){
log_w("EDGE timer interrupt is not supported! Setting to LEVEL...");
}
timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, intr_alloc_flags);
}
void timerAttachInterrupt(hw_timer_t timer, void (*fn)(void)){
esp_err_t err = ESP_OK;
gptimer_event_callbacks_t cbs = {
.on_alarm = timerFnWrapper,
};

void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
timerAttachInterruptFlag(timer, fn, edge, 0);
gptimer_disable(timer);
err = gptimer_register_event_callbacks(timer, &cbs, fn);
if (err != ESP_OK){
log_e("Timer Attach Interrupt failed, error num=%d", err);
}
gptimer_enable(timer);
}

void timerDetachInterrupt(hw_timer_t *timer){
timer_isr_callback_remove(timer->group, timer->num);
void timerDetachInterrupt(hw_timer_t timer){
esp_err_t err = ESP_OK;
err = gptimer_set_alarm_action(timer, NULL);
if (err != ESP_OK){
log_e("Timer Detach Interrupt failed, error num=%d", err);
}
}

uint64_t timerReadMicros(hw_timer_t *timer){
uint64_t timerReadMicros(hw_timer_t timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000000);
uint32_t resolution = timerGetResolution(timer);
return timer_val * 1000000 / resolution;
}

uint64_t timerReadMilis(hw_timer_t *timer){
uint64_t timerReadMilis(hw_timer_t timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000);
uint32_t resolution = timerGetResolution(timer);
return timer_val * 1000 / resolution;
}

double timerReadSeconds(hw_timer_t *timer){
double timerReadSeconds(hw_timer_t timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / getApbFrequency();
}

uint64_t timerAlarmReadMicros(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000000);
}

uint64_t timerAlarmReadMilis(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000);
}

double timerAlarmReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / getApbFrequency();
uint32_t resolution = timerGetResolution(timer);
return (double)timer_val / resolution;
}
Loading