esp32-hal-timer.c
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_LOCK() portENTER_CRITICAL(timer->lock) 26 #define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock) 27 28 typedef struct { 29 union { 30 struct { 31 uint32_t reserved0: 10; 32 uint32_t alarm_en: 1; /*When set alarm is enabled*/ 33 uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/ 34 uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/ 35 uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/ 36 uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/ 37 uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/ 38 uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/ 39 }; 40 uint32_t val; 41 } config; 42 uint32_t cnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/ 43 uint32_t cnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/ 44 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)*/ 45 uint32_t alarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/ 46 uint32_t alarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/ 47 uint32_t load_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/ 48 uint32_t load_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/ 49 uint32_t reload; /*Write any value will trigger timer 0 time-base counter reload*/ 50 } hw_timer_reg_t; 51 52 typedef struct hw_timer_s { 53 hw_timer_reg_t * dev; 54 uint8_t num; 55 uint8_t group; 56 uint8_t timer; 57 portMUX_TYPE lock; 58 } hw_timer_t; 59 60 static hw_timer_t hw_timer[4] = { 61 {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED}, 62 {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x0024),1,0,1,portMUX_INITIALIZER_UNLOCKED}, 63 {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1000),2,1,0,portMUX_INITIALIZER_UNLOCKED}, 64 {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1024),3,1,1,portMUX_INITIALIZER_UNLOCKED} 65 }; 66 67 typedef void (*voidFuncPtr)(void); 68 static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0}; 69 70 void IRAM_ATTR __timerISR(void * arg){ 71 uint32_t s0 = TIMERG0.int_st_timers.val; 72 uint32_t s1 = TIMERG1.int_st_timers.val; 73 TIMERG0.int_clr_timers.val = s0; 74 TIMERG1.int_clr_timers.val = s1; 75 uint8_t status = (s1 & 3) << 2 | (s0 & 3); 76 uint8_t i = 4; 77 //restart the timers that should autoreload 78 while(i--){ 79 hw_timer_reg_t * dev = hw_timer[i].dev; 80 if((status & (1 << i)) && dev->config.autoreload){ 81 dev->config.alarm_en = 1; 82 } 83 } 84 i = 4; 85 //call callbacks 86 while(i--){ 87 if(__timerInterruptHandlers[i] && status & (1 << i)){ 88 __timerInterruptHandlers[i](); 89 } 90 } 91 } 92 93 uint64_t timerRead(hw_timer_t *timer){ 94 timer->dev->update = 1; 95 uint64_t h = timer->dev->cnt_high; 96 uint64_t l = timer->dev->cnt_low; 97 return (h << 32) | l; 98 } 99 100 uint64_t timerAlarmRead(hw_timer_t *timer){ 101 uint64_t h = timer->dev->alarm_high; 102 uint64_t l = timer->dev->alarm_low; 103 return (h << 32) | l; 104 } 105 106 void timerWrite(hw_timer_t *timer, uint64_t val){ 107 timer->dev->load_high = (uint32_t) (val >> 32); 108 timer->dev->load_low = (uint32_t) (val); 109 timer->dev->reload = 1; 110 } 111 112 void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ 113 timer->dev->alarm_high = (uint32_t) (alarm_value >> 32); 114 timer->dev->alarm_low = (uint32_t) alarm_value; 115 timer->dev->config.autoreload = autoreload; 116 } 117 118 void timerSetConfig(hw_timer_t *timer, uint32_t config){ 119 timer->dev->config.val = config; 120 } 121 122 uint32_t timerGetConfig(hw_timer_t *timer){ 123 return timer->dev->config.val; 124 } 125 126 void timerSetCountUp(hw_timer_t *timer, bool countUp){ 127 timer->dev->config.increase = countUp; 128 } 129 130 bool timerGetCountUp(hw_timer_t *timer){ 131 return timer->dev->config.increase; 132 } 133 134 void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ 135 timer->dev->config.autoreload = autoreload; 136 } 137 138 bool timerGetAutoReload(hw_timer_t *timer){ 139 return timer->dev->config.autoreload; 140 } 141 142 void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536 143 if(!divider){ 144 divider = 0xFFFF; 145 } else if(divider == 1){ 146 divider = 2; 147 } 148 int timer_en = timer->dev->config.enable; 149 timer->dev->config.enable = 0; 150 timer->dev->config.divider = divider; 151 timer->dev->config.enable = timer_en; 152 } 153 154 uint16_t timerGetDivider(hw_timer_t *timer){ 155 return timer->dev->config.divider; 156 } 157 158 void timerStart(hw_timer_t *timer){ 159 timer->dev->config.enable = 1; 160 } 161 162 void timerStop(hw_timer_t *timer){ 163 timer->dev->config.enable = 0; 164 } 165 166 void timerRestart(hw_timer_t *timer){ 167 timer->dev->config.enable = 0; 168 timer->dev->config.enable = 1; 169 } 170 171 bool timerStarted(hw_timer_t *timer){ 172 return timer->dev->config.enable; 173 } 174 175 void timerAlarmEnable(hw_timer_t *timer){ 176 timer->dev->config.alarm_en = 1; 177 } 178 179 void timerAlarmDisable(hw_timer_t *timer){ 180 timer->dev->config.alarm_en = 0; 181 } 182 183 bool timerAlarmEnabled(hw_timer_t *timer){ 184 return timer->dev->config.alarm_en; 185 } 186 187 hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ 188 if(num > 3){ 189 return NULL; 190 } 191 hw_timer_t * timer = &hw_timer[num]; 192 if(timer->group) { 193 DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN); 194 DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST); 195 TIMERG1.int_ena.val &= ~BIT(timer->timer); 196 } else { 197 DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN); 198 DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST); 199 TIMERG0.int_ena.val &= ~BIT(timer->timer); 200 } 201 timer->dev->config.enable = 0; 202 timerSetDivider(timer, divider); 203 timerSetCountUp(timer, countUp); 204 timerSetAutoReload(timer, false); 205 timerAttachInterrupt(timer, NULL, false); 206 timerWrite(timer, 0); 207 timer->dev->config.enable = 1; 208 return timer; 209 } 210 211 void timerEnd(hw_timer_t *timer){ 212 timer->dev->config.enable = 0; 213 timerAttachInterrupt(timer, NULL, false); 214 } 215 216 void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ 217 static bool initialized = false; 218 static intr_handle_t intr_handle = NULL; 219 if(intr_handle){ 220 esp_intr_disable(intr_handle); 221 } 222 if(fn == NULL){ 223 timer->dev->config.level_int_en = 0; 224 timer->dev->config.edge_int_en = 0; 225 timer->dev->config.alarm_en = 0; 226 if(timer->num & 2){ 227 TIMERG1.int_ena.val &= ~BIT(timer->timer); 228 } else { 229 TIMERG0.int_ena.val &= ~BIT(timer->timer); 230 } 231 __timerInterruptHandlers[timer->num] = NULL; 232 } else { 233 __timerInterruptHandlers[timer->num] = fn; 234 timer->dev->config.level_int_en = edge?0:1;//When set, an alarm will generate a level type interrupt. 235 timer->dev->config.edge_int_en = edge?1:0;//When set, an alarm will generate an edge type interrupt. 236 int intr_source = 0; 237 if(!edge){ 238 if(timer->group){ 239 intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer; 240 } else { 241 intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer; 242 } 243 } else { 244 if(timer->group){ 245 intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer->timer; 246 } else { 247 intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer->timer; 248 } 249 } 250 if(!initialized){ 251 initialized = true; 252 esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle); 253 } else { 254 intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle)); 255 } 256 if(timer->group){ 257 TIMERG1.int_ena.val |= BIT(timer->timer); 258 } else { 259 TIMERG0.int_ena.val |= BIT(timer->timer); 260 } 261 } 262 if(intr_handle){ 263 esp_intr_enable(intr_handle); 264 } 265 } 266 267 void timerDetachInterrupt(hw_timer_t *timer){ 268 timerAttachInterrupt(timer, NULL, false); 269 } 270 271 uint64_t timerReadMicros(hw_timer_t *timer){ 272 uint64_t timer_val = timerRead(timer); 273 uint16_t div = timerGetDivider(timer); 274 return timer_val * div / 80; 275 } 276 277 double timerReadSeconds(hw_timer_t *timer){ 278 uint64_t timer_val = timerRead(timer); 279 uint16_t div = timerGetDivider(timer); 280 return (double)timer_val * div / 80000000; 281 } 282 283 uint64_t timerAlarmReadMicros(hw_timer_t *timer){ 284 uint64_t timer_val = timerAlarmRead(timer); 285 uint16_t div = timerGetDivider(timer); 286 return timer_val * div / 80; 287 } 288 289 double timerAlarmReadSeconds(hw_timer_t *timer){ 290 uint64_t timer_val = timerAlarmRead(timer); 291 uint16_t div = timerGetDivider(timer); 292 return (double)timer_val * div / 80000000; 293 }