Skip to content

Commit fa485cd

Browse files
committed
Merge pull request #1231 from Makuna/ServoDetachFixes
Fix detach and attach
2 parents 695583e + 2425ee3 commit fa485cd

File tree

1 file changed

+59
-31
lines changed

1 file changed

+59
-31
lines changed

libraries/Servo/src/esp8266/Servo.cpp

+59-31
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
/*
2-
Copyright (c) 2015 Michael C. Miller. All right reserved.
2+
Copyright (c) 2015 Michael C. Miller. All right reserved.
33
4-
This library is free software; you can redistribute it and/or
5-
modify it under the terms of the GNU Lesser General Public
6-
License as published by the Free Software Foundation; either
7-
version 2.1 of the License, or (at your option) any later version.
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
88
9-
This library is distributed in the hope that it will be useful,
10-
but WITHOUT ANY WARRANTY; without even the implied warranty of
11-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12-
Lesser General Public License for more details.
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
Lesser General Public License for more details.
1313
14-
You should have received a copy of the GNU Lesser General Public
15-
License along with this library; if not, write to the Free Software
16-
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17-
*/
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
1818

1919
#if defined(ESP8266)
2020

@@ -26,9 +26,12 @@
2626

2727
const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays
2828

29+
#define INVALID_PIN 63 // flag indicating never attached servo
30+
2931
struct ServoInfo {
30-
uint8_t pin : 6; // a pin number from 0 to 63
32+
uint8_t pin : 6; // a pin number from 0 to 62, 63 reserved
3133
uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false
34+
uint8_t isDetaching : 1; // true if this channel is being detached, maintains pulse integrity
3235
};
3336

3437
struct ServoState {
@@ -76,29 +79,49 @@ static void Servo_Handler(T* timer)
7679
if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
7780
// pulse this channel low if activated
7881
digitalWrite(s_servos[servoIndex].info.pin, LOW);
82+
83+
if (s_servos[servoIndex].info.isDetaching) {
84+
s_servos[servoIndex].info.isActive = false;
85+
s_servos[servoIndex].info.isDetaching = false;
86+
}
7987
}
8088
timer->nextChannel();
8189
}
8290

8391
servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
8492

85-
if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) {
93+
if (servoIndex < s_servoCount &&
94+
timer->getCurrentChannel() < SERVOS_PER_TIMER) {
8695
timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);
8796

88-
if (s_servos[servoIndex].info.isActive) { // check if activated
89-
digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high
97+
if (s_servos[servoIndex].info.isActive) {
98+
if (s_servos[servoIndex].info.isDetaching) {
99+
// it was active, reset state and leave low
100+
s_servos[servoIndex].info.isActive = false;
101+
s_servos[servoIndex].info.isDetaching = false;
102+
}
103+
else {
104+
// its an active channel so pulse it high
105+
digitalWrite(s_servos[servoIndex].info.pin, HIGH);
106+
}
90107
}
91108
}
92109
else {
93-
// finished all channels so wait for the refresh period to expire before starting over
94-
// allow a few ticks to ensure the next match is not missed
95-
uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
96-
if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
97-
timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
110+
if (!isTimerActive(timer->timerId())) {
111+
// no active running channels on this timer, stop the ISR
112+
finISR(timer->timerId());
98113
}
99114
else {
100-
// at least REFRESH_INTERVAL has elapsed
101-
timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
115+
// finished all channels so wait for the refresh period to expire before starting over
116+
// allow a few ticks to ensure the next match is not missed
117+
uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
118+
if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
119+
timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
120+
}
121+
else {
122+
// at least REFRESH_INTERVAL has elapsed
123+
timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
124+
}
102125
}
103126

104127
timer->setEndOfCycle();
@@ -166,6 +189,10 @@ Servo::Servo()
166189
// set default _minUs and _maxUs incase write() is called before attach()
167190
_minUs = MIN_PULSE_WIDTH;
168191
_maxUs = MAX_PULSE_WIDTH;
192+
193+
s_servos[_servoIndex].info.isActive = false;
194+
s_servos[_servoIndex].info.isDetaching = false;
195+
s_servos[_servoIndex].info.pin = INVALID_PIN;
169196
}
170197
else {
171198
_servoIndex = INVALID_SERVO; // too many servos
@@ -182,9 +209,11 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
182209
ServoTimerSequence timerId;
183210

184211
if (_servoIndex < MAX_SERVOS) {
185-
pinMode(pin, OUTPUT); // set servo pin to output
186-
digitalWrite(pin, LOW);
187-
s_servos[_servoIndex].info.pin = pin;
212+
if (s_servos[_servoIndex].info.pin == INVALID_PIN) {
213+
pinMode(pin, OUTPUT); // set servo pin to output
214+
digitalWrite(pin, LOW);
215+
s_servos[_servoIndex].info.pin = pin;
216+
}
188217

189218
// keep the min and max within 200-3000 us, these are extreme
190219
// ranges and should support extreme servos while maintaining
@@ -197,6 +226,7 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
197226
if (!isTimerActive(timerId)) {
198227
initISR(timerId);
199228
}
229+
s_servos[_servoIndex].info.isDetaching = false;
200230
s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive
201231
}
202232
return _servoIndex;
@@ -206,10 +236,8 @@ void Servo::detach()
206236
{
207237
ServoTimerSequence timerId;
208238

209-
s_servos[_servoIndex].info.isActive = false;
210-
timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
211-
if (!isTimerActive(timerId)) {
212-
finISR(timerId);
239+
if (s_servos[_servoIndex].info.isActive) {
240+
s_servos[_servoIndex].info.isDetaching = true;
213241
}
214242
}
215243

0 commit comments

Comments
 (0)