/ MCUME_esp32 / espboot / components / Audio / esp32-hal-timer.c
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  }