30
30
#include " Adafruit_PWMServoDriver.h"
31
31
#include < Wire.h>
32
32
33
+ /* !
34
+ * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
35
+ * TwoWire interface
36
+ */
37
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver ():
38
+ _i2caddr(PCA9685_I2C_ADDRESS), _i2c(&Wire) {
39
+ }
40
+
41
+ /* !
42
+ * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
43
+ * TwoWire interface
44
+ * @param addr The 7-bit I2C address to locate this chip, default is 0x40
45
+ */
46
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr):
47
+ _i2caddr(addr), _i2c(&Wire) {
48
+ }
49
+
33
50
/* !
34
51
* @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
35
52
* TwoWire interface
36
53
* @param addr The 7-bit I2C address to locate this chip, default is 0x40
37
- * @param i2c A pointer to a 'Wire' compatible object that we'll use to
38
- * communicate with
54
+ * @param i2c A reference to a 'TwoWire' object that we'll use to communicate
55
+ * with
39
56
*/
40
- Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (uint8_t addr, TwoWire *i2c) {
41
- _i2c = i2c;
42
- _i2caddr = addr;
57
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr, TwoWire& i2c) :
58
+ _i2caddr(addr), _i2c(&i2c) {
43
59
}
44
60
45
61
/* !
46
62
* @brief Setups the I2C interface and hardware
47
63
* @param prescale
48
64
* Sets External Clock (Optional)
49
- *
50
65
*/
51
66
void Adafruit_PWMServoDriver::begin (uint8_t prescale) {
52
67
_i2c->begin ();
@@ -63,7 +78,7 @@ void Adafruit_PWMServoDriver::begin(uint8_t prescale) {
63
78
* @brief Sends a reset command to the PCA9685 chip over I2C
64
79
*/
65
80
void Adafruit_PWMServoDriver::reset () {
66
- write8 (PCA9685_MODE1, 0x80 );
81
+ write8 (PCA9685_MODE1, MODE1_RESTART );
67
82
delay (10 );
68
83
}
69
84
@@ -72,7 +87,7 @@ void Adafruit_PWMServoDriver::reset() {
72
87
*/
73
88
void Adafruit_PWMServoDriver::sleep () {
74
89
uint8_t awake = read8 (PCA9685_MODE1);
75
- uint8_t sleep = awake | 0x10 ; // set sleep bit high
90
+ uint8_t sleep = awake | MODE1_SLEEP ; // set sleep bit high
76
91
write8 (PCA9685_MODE1, sleep);
77
92
delay (5 ); // wait until cycle ends for sleep to be active
78
93
}
@@ -82,31 +97,29 @@ void Adafruit_PWMServoDriver::sleep() {
82
97
*/
83
98
void Adafruit_PWMServoDriver::wakeup () {
84
99
uint8_t sleep = read8 (PCA9685_MODE1);
85
- uint8_t wakeup = sleep & ~0x10 ; // set sleep bit low
100
+ uint8_t wakeup = sleep & ~MODE1_SLEEP ; // set sleep bit low
86
101
write8 (PCA9685_MODE1, wakeup);
87
102
}
88
103
89
- /* *************************************************************************/
90
104
/* !
91
- @brief Sets EXTCLK pin to use the external clock
92
- @param prescale Configures the prescale value to be used by the external
93
- clock
94
- */
95
- /* *************************************************************************/
105
+ * @brief Sets EXTCLK pin to use the external clock
106
+ * @param prescale
107
+ * Configures the prescale value to be used by the external clock
108
+ */
96
109
void Adafruit_PWMServoDriver::setExtClk (uint8_t prescale) {
97
110
uint8_t oldmode = read8 (PCA9685_MODE1);
98
- uint8_t newmode = (oldmode & 0x7F ) | 0x10 ; // sleep
111
+ uint8_t newmode = (oldmode & ~MODE1_RESTART ) | MODE1_SLEEP ; // sleep
99
112
write8 (PCA9685_MODE1, newmode); // go to sleep, turn off internal oscillator
100
113
101
114
// This sets both the SLEEP and EXTCLK bits of the MODE1 register to switch to
102
115
// use the external clock.
103
- write8 (PCA9685_MODE1, (newmode |= 0x40 ));
116
+ write8 (PCA9685_MODE1, (newmode |= MODE1_EXTCLK ));
104
117
105
118
write8 (PCA9685_PRESCALE, prescale); // set the prescaler
106
119
107
120
delay (5 );
108
- write8 (PCA9685_MODE1,
109
- (newmode & ~( 0x10 )) | 0xa0 ); // clear the SLEEP bit to start
121
+ // clear the SLEEP bit to start
122
+ write8 (PCA9685_MODE1, (newmode & ~MODE1_SLEEP) | MODE1_RESTART | MODE1_AI);
110
123
111
124
#ifdef ENABLE_DEBUG_OUTPUT
112
125
Serial.print (" Mode now 0x" );
@@ -123,34 +136,36 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
123
136
Serial.print (" Attempting to set freq " );
124
137
Serial.println (freq);
125
138
#endif
126
-
127
- freq *=
128
- 0.9 ; // Correct for overshoot in the frequency setting (see issue #11).
129
- float prescaleval = 25000000 ;
139
+ // Range output modulation frequency is dependant on oscillator
140
+ if (freq < 1 ) freq = 1 ;
141
+ if (freq > 3500 ) freq = 3500 ; // Datasheet limit is 3052=50MHz/(4*4096)
142
+ /*
143
+ freq *= 0.9; // Correct for overshoot in the frequency setting (see issue #11)
144
+ float prescaleval = FREQUENCY_OSCILLATOR;
145
+ */
146
+ uint32_t prescaleval = FREQUENCY_CALIBRATED;
147
+ prescaleval /= freq; // required output modulation frequency
148
+ // rounding to nearest number is equal to adding 0,5 and floor to nearest number
149
+ prescaleval += 2048 ;
130
150
prescaleval /= 4096 ;
131
- prescaleval /= freq;
132
151
prescaleval -= 1 ;
152
+ if (prescaleval < PCA9685_PRESCALE_MIN) prescaleval = PCA9685_PRESCALE_MIN;
153
+ if (prescaleval > PCA9685_PRESCALE_MAX) prescaleval = PCA9685_PRESCALE_MAX;
154
+ uint8_t prescale = (uint8_t ) prescaleval;
133
155
134
- #ifdef ENABLE_DEBUG_OUTPUT
135
- Serial.print (" Estimated pre-scale: " );
136
- Serial.println (prescaleval);
137
- #endif
138
-
139
- uint8_t prescale = floor (prescaleval + 0.5 );
140
156
#ifdef ENABLE_DEBUG_OUTPUT
141
157
Serial.print (" Final pre-scale: " );
142
158
Serial.println (prescale);
143
159
#endif
144
160
145
161
uint8_t oldmode = read8 (PCA9685_MODE1);
146
- uint8_t newmode = (oldmode & 0x7F ) | 0x10 ; // sleep
162
+ uint8_t newmode = (oldmode & ~MODE1_RESTART ) | MODE1_SLEEP ; // sleep
147
163
write8 (PCA9685_MODE1, newmode); // go to sleep
148
164
write8 (PCA9685_PRESCALE, prescale); // set the prescaler
149
165
write8 (PCA9685_MODE1, oldmode);
150
166
delay (5 );
151
- write8 (PCA9685_MODE1,
152
- oldmode |
153
- 0xa0 ); // This sets the MODE1 register to turn on auto increment.
167
+ // This sets the MODE1 register to turn on auto increment.
168
+ write8 (PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);
154
169
155
170
#ifdef ENABLE_DEBUG_OUTPUT
156
171
Serial.print (" Mode now 0x" );
@@ -169,10 +184,10 @@ void Adafruit_PWMServoDriver::setOutputMode(bool totempole) {
169
184
uint8_t oldmode = read8 (PCA9685_MODE2);
170
185
uint8_t newmode;
171
186
if (totempole) {
172
- newmode = ( oldmode& 0x7F ) | 0x04 ;
187
+ newmode = oldmode | MODE2_OUTDRV ;
173
188
}
174
189
else {
175
- newmode = ( oldmode& 0x7F ) & ~0x04 ;
190
+ newmode = oldmode & ~MODE2_OUTDRV ;
176
191
}
177
192
write8 (PCA9685_MODE2, newmode);
178
193
#ifdef ENABLE_DEBUG_OUTPUT
@@ -183,13 +198,22 @@ void Adafruit_PWMServoDriver::setOutputMode(bool totempole) {
183
198
#endif
184
199
}
185
200
201
+ /* !
202
+ * @brief Reads set Prescale from PCA9685
203
+ * @return prescale value
204
+ */
205
+ uint8_t Adafruit_PWMServoDriver::readPrescale (void )
206
+ {
207
+ return read8 (PCA9685_PRESCALE);
208
+ }
209
+
186
210
/* !
187
211
* @brief Gets the PWM output of one of the PCA9685 pins
188
212
* @param num One of the PWM output pins, from 0 to 15
189
213
* @return requested PWM output value
190
214
*/
191
215
uint8_t Adafruit_PWMServoDriver::getPWM (uint8_t num) {
192
- _i2c->requestFrom ((int )_i2caddr, LED0_ON_L + 4 * num, (int )4 );
216
+ _i2c->requestFrom ((int )_i2caddr, PCA9685_LED0_ON_L + 4 * num, (int )4 );
193
217
return _i2c->read ();
194
218
}
195
219
@@ -210,7 +234,7 @@ void Adafruit_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
210
234
#endif
211
235
212
236
_i2c->beginTransmission (_i2caddr);
213
- _i2c->write (LED0_ON_L + 4 * num);
237
+ _i2c->write (PCA9685_LED0_ON_L + 4 * num);
214
238
_i2c->write (on);
215
239
_i2c->write (on >> 8 );
216
240
_i2c->write (off);
0 commit comments