Skip to content

Commit 4e458fd

Browse files
committed
Initial Timers driver
Implementation for Timers 0-4 (no locks yet)
1 parent f5d6828 commit 4e458fd

File tree

3 files changed

+368
-0
lines changed

3 files changed

+368
-0
lines changed

cores/esp32/esp32-hal-timer.c

+295
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "esp32-hal-timer.h"
16+
#include "freertos/FreeRTOS.h"
17+
#include "freertos/xtensa_api.h"
18+
#include "freertos/task.h"
19+
#include "rom/ets_sys.h"
20+
#include "soc/timer_group_struct.h"
21+
#include "soc/dport_reg.h"
22+
#include "esp_attr.h"
23+
#include "esp_intr.h"
24+
25+
#define HWTIMER_INUM 10
26+
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
27+
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
28+
29+
typedef struct {
30+
union {
31+
struct {
32+
uint32_t reserved0: 10;
33+
uint32_t alarm_en: 1; /*When set alarm is enabled*/
34+
uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/
35+
uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/
36+
uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/
37+
uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
38+
uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
39+
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
40+
};
41+
uint32_t val;
42+
} config;
43+
uint32_t cnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/
44+
uint32_t cnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/
45+
uint32_t update; /*Write any value will trigger a timer 0 time-base counter value update (timer 0 current value will be stored in registers above)*/
46+
uint32_t alarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/
47+
uint32_t alarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/
48+
uint32_t load_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/
49+
uint32_t load_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/
50+
uint32_t reload; /*Write any value will trigger timer 0 time-base counter reload*/
51+
} hw_timer_reg_t;
52+
53+
typedef struct hw_timer_s {
54+
hw_timer_reg_t * dev;
55+
uint8_t num;
56+
uint8_t group;
57+
uint8_t timer;
58+
portMUX_TYPE lock;
59+
} hw_timer_t;
60+
61+
static hw_timer_t hw_timer[4] = {
62+
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED},
63+
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x0024),1,0,1,portMUX_INITIALIZER_UNLOCKED},
64+
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1000),2,1,0,portMUX_INITIALIZER_UNLOCKED},
65+
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1024),3,1,1,portMUX_INITIALIZER_UNLOCKED}
66+
};
67+
68+
typedef void (*voidFuncPtr)(void);
69+
static voidFuncPtr __timerInterruptHandlers[4] = {0,};
70+
71+
void IRAM_ATTR __timerISR(void * arg){
72+
uint32_t s0 = TIMERG0.int_st_timers.val;
73+
uint32_t s1 = TIMERG1.int_st_timers.val;
74+
TIMERG0.int_clr_timers.val = s0;
75+
TIMERG1.int_clr_timers.val = s1;
76+
uint8_t status = (s1 & 3) << 2 | (s0 & 3);
77+
uint8_t i = 4;
78+
//restart the timers that should autoreload
79+
while(i--){
80+
hw_timer_reg_t * dev = hw_timer[i].dev;
81+
if((status & (1 << i)) && dev->config.autoreload){
82+
dev->load_high = 0;
83+
dev->load_low = 0;
84+
dev->reload = 1;
85+
dev->config.alarm_en = 1;
86+
}
87+
}
88+
i = 4;
89+
//call callbacks
90+
while(i--){
91+
if(status & (1 << i)){
92+
if(__timerInterruptHandlers[i]){
93+
__timerInterruptHandlers[i]();
94+
}
95+
}
96+
}
97+
}
98+
99+
uint64_t timerRead(hw_timer_t *timer){
100+
timer->dev->update = 1;
101+
uint64_t h = timer->dev->cnt_high;
102+
uint64_t l = timer->dev->cnt_low;
103+
return (h << 32) | l;
104+
}
105+
106+
uint64_t timerAlarmRead(hw_timer_t *timer){
107+
uint64_t h = timer->dev->alarm_high;
108+
uint64_t l = timer->dev->alarm_low;
109+
return (h << 32) | l;
110+
}
111+
112+
void timerWrite(hw_timer_t *timer, uint64_t val){
113+
timer->dev->load_high = (uint32_t) (val >> 32);
114+
timer->dev->load_low = (uint32_t) (val);
115+
timer->dev->reload = 1;
116+
}
117+
118+
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
119+
timer->dev->alarm_high = (uint32_t) (alarm_value >> 32);
120+
timer->dev->alarm_low = (uint32_t) alarm_value;
121+
timer->dev->config.autoreload = autoreload;
122+
}
123+
124+
void timerSetConfig(hw_timer_t *timer, uint32_t config){
125+
timer->dev->config.val = config;
126+
}
127+
128+
uint32_t timerGetConfig(hw_timer_t *timer){
129+
return timer->dev->config.val;
130+
}
131+
132+
void timerSetCountUp(hw_timer_t *timer, bool countUp){
133+
timer->dev->config.increase = countUp;
134+
}
135+
136+
bool timerGetCountUp(hw_timer_t *timer){
137+
return timer->dev->config.increase;
138+
}
139+
140+
void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
141+
timer->dev->config.autoreload = autoreload;
142+
}
143+
144+
bool timerGetAutoReload(hw_timer_t *timer){
145+
return timer->dev->config.autoreload;
146+
}
147+
148+
void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
149+
if(!divider){
150+
divider = 0xFFFF;
151+
} else if(divider == 1){
152+
divider = 2;
153+
}
154+
int timer_en = timer->dev->config.enable;
155+
timer->dev->config.enable = 0;
156+
timer->dev->config.divider = divider;
157+
timer->dev->config.enable = timer_en;
158+
}
159+
160+
uint16_t timerGetDivider(hw_timer_t *timer){
161+
return timer->dev->config.divider;
162+
}
163+
164+
void timerStart(hw_timer_t *timer){
165+
timer->dev->config.enable = 1;
166+
}
167+
168+
void timerStop(hw_timer_t *timer){
169+
timer->dev->config.enable = 0;
170+
}
171+
172+
void timerRestart(hw_timer_t *timer){
173+
timer->dev->config.enable = 0;
174+
timer->dev->config.enable = 1;
175+
}
176+
177+
bool timerStarted(hw_timer_t *timer){
178+
return timer->dev->config.enable;
179+
}
180+
181+
void timerAlarmEnable(hw_timer_t *timer){
182+
timer->dev->config.alarm_en = 1;
183+
}
184+
185+
void timerAlarmDisable(hw_timer_t *timer){
186+
timer->dev->config.alarm_en = 0;
187+
}
188+
189+
bool timerAlarmEnabled(hw_timer_t *timer){
190+
return timer->dev->config.alarm_en;
191+
}
192+
193+
194+
195+
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
196+
if(num > 3){
197+
return NULL;
198+
}
199+
hw_timer_t * timer = &hw_timer[num];
200+
if(timer->group) {
201+
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
202+
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
203+
TIMERG1.int_ena.val &= ~BIT(timer->timer);
204+
} else {
205+
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
206+
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
207+
TIMERG0.int_ena.val &= ~BIT(timer->timer);
208+
}
209+
timer->dev->config.enable = 0;
210+
timerSetDivider(timer, divider);
211+
timerSetCountUp(timer, countUp);
212+
timerSetAutoReload(timer, false);
213+
timerAttachInterrupt(timer, NULL, false);
214+
timerWrite(timer, 0);
215+
timer->dev->config.enable = 1;
216+
return timer;
217+
}
218+
219+
void timerEnd(hw_timer_t *timer){
220+
timer->dev->config.enable = 0;
221+
timerAttachInterrupt(timer, NULL, false);
222+
}
223+
224+
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
225+
static bool initialized = false;
226+
ESP_INTR_DISABLE(HWTIMER_INUM);
227+
if(fn == NULL){
228+
timer->dev->config.level_int_en = 0;
229+
timer->dev->config.edge_int_en = 0;
230+
timer->dev->config.alarm_en = 0;
231+
if(timer->num & 2){
232+
TIMERG1.int_ena.val &= ~BIT(timer->timer);
233+
} else {
234+
TIMERG0.int_ena.val &= ~BIT(timer->timer);
235+
}
236+
__timerInterruptHandlers[timer->num] = NULL;
237+
} else {
238+
if(!initialized){
239+
xt_set_interrupt_handler(HWTIMER_INUM, &__timerISR, NULL);
240+
initialized = true;
241+
}
242+
__timerInterruptHandlers[timer->num] = fn;
243+
timer->dev->config.level_int_en = edge?0:1;//When set, an alarm will generate a level type interrupt.
244+
timer->dev->config.edge_int_en = edge?1:0;//When set, an alarm will generate an edge type interrupt.
245+
int intr_source = 0;
246+
if(!edge){
247+
if(timer->group){
248+
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer;
249+
} else {
250+
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer;
251+
}
252+
} else {
253+
if(timer->group){
254+
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer->timer;
255+
} else {
256+
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer->timer;
257+
}
258+
}
259+
intr_matrix_set(xPortGetCoreID(), intr_source, HWTIMER_INUM);
260+
if(timer->group){
261+
TIMERG1.int_ena.val |= BIT(timer->timer);
262+
} else {
263+
TIMERG0.int_ena.val |= BIT(timer->timer);
264+
}
265+
}
266+
ESP_INTR_ENABLE(HWTIMER_INUM);
267+
}
268+
269+
void timerDetachInterrupt(hw_timer_t *timer){
270+
timerAttachInterrupt(timer, NULL, false);
271+
}
272+
273+
uint64_t timerReadMicros(hw_timer_t *timer){
274+
uint64_t timer_val = timerRead(timer);
275+
uint16_t div = timerGetDivider(timer);
276+
return timer_val * div / 80;
277+
}
278+
279+
double timerReadSeconds(hw_timer_t *timer){
280+
uint64_t timer_val = timerRead(timer);
281+
uint16_t div = timerGetDivider(timer);
282+
return (double)timer_val * div / 80000000;
283+
}
284+
285+
uint64_t timerAlarmReadMicros(hw_timer_t *timer){
286+
uint64_t timer_val = timerAlarmRead(timer);
287+
uint16_t div = timerGetDivider(timer);
288+
return timer_val * div / 80;
289+
}
290+
291+
double timerAlarmReadSeconds(hw_timer_t *timer){
292+
uint64_t timer_val = timerAlarmRead(timer);
293+
uint16_t div = timerGetDivider(timer);
294+
return (double)timer_val * div / 80000000;
295+
}

