ESP32Encoder
ESP32Encoder.cpp
Go to the documentation of this file.
1 /*
2  * ESP32Encoder.cpp
3  *
4  * Created on: Oct 15, 2018
5  * Author: hephaestus
6  */
7 
8 #include <ESP32Encoder.h>
9 
10 //static ESP32Encoder *gpio2enc[48];
11 //
12 //
15  NULL,
16  NULL, NULL, NULL, NULL };
17 
19 pcnt_isr_handle_t ESP32Encoder::user_isr_handle = NULL;
20 
22  attached = false;
23  aPinNumber = (gpio_num_t) 0;
24  bPinNumber = (gpio_num_t) 0;
25  working = false;
26  direction = false;
27  unit = (pcnt_unit_t) -1;
28 }
29 
31 }
32 
33 /* Decode what PCNT's unit originated an interrupt
34  * and pass this information together with the event type
35  * the main program using a queue.
36  */
37 static void IRAM_ATTR pcnt_example_intr_handler(void *arg) {
38  ESP32Encoder * ptr;
39 
40  uint32_t intr_status = PCNT.int_st.val;
41  int i;
42 
43  for (i = 0; i < PCNT_UNIT_MAX; i++) {
44  if (intr_status & (BIT(i))) {
45  ptr = ESP32Encoder::encoders[i];
46  /* Save the PCNT event type that caused an interrupt
47  to pass it to the main program */
48 
49  int64_t status=0;
50  if(PCNT.status_unit[i].h_lim_lat){
51  status=ptr->r_enc_config.counter_h_lim;
52  }
53  if(PCNT.status_unit[i].l_lim_lat){
54  status=ptr->r_enc_config.counter_l_lim;
55  }
56  //pcnt_counter_clear(ptr->unit);
57  PCNT.int_clr.val = BIT(i); // clear the interrupt
58  ptr->count = status + ptr->count;
59  }
60  }
61 }
62 
63 void ESP32Encoder::attach(int a, int b, enum encType et) {
64  if (attached) {
65  Serial.println("Already attached, FAIL!");
66  return;
67  }
68  int index = 0;
69  for (; index < MAX_ESP32_ENCODERS; index++) {
70  if (ESP32Encoder::encoders[index] == NULL) {
71  encoders[index] = this;
72  break;
73  }
74  }
75  if (index == MAX_ESP32_ENCODERS) {
76  Serial.println("Too many encoders, FAIL!");
77  return;
78  }
79 
80  // Set data now that pin attach checks are done
81  fullQuad = et != single;
82  unit = (pcnt_unit_t) index;
83  this->aPinNumber = (gpio_num_t) a;
84  this->bPinNumber = (gpio_num_t) b;
85 
86  //Set up the IO state of hte pin
87  gpio_pad_select_gpio(aPinNumber);
88  gpio_pad_select_gpio(bPinNumber);
89  gpio_set_direction(aPinNumber, GPIO_MODE_INPUT);
90  gpio_set_direction(bPinNumber, GPIO_MODE_INPUT);
92  gpio_pulldown_en(aPinNumber);
93  gpio_pulldown_en(bPinNumber);
94  }
96  gpio_pullup_en(aPinNumber);
97  gpio_pullup_en(bPinNumber);
98  }
99  // Set up encoder PCNT configuration
100  r_enc_config.pulse_gpio_num = aPinNumber; //Rotary Encoder Chan A
101  r_enc_config.ctrl_gpio_num = bPinNumber; //Rotary Encoder Chan B
102 
103  r_enc_config.unit = unit;
104  r_enc_config.channel = PCNT_CHANNEL_0;
105 
106  r_enc_config.pos_mode = fullQuad ? PCNT_COUNT_DEC : PCNT_COUNT_DIS; //Count Only On Rising-Edges
107  r_enc_config.neg_mode = PCNT_COUNT_INC; // Discard Falling-Edge
108 
109  r_enc_config.lctrl_mode = PCNT_MODE_KEEP; // Rising A on HIGH B = CW Step
110  r_enc_config.hctrl_mode = PCNT_MODE_REVERSE; // Rising A on LOW B = CCW Step
111 
112  r_enc_config .counter_h_lim = _INT16_MAX;
113  r_enc_config .counter_l_lim = _INT16_MIN ;
114 
115  pcnt_unit_config(&r_enc_config);
116 
117  if (et == full) {
118  // set up second channel for full quad
119  r_enc_config.pulse_gpio_num = bPinNumber; //make prior control into signal
120  r_enc_config.ctrl_gpio_num = aPinNumber; //and prior signal into control
121 
122  r_enc_config.unit = unit;
123  r_enc_config.channel = PCNT_CHANNEL_1; // channel 1
124 
125  r_enc_config.pos_mode = PCNT_COUNT_DEC; //Count Only On Rising-Edges
126  r_enc_config.neg_mode = PCNT_COUNT_INC; // Discard Falling-Edge
127 
128  r_enc_config.lctrl_mode = PCNT_MODE_REVERSE; // prior high mode is now low
129  r_enc_config.hctrl_mode = PCNT_MODE_KEEP; // prior low mode is now high
130 
131  r_enc_config .counter_h_lim = _INT16_MAX;
132  r_enc_config .counter_l_lim = _INT16_MIN ;
133 
134  pcnt_unit_config(&r_enc_config);
135  } else { // make sure channel 1 is not set when not full quad
136  r_enc_config.pulse_gpio_num = bPinNumber; //make prior control into signal
137  r_enc_config.ctrl_gpio_num = aPinNumber; //and prior signal into control
138 
139  r_enc_config.unit = unit;
140  r_enc_config.channel = PCNT_CHANNEL_1; // channel 1
141 
142  r_enc_config.pos_mode = PCNT_COUNT_DIS; //disabling channel 1
143  r_enc_config.neg_mode = PCNT_COUNT_DIS; // disabling channel 1
144 
145  r_enc_config.lctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1
146  r_enc_config.hctrl_mode = PCNT_MODE_DISABLE; // disabling channel 1
147 
148  r_enc_config .counter_h_lim = _INT16_MAX;
149  r_enc_config .counter_l_lim = _INT16_MIN ;
150 
151  pcnt_unit_config(&r_enc_config);
152  }
153 
154 
155  // Filter out bounces and noise
156  setFilter(250); // Filter Runt Pulses
157 
158  /* Enable events on maximum and minimum limit values */
159  pcnt_event_enable(unit, PCNT_EVT_H_LIM);
160  pcnt_event_enable(unit, PCNT_EVT_L_LIM);
161 
162  pcnt_counter_pause(unit); // Initial PCNT init
163  pcnt_counter_clear(unit);
164  /* Register ISR handler and enable interrupts for PCNT unit */
165  if(attachedInterrupt==false){
166  attachedInterrupt=true;
167  esp_err_t er = pcnt_isr_register(pcnt_example_intr_handler,(void *) NULL, (int)0,
168  (pcnt_isr_handle_t *)&ESP32Encoder::user_isr_handle);
169  if (er != ESP_OK){
170  Serial.println("Encoder wrap interrupt failed");
171  }
172  }
173  pcnt_intr_enable(unit);
174  pcnt_counter_resume(unit);
175 
176 }
177 
178 void ESP32Encoder::attachHalfQuad(int aPintNumber, int bPinNumber) {
179  attach(aPintNumber, bPinNumber, half);
180 
181 }
182 void ESP32Encoder::attachSingleEdge(int aPintNumber, int bPinNumber) {
183  attach(aPintNumber, bPinNumber, single);
184 }
185 void ESP32Encoder::attachFullQuad(int aPintNumber, int bPinNumber) {
186  attach(aPintNumber, bPinNumber, full);
187 }
188 
189 void ESP32Encoder::setCount(int64_t value) {
190  count = value - getCountRaw();
191 }
193  int16_t c;
194  pcnt_get_counter_value(unit, &c);
195  return c;
196 }
198  return getCountRaw() + count;
199 }
200 
202  count = 0;
203  return pcnt_counter_clear(unit);
204 }
205 
207  return pcnt_counter_pause(unit);
208 }
209 
211  return pcnt_counter_resume(unit);
212 }
213 
214 void ESP32Encoder::setFilter(uint16_t value) {
215  if(value==0) {
216  pcnt_filter_disable(unit);
217  } else {
218  pcnt_set_filter_value(unit, value);
219  pcnt_filter_enable(unit);
220  }
221 
222 }
pcnt_config_t r_enc_config
Definition: ESP32Encoder.h:52
#define _INT16_MAX
Definition: ESP32Encoder.h:6
encType
Definition: ESP32Encoder.h:9
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
#define _INT16_MIN
Definition: ESP32Encoder.h:7
int64_t resumeCount()
void setFilter(uint16_t value)
void attachHalfQuad(int aPintNumber, int bPinNumber)
void attachSingleEdge(int aPintNumber, int bPinNumber)
void setCount(int64_t value)
static pcnt_isr_handle_t user_isr_handle
Definition: ESP32Encoder.h:25
int64_t pauseCount()
pcnt_unit_t unit
Definition: ESP32Encoder.h:48
volatile int64_t count
Definition: ESP32Encoder.h:51
#define MAX_ESP32_ENCODERS
Definition: ESP32Encoder.h:5
void attach(int aPintNumber, int bPinNumber, enum encType et)
gpio_num_t aPinNumber
Definition: ESP32Encoder.h:46
boolean attached
Definition: ESP32Encoder.h:22
int64_t getCount()
static ESP32Encoder * encoders[MAX_ESP32_ENCODERS]
Definition: ESP32Encoder.h:45
puType
Definition: ESP32Encoder.h:14
gpio_num_t bPinNumber
Definition: ESP32Encoder.h:47
static enum puType useInternalWeakPullResistors
Definition: ESP32Encoder.h:53
static bool attachedInterrupt
Definition: ESP32Encoder.h:29
void attachFullQuad(int aPintNumber, int bPinNumber)
int64_t getCountRaw()
int64_t clearCount()