21
21
#include < Arduino.h>
22
22
#include < Servo.h>
23
23
24
+ static uintptr_t _servoToken = (uintptr_t )(&_servoToken);
24
25
25
26
static servo_t servos[MAX_SERVOS]; // static array of servo structures
26
27
uint8_t ServoCount = 0 ; // the total number of attached servos
@@ -32,7 +33,6 @@ Servo::Servo()
32
33
} else {
33
34
this ->servoIndex = INVALID_SERVO; // too many servos
34
35
}
35
-
36
36
this ->pwm = NULL ;
37
37
}
38
38
@@ -43,55 +43,81 @@ uint8_t Servo::attach(int pin)
43
43
44
44
uint8_t Servo::attach (int pin, int min, int max)
45
45
{
46
- if (this ->servoIndex < MAX_SERVOS) {
47
- pinMode (pin, OUTPUT); // set servo pin to output
48
- servos[this ->servoIndex ].Pin .nbr = pin;
49
-
50
- if (min < MIN_PULSE_WIDTH) min = MIN_PULSE_WIDTH;
51
- if (max > MAX_PULSE_WIDTH) max = MAX_PULSE_WIDTH;
52
-
53
- // fix min if conversion to pulse cycle value is too low
54
- if ((min/DUTY_CYCLE_RESOLUTION)*DUTY_CYCLE_RESOLUTION<min) min+=DUTY_CYCLE_RESOLUTION;
55
-
56
- this ->min = min;
57
- this ->max = max;
58
-
59
- servos[this ->servoIndex ].Pin .isActive = true ;
60
-
61
- // Adafruit, add pin to 1 of available Hw PWM
62
- for (int i=0 ; i<HWPWM_MODULE_NUM; i++)
63
- {
64
- if ( HwPWMx[i]->addPin (pin) )
65
- {
46
+ if (this ->servoIndex == INVALID_SERVO) {
47
+ return INVALID_SERVO;
48
+ }
49
+ bool succeeded = false ;
50
+ pinMode (pin, OUTPUT); // set servo pin to output
51
+ servos[this ->servoIndex ].Pin .nbr = pin;
52
+
53
+ if (min < MIN_PULSE_WIDTH) {
54
+ min = MIN_PULSE_WIDTH;
55
+ }
56
+ if (max > MAX_PULSE_WIDTH) {
57
+ max = MAX_PULSE_WIDTH;
58
+ }
59
+
60
+ // fix min if conversion to pulse cycle value is too low
61
+ if ( (min/DUTY_CYCLE_RESOLUTION) * DUTY_CYCLE_RESOLUTION < min) {
62
+ min += DUTY_CYCLE_RESOLUTION;
63
+ }
64
+
65
+ this ->min = min;
66
+ this ->max = max;
67
+
68
+ servos[this ->servoIndex ].Pin .isActive = true ;
69
+
70
+ // Adafruit, add pin to 1 of available Hw PWM
71
+ // first, use existing HWPWM modules (already owned by Servo)
72
+ for (int i=0 ; i<HWPWM_MODULE_NUM; i++) {
73
+ if (HwPWMx[i]->isOwner (_servoToken) &&
74
+ HwPWMx[i]->addPin (pin)) {
75
+ this ->pwm = HwPWMx[i];
76
+ succeeded = true ;
77
+ break ;
78
+ }
79
+ }
80
+ // if could not add to existing owned PWM modules, try to add to a new PWM module
81
+ if (!succeeded) {
82
+ for (int i=0 ; i<HWPWM_MODULE_NUM; i++) {
83
+ if (HwPWMx[i]->takeOwnership (_servoToken) &&
84
+ HwPWMx[i]->addPin (pin)) {
66
85
this ->pwm = HwPWMx[i];
86
+ succeeded = true ;
67
87
break ;
68
88
}
69
89
}
90
+ }
70
91
92
+ if (succeeded) { // do not use this->pwm unless success above!
71
93
this ->pwm ->setMaxValue (MAXVALUE);
72
94
this ->pwm ->setClockDiv (CLOCKDIV);
73
-
74
95
}
75
- return this ->servoIndex ;
96
+ return succeeded ? this ->servoIndex : INVALID_SERVO; // return INVALID_SERVO on failure (zero is a valid servo index)
76
97
}
77
98
78
99
void Servo::detach ()
79
100
{
80
- uint8_t const pin = servos[ this ->servoIndex ]. Pin . nbr ;
81
-
82
- servos[ this -> servoIndex ]. Pin . isActive = false ;
101
+ if ( this ->servoIndex == INVALID_SERVO) {
102
+ return ;
103
+ }
83
104
84
- // remove pin from HW PWM
85
- this ->pwm ->removePin (pin);
105
+ uint8_t const pin = servos[this ->servoIndex ].Pin .nbr ;
106
+ servos[this ->servoIndex ].Pin .isActive = false ;
107
+ // remove pin from HW PWM
108
+ HardwarePWM * pwm = this ->pwm ;
109
+ this ->pwm = nullptr ;
110
+ pwm->removePin (pin);
111
+ pwm->releaseOwnership (_servoToken); // ignore failure ... which happens if a pin is still in use, for example
86
112
}
87
113
88
-
89
114
void Servo::write (int value)
90
- {
91
- if (value < 0 )
115
+ {
116
+ if (value < 0 ) {
92
117
value = 0 ;
93
- else if (value > 180 )
118
+ } else if (value > 180 ) {
94
119
value = 180 ;
120
+ }
95
121
value = map (value, 0 , 180 , this ->min , this ->max );
96
122
97
123
writeMicroseconds (value);
@@ -100,9 +126,10 @@ void Servo::write(int value)
100
126
101
127
void Servo::writeMicroseconds (int value)
102
128
{
103
- uint8_t pin = servos[this ->servoIndex ].Pin .nbr ;
104
-
105
- if ( this ->pwm ) this ->pwm ->writePin (pin, value/DUTY_CYCLE_RESOLUTION);
129
+ if (this ->pwm ) { // pwm is only set when this->servoIndex != INVALID_SERVO
130
+ uint8_t pin = servos[this ->servoIndex ].Pin .nbr ;
131
+ this ->pwm ->writePin (pin, value/DUTY_CYCLE_RESOLUTION);
132
+ }
106
133
}
107
134
108
135
int Servo::read () // return the value as degrees
@@ -112,15 +139,18 @@ int Servo::read() // return the value as degrees
112
139
113
140
int Servo::readMicroseconds ()
114
141
{
115
- uint8_t pin = servos[ this ->servoIndex ]. Pin . nbr ;
116
-
117
- if ( this -> pwm ) return this ->pwm ->readPin (pin)*DUTY_CYCLE_RESOLUTION;
118
-
142
+ if ( this ->pwm ) { // pwm is only set when this-> servoIndex != INVALID_SERVO
143
+ uint8_t pin = servos[ this -> servoIndex ]. Pin . nbr ;
144
+ return this ->pwm ->readPin (pin)*DUTY_CYCLE_RESOLUTION;
145
+ }
119
146
return 0 ;
120
147
}
121
148
122
149
bool Servo::attached ()
123
150
{
151
+ if (this ->servoIndex == INVALID_SERVO) {
152
+ return false ;
153
+ }
124
154
return servos[this ->servoIndex ].Pin .isActive ;
125
155
}
126
156
0 commit comments