|
| 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 | +#defineHWTIMER_INUM 10 |
| 26 | +#defineHWTIMER_LOCK() portENTER_CRITICAL(timer->lock) |
| 27 | +#defineHWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock) |
| 28 | + |
| 29 | +typedefstruct{ |
| 30 | +union{ |
| 31 | +struct{ |
| 32 | +uint32_treserved0: 10; |
| 33 | +uint32_talarm_en: 1; /*When set alarm is enabled*/ |
| 34 | +uint32_tlevel_int_en: 1; /*When set level type interrupt will be generated during alarm*/ |
| 35 | +uint32_tedge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/ |
| 36 | +uint32_tdivider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/ |
| 37 | +uint32_tautoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/ |
| 38 | +uint32_tincrease: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/ |
| 39 | +uint32_tenable: 1; /*When set timer 0/1 time-base counter is enabled*/ |
| 40 | + }; |
| 41 | +uint32_tval; |
| 42 | + } config; |
| 43 | +uint32_tcnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/ |
| 44 | +uint32_tcnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/ |
| 45 | +uint32_tupdate; /*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_talarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/ |
| 47 | +uint32_talarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/ |
| 48 | +uint32_tload_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/ |
| 49 | +uint32_tload_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/ |
| 50 | +uint32_treload; /*Write any value will trigger timer 0 time-base counter reload*/ |
| 51 | +} hw_timer_reg_t; |
| 52 | + |
| 53 | +typedefstructhw_timer_s{ |
| 54 | +hw_timer_reg_t*dev; |
| 55 | +uint8_tnum; |
| 56 | +uint8_tgroup; |
| 57 | +uint8_ttimer; |
| 58 | +portMUX_TYPElock; |
| 59 | +} hw_timer_t; |
| 60 | + |
| 61 | +statichw_timer_thw_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 | +typedefvoid (*voidFuncPtr)(void); |
| 69 | +staticvoidFuncPtr__timerInterruptHandlers[4] ={0,}; |
| 70 | + |
| 71 | +voidIRAM_ATTR__timerISR(void*arg){ |
| 72 | +uint32_ts0=TIMERG0.int_st_timers.val; |
| 73 | +uint32_ts1=TIMERG1.int_st_timers.val; |
| 74 | +TIMERG0.int_clr_timers.val=s0; |
| 75 | +TIMERG1.int_clr_timers.val=s1; |
| 76 | +uint8_tstatus= (s1&3) << 2 | (s0&3); |
| 77 | +uint8_ti=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_ttimerRead(hw_timer_t*timer){ |
| 100 | +timer->dev->update=1; |
| 101 | +uint64_th=timer->dev->cnt_high; |
| 102 | +uint64_tl=timer->dev->cnt_low; |
| 103 | +return (h << 32) | l; |
| 104 | +} |
| 105 | + |
| 106 | +uint64_ttimerAlarmRead(hw_timer_t*timer){ |
| 107 | +uint64_th=timer->dev->alarm_high; |
| 108 | +uint64_tl=timer->dev->alarm_low; |
| 109 | +return (h << 32) | l; |
| 110 | +} |
| 111 | + |
| 112 | +voidtimerWrite(hw_timer_t*timer, uint64_tval){ |
| 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 | +voidtimerAlarmWrite(hw_timer_t*timer, uint64_talarm_value, boolautoreload){ |
| 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 | +voidtimerSetConfig(hw_timer_t*timer, uint32_tconfig){ |
| 125 | +timer->dev->config.val=config; |
| 126 | +} |
| 127 | + |
| 128 | +uint32_ttimerGetConfig(hw_timer_t*timer){ |
| 129 | +returntimer->dev->config.val; |
| 130 | +} |
| 131 | + |
| 132 | +voidtimerSetCountUp(hw_timer_t*timer, boolcountUp){ |
| 133 | +timer->dev->config.increase=countUp; |
| 134 | +} |
| 135 | + |
| 136 | +booltimerGetCountUp(hw_timer_t*timer){ |
| 137 | +returntimer->dev->config.increase; |
| 138 | +} |
| 139 | + |
| 140 | +voidtimerSetAutoReload(hw_timer_t*timer, boolautoreload){ |
| 141 | +timer->dev->config.autoreload=autoreload; |
| 142 | +} |
| 143 | + |
| 144 | +booltimerGetAutoReload(hw_timer_t*timer){ |
| 145 | +returntimer->dev->config.autoreload; |
| 146 | +} |
| 147 | + |
| 148 | +voidtimerSetDivider(hw_timer_t*timer, uint16_tdivider){//2 to 65536 |
| 149 | +if(!divider){ |
| 150 | +divider=0xFFFF; |
| 151 | + } elseif(divider==1){ |
| 152 | +divider=2; |
| 153 | + } |
| 154 | +inttimer_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_ttimerGetDivider(hw_timer_t*timer){ |
| 161 | +returntimer->dev->config.divider; |
| 162 | +} |
| 163 | + |
| 164 | +voidtimerStart(hw_timer_t*timer){ |
| 165 | +timer->dev->config.enable=1; |
| 166 | +} |
| 167 | + |
| 168 | +voidtimerStop(hw_timer_t*timer){ |
| 169 | +timer->dev->config.enable=0; |
| 170 | +} |
| 171 | + |
| 172 | +voidtimerRestart(hw_timer_t*timer){ |
| 173 | +timer->dev->config.enable=0; |
| 174 | +timer->dev->config.enable=1; |
| 175 | +} |
| 176 | + |
| 177 | +booltimerStarted(hw_timer_t*timer){ |
| 178 | +returntimer->dev->config.enable; |
| 179 | +} |
| 180 | + |
| 181 | +voidtimerAlarmEnable(hw_timer_t*timer){ |
| 182 | +timer->dev->config.alarm_en=1; |
| 183 | +} |
| 184 | + |
| 185 | +voidtimerAlarmDisable(hw_timer_t*timer){ |
| 186 | +timer->dev->config.alarm_en=0; |
| 187 | +} |
| 188 | + |
| 189 | +booltimerAlarmEnabled(hw_timer_t*timer){ |
| 190 | +returntimer->dev->config.alarm_en; |
| 191 | +} |
| 192 | + |
| 193 | + |
| 194 | + |
| 195 | +hw_timer_t*timerBegin(uint8_tnum, uint16_tdivider, boolcountUp){ |
| 196 | +if(num>3){ |
| 197 | +returnNULL; |
| 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 | +returntimer; |
| 217 | +} |
| 218 | + |
| 219 | +voidtimerEnd(hw_timer_t*timer){ |
| 220 | +timer->dev->config.enable=0; |
| 221 | +timerAttachInterrupt(timer, NULL, false); |
| 222 | +} |
| 223 | + |
| 224 | +voidtimerAttachInterrupt(hw_timer_t*timer, void (*fn)(void), booledge){ |
| 225 | +staticboolinitialized= 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 | +intintr_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 | +voidtimerDetachInterrupt(hw_timer_t*timer){ |
| 270 | +timerAttachInterrupt(timer, NULL, false); |
| 271 | +} |
| 272 | + |
| 273 | +uint64_ttimerReadMicros(hw_timer_t*timer){ |
| 274 | +uint64_ttimer_val=timerRead(timer); |
| 275 | +uint16_tdiv=timerGetDivider(timer); |
| 276 | +returntimer_val*div / 80; |
| 277 | +} |
| 278 | + |
| 279 | +doubletimerReadSeconds(hw_timer_t*timer){ |
| 280 | +uint64_ttimer_val=timerRead(timer); |
| 281 | +uint16_tdiv=timerGetDivider(timer); |
| 282 | +return (double)timer_val*div / 80000000; |
| 283 | +} |
| 284 | + |
| 285 | +uint64_ttimerAlarmReadMicros(hw_timer_t*timer){ |
| 286 | +uint64_ttimer_val=timerAlarmRead(timer); |
| 287 | +uint16_tdiv=timerGetDivider(timer); |
| 288 | +returntimer_val*div / 80; |
| 289 | +} |
| 290 | + |
| 291 | +doubletimerAlarmReadSeconds(hw_timer_t*timer){ |
| 292 | +uint64_ttimer_val=timerAlarmRead(timer); |
| 293 | +uint16_tdiv=timerGetDivider(timer); |
| 294 | +return (double)timer_val*div / 80000000; |
| 295 | +} |
0 commit comments