cores/esp32/esp32-hal-timer.h

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Arduino.h - Main include file for the Arduino SDK
3+
Copyright (c) 2005-2013 Arduino Team. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef MAIN_ESP32_HAL_TIMER_H_
21+
#define MAIN_ESP32_HAL_TIMER_H_
22+
23+
#ifdef __cplusplus
24+
extern "C" {
25+
#endif
26+
27+
#include "esp32-hal.h"
28+
#include "freertos/FreeRTOS.h"
29+
30+
struct hw_timer_s;
31+
typedef struct hw_timer_s hw_timer_t;
32+
33+
hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp);
34+
void timerEnd(hw_timer_t *timer);
35+
36+
void timerSetConfig(hw_timer_t *timer, uint32_t config);
37+
uint32_t timerGetConfig(hw_timer_t *timer);
38+
39+
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
40+
void timerDetachInterrupt(hw_timer_t *timer);
41+
42+
void timerStart(hw_timer_t *timer);
43+
void timerStop(hw_timer_t *timer);
44+
void timerRestart(hw_timer_t *timer);
45+
void timerWrite(hw_timer_t *timer, uint64_t val);
46+
void timerSetDivider(hw_timer_t *timer, uint16_t divider);
47+
void timerSetCountUp(hw_timer_t *timer, bool countUp);
48+
void timerSetAutoReload(hw_timer_t *timer, bool autoreload);
49+
50+
bool timerStarted(hw_timer_t *timer);
51+
uint64_t timerRead(hw_timer_t *timer);
52+
uint64_t timerReadMicros(hw_timer_t *timer);
53+
double timerReadSeconds(hw_timer_t *timer);
54+
uint16_t timerGetDivider(hw_timer_t *timer);
55+
bool timerGetCountUp(hw_timer_t *timer);
56+
bool timerGetAutoReload(hw_timer_t *timer);
57+
58+
void timerAlarmEnable(hw_timer_t *timer);
59+
void timerAlarmDisable(hw_timer_t *timer);
60+
void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload);
61+
62+
bool timerAlarmEnabled(hw_timer_t *timer);
63+
uint64_t timerAlarmRead(hw_timer_t *timer);
64+
uint64_t timerAlarmReadMicros(hw_timer_t *timer);
65+
double timerAlarmReadSeconds(hw_timer_t *timer);
66+
67+
68+
#ifdef __cplusplus
69+
}
70+
#endif
71+
72+
#endif /* MAIN_ESP32_HAL_TIMER_H_ */

cores/esp32/esp32-hal.h

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ void vPortYield( void );
5757
#include "esp32-hal-i2c.h"
5858
#include "esp32-hal-ledc.h"
5959
#include "esp32-hal-sd.h"
60+
#include "esp32-hal-timer.h"
6061
#include "esp_system.h"
6162

6263
uint32_t micros();

0 commit comments

Comments
 (0)