1 #ifndef ServoDispatchPrivate_h
2 #define ServoDispatchPrivate_h
9 #ifndef ARDUINO_ARCH_ESP32
10 struct ServoDispatchISR
13 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
18 enum Timer16Order { kTimer16_5, kTimer16_1, kTimer16_3, kTimer16_4, kNumTimers16 };
19 #elif defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || \
20 defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
23 enum Timer16Order { kTimer16_3, kTimer16_1, kNumTimers16 };
24 #else // everything else
26 enum Timer16Order { kTimer16_1, kNumTimers16 };
28 #define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
29 #define MAX_SERVOS (kNumTimers16 * SERVOS_PER_TIMER)
30 #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel)
36 volatile uint8_t isActive:1;
46 volatile int8_t channel[kNumTimers16];
50 static Private* privates()
56 static unsigned int convertMicrosecToTicks(
unsigned int microsec)
58 return (clockCyclesPerMicrosecond() * microsec) / 8;
61 static unsigned int convertTicksToMicrosec(
unsigned int ticks)
63 return ((
unsigned)ticks * 8) / clockCyclesPerMicrosecond();
66 static inline void handle_interrupts(Timer16Order timer,
volatile uint16_t *TCNTn,
volatile uint16_t* OCRnA)
68 auto priv = privates();
69 volatile int8_t* timerChannel = &priv->channel[timer];
70 PWMChannel* servo = &priv->pwm[
SERVO_INDEX(timer, *timerChannel)];
71 if (*timerChannel < 0)
77 if (
SERVO_INDEX(timer,*timerChannel) < priv->ServoCount && servo->isActive ==
true)
78 digitalWrite(servo->pin,LOW);
82 servo = &priv->pwm[
SERVO_INDEX(timer, *timerChannel)];
90 if (servo->target > servo->ticks)
92 servo->ticks += servo->speed;
93 if (servo->target <= servo->ticks)
95 servo->ticks = servo->target;
101 servo->ticks -= servo->speed;
102 if (servo->target >= servo->ticks)
104 servo->ticks = servo->target;
112 *OCRnA = *TCNTn + servo->ticks;
113 if (servo->isActive ==
true)
114 digitalWrite(servo->pin,HIGH);
118 const unsigned kRefreshInterval = 20000;
120 unsigned long ticks = convertMicrosecToTicks(kRefreshInterval);
121 if ((
unsigned)*TCNTn < ticks + 4)
122 *OCRnA = (
unsigned int)ticks;
129 static Timer16Order channelToTimer(
byte channel)
134 static void initISR(
int channel)
136 Timer16Order timer = channelToTimer(channel);
137 if (!isTimerActive(timer))
141 #if defined (USE_TIMER1)
147 #if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
149 TIMSK |= _BV(OCIE1A) ;
153 TIMSK1 |= _BV(OCIE1A) ;
162 #if defined (USE_TIMER3)
168 #if defined(__AVR_ATmega128__)
170 ETIMSK |= _BV(OCIE3A);
173 TIMSK3 = _BV(OCIE3A) ;
182 #if defined (USE_TIMER4)
189 TIMSK4 = _BV(OCIE4A) ;
194 #if defined (USE_TIMER5)
201 TIMSK5 = _BV(OCIE5A) ;
210 auto priv = privates();
211 priv->pwm[channel].isActive =
true;
214 static boolean isTimerActive(Timer16Order timer)
216 auto priv = privates();
220 if (priv->pwm[
SERVO_INDEX(timer,channel)].isActive ==
true)
227 #if defined(USE_TIMER1)
231 ServoDispatchISR::handle_interrupts(ServoDispatchISR::kTimer16_1, &TCNT1, &OCR1A);
235 #if defined(USE_TIMER3)
237 ISR (TIMER3_COMPA_vect)
239 ServoDispatchISR::handle_interrupts(ServoDispatchISR::kTimer16_3, &TCNT3, &OCR3A);
243 #if defined(USE_TIMER4)
245 ISR (TIMER4_COMPA_vect)
247 ServoDispatchISR::handle_interrupts(ServoDispatchISR::kTimer16_4, &TCNT4, &OCR4A);
251 #if defined(USE_TIMER5)
253 ISR (TIMER5_COMPA_vect)
255 ServoDispatchISR::handle_interrupts(ServoDispatchISR::kTimer16_5, &TCNT5, &OCR5A);
266 #include "esp32-hal-ledc.h"
269 class ServoDispatchESP32
272 static constexpr
unsigned kNumPWM = 16;
280 ServoDispatchESP32* ChannelUsed[kNumPWM];
281 long timerFreqSet[4] = { -1, -1, -1, -1 };
282 bool explicateAllocationMode;
285 static Private* privates()
296 virtual ~ServoDispatchESP32()
303 void detachPin(
int pin)
309 void attachPin(uint8_t pin,
double freq, uint8_t resolution_bits = 10)
312 setup(freq, resolution_bits);
316 inline bool attached()
321 void write(uint32_t duty)
324 ledcWrite(getChannel(), duty);
327 void writeScaled(
float duty)
329 write(mapf(duty, 0.0, 1.0, 0, (
float) ((1 << fResolutionBits) - 1)));
332 void adjustFrequency(
double freq,
float dutyScaled = -1)
335 dutyScaled = getDutyScaled();
336 writeScaled(dutyScaled);
337 auto priv = privates();
338 auto ChannelUsed = priv->ChannelUsed;
339 for (
int i = 0; i < priv->timerCount[getTimer()]; i++)
341 int pwm = timerAndIndexToChannel(getTimer(), i);
342 if (ChannelUsed[pwm] !=
nullptr)
344 if (ChannelUsed[pwm]->fFreq != freq)
346 ChannelUsed[pwm]->adjustFrequencyLocal(freq, ChannelUsed[pwm]->getDutyScaled());
354 return ledcRead(getChannel());
362 float getDutyScaled()
364 return mapf((
float)fDuty, 0, (
float) ((1 << fResolutionBits) - 1), 0.0, 1.0);
367 static int timerAndIndexToChannel(
int timerNum,
int index)
370 for (
int j = 0; j < kNumPWM; j++)
372 if (((j / 2) % 4) == timerNum)
382 static void configureTimer(
int timerNumber)
384 if (timerNumber >= 0 && timerNumber < 4)
386 auto priv = privates();
387 if (priv->explicateAllocationMode ==
false)
389 priv->explicateAllocationMode =
true;
390 for (
int i = 0; i < 4; i++)
391 priv->timerCount[i] = 4;
393 priv->timerCount[timerNumber] = 0;
397 inline int getTimer()
402 inline int getChannel()
412 static bool validPWM(
int pin)
414 #ifdef CONFIG_IDF_TARGET_ESP32
417 return (pin == 2 || pin == 4 || pin == 5) ||
418 (pin >= 12 && pin <= 19) || (pin >= 21 && pin <= 23) ||
419 (pin >= 25 && pin <= 27) || (pin == 32 || pin == 33);
420 #elif CONFIG_IDF_TARGET_ESP32S2
423 return (pin >= 1 && pin <= 21) || (pin >= 33 && pin <= 44);
424 #elif CONFIG_IDF_TARGET_ESP32S3
427 if (pin >= 0 && pin <= 48)
433 if (pin >= 26 && pin <= 32)
436 if (pin >= 33 && pin <= 37)
443 #error Unsupported ESP32 platform
448 static int channelsRemaining()
450 return kNumPWM - privates()->PWMCount;
458 int fPWMChannel = -1;
459 bool fAttached =
false;
460 uint8_t fResolutionBits = 8;
462 static inline float mapf(
float x,
float in_min,
float in_max,
float out_min,
float out_max)
464 return (x > in_max) ? out_max : (x < in_min) ? out_min :
465 (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
468 static double _ledcSetupTimerFreq(uint8_t chan,
double freq, uint8_t bit_num)
470 return ledcSetup(chan, freq, bit_num);
479 void adjustFrequencyLocal(
double freq,
float dutyScaled)
481 privates()->timerFreqSet[getTimer()] = (long) freq;
487 _ledcSetupTimerFreq(getChannel(), freq, fResolutionBits);
488 writeScaled(dutyScaled);
489 ledcAttachPin(fPin, getChannel());
493 _ledcSetupTimerFreq(getChannel(), freq, fResolutionBits);
494 writeScaled(dutyScaled);
498 double setup(
double freq, uint8_t resolution_bits = 10)
500 auto priv = privates();
501 auto timerCount = priv->timerCount;
502 auto timerFreqSet = priv->timerFreqSet;
503 auto ChannelUsed = priv->ChannelUsed;
505 long freqlocal = (long)freq;
509 for (
int i = 0; i < 4; i++)
511 bool freqAllocated = (timerFreqSet[i] == freqlocal || timerFreqSet[i] == -1);
512 if (freqAllocated && timerCount[i] < 4)
514 if (timerFreqSet[i] == -1)
515 timerFreqSet[i] = freqlocal;
518 for (
int index = 0; index < 4; index++)
520 int myTimerNumber = timerAndIndexToChannel(fTimerNum, index);
521 if (myTimerNumber >= 0 && ChannelUsed[myTimerNumber] ==
nullptr)
523 fPWMChannel = myTimerNumber;
524 ChannelUsed[fPWMChannel] =
this;
525 timerCount[fTimerNum]++;
537 for (
int i = 0; i < priv->timerCount[getTimer()]; i++)
539 int pwm = timerAndIndexToChannel(getTimer(), i);
541 if (pwm == fPWMChannel || ChannelUsed[pwm] ==
nullptr ||
542 ChannelUsed[pwm]->getTimer() != getTimer())
546 double diff = abs(ChannelUsed[pwm]->fFreq - freq);
550 ChannelUsed[pwm]->fFreq = freq;
554 fResolutionBits = resolution_bits;
558 double val = ledcSetup(getChannel(), freq, resolution_bits);
562 return ledcSetup(getChannel(), freq, resolution_bits);
565 void attachPin(uint8_t pin)
573 ledcAttachPin(pin, getChannel());
580 auto priv = privates();
581 if (--priv->timerCount[getTimer()] == 0)
583 priv->timerFreqSet[getTimer()] = -1;
587 priv->ChannelUsed[fPWMChannel] =
nullptr;