30
30
#include " Adafruit_PWMServoDriver.h"
31
31
#include < Wire.h>
32
32
33
+ // #define ENABLE_DEBUG_OUTPUT
34
+
33
35
/* !
34
36
* @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
35
37
* TwoWire interface
36
38
*/
37
- Adafruit_PWMServoDriver::Adafruit_PWMServoDriver ():
38
- _i2caddr(PCA9685_I2C_ADDRESS), _i2c(&Wire) {
39
- }
39
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver ()
40
+ : _i2caddr(PCA9685_I2C_ADDRESS), _i2c(&Wire) {}
40
41
41
42
/* !
42
43
* @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
43
44
* TwoWire interface
44
45
* @param addr The 7-bit I2C address to locate this chip, default is 0x40
45
46
*/
46
- Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr):
47
- _i2caddr(addr), _i2c(&Wire) {
48
- }
47
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr)
48
+ : _i2caddr(addr), _i2c(&Wire) {}
49
49
50
50
/* !
51
51
* @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
@@ -54,9 +54,9 @@ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr):
54
54
* @param i2c A reference to a 'TwoWire' object that we'll use to communicate
55
55
* with
56
56
*/
57
- Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr, TwoWire& i2c) :
58
- _i2caddr(addr), _i2c( &i2c) {
59
- }
57
+ Adafruit_PWMServoDriver::Adafruit_PWMServoDriver (const uint8_t addr,
58
+ TwoWire &i2c)
59
+ : _i2caddr(addr), _i2c(&i2c) { }
60
60
61
61
/* !
62
62
* @brief Setups the I2C interface and hardware
@@ -72,6 +72,8 @@ void Adafruit_PWMServoDriver::begin(uint8_t prescale) {
72
72
// set a default frequency
73
73
setPWMFreq (1000 );
74
74
}
75
+ // set the default internal frequency
76
+ setOscillatorFrequency (FREQUENCY_OSCILLATOR);
75
77
}
76
78
77
79
/* !
@@ -137,21 +139,17 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
137
139
Serial.println (freq);
138
140
#endif
139
141
// 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 ;
150
- prescaleval /= 4096 ;
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;
142
+ if (freq < 1 )
143
+ freq = 1 ;
144
+ if (freq > 3500 )
145
+ freq = 3500 ; // Datasheet limit is 3052=50MHz/(4*4096)
146
+
147
+ float prescaleval = ((_oscillator_freq / (freq * 4096.0 )) + 0.5 ) - 1 ;
148
+ if (prescaleval < PCA9685_PRESCALE_MIN)
149
+ prescaleval = PCA9685_PRESCALE_MIN;
150
+ if (prescaleval > PCA9685_PRESCALE_MAX)
151
+ prescaleval = PCA9685_PRESCALE_MAX;
152
+ uint8_t prescale = (uint8_t )prescaleval;
155
153
156
154
#ifdef ENABLE_DEBUG_OUTPUT
157
155
Serial.print (" Final pre-scale: " );
@@ -160,12 +158,12 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
160
158
161
159
uint8_t oldmode = read8 (PCA9685_MODE1);
162
160
uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep
163
- write8 (PCA9685_MODE1, newmode); // go to sleep
164
- write8 (PCA9685_PRESCALE, prescale); // set the prescaler
161
+ write8 (PCA9685_MODE1, newmode); // go to sleep
162
+ write8 (PCA9685_PRESCALE, prescale); // set the prescaler
165
163
write8 (PCA9685_MODE1, oldmode);
166
164
delay (5 );
167
165
// This sets the MODE1 register to turn on auto increment.
168
- write8 (PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);
166
+ write8 (PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);
169
167
170
168
#ifdef ENABLE_DEBUG_OUTPUT
171
169
Serial.print (" Mode now 0x" );
@@ -174,22 +172,21 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
174
172
}
175
173
176
174
/* !
177
- * @brief Sets the output mode of the PCA9685 to either
178
- * open drain or push pull / totempole.
175
+ * @brief Sets the output mode of the PCA9685 to either
176
+ * open drain or push pull / totempole.
179
177
* Warning: LEDs with integrated zener diodes should
180
- * only be driven in open drain mode.
181
- * @param totempole Totempole if true, open drain if false.
178
+ * only be driven in open drain mode.
179
+ * @param totempole Totempole if true, open drain if false.
182
180
*/
183
- void Adafruit_PWMServoDriver::setOutputMode (bool totempole) {
184
- uint8_t oldmode = read8 (PCA9685_MODE2);
181
+ void Adafruit_PWMServoDriver::setOutputMode (bool totempole) {
182
+ uint8_t oldmode = read8 (PCA9685_MODE2);
185
183
uint8_t newmode;
186
184
if (totempole) {
187
185
newmode = oldmode | MODE2_OUTDRV;
188
- }
189
- else {
186
+ } else {
190
187
newmode = oldmode & ~MODE2_OUTDRV;
191
188
}
192
- write8 (PCA9685_MODE2, newmode);
189
+ write8 (PCA9685_MODE2, newmode);
193
190
#ifdef ENABLE_DEBUG_OUTPUT
194
191
Serial.print (" Setting output mode: " );
195
192
Serial.print (totempole ? " totempole" : " open drain" );
@@ -202,8 +199,7 @@ void Adafruit_PWMServoDriver::setOutputMode(bool totempole) {
202
199
* @brief Reads set Prescale from PCA9685
203
200
* @return prescale value
204
201
*/
205
- uint8_t Adafruit_PWMServoDriver::readPrescale (void )
206
- {
202
+ uint8_t Adafruit_PWMServoDriver::readPrescale (void ) {
207
203
return read8 (PCA9685_PRESCALE);
208
204
}
209
205
@@ -279,55 +275,74 @@ void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) {
279
275
}
280
276
281
277
/* !
282
- * @brief Sets the PWM output of one of the PCA9685 pins based on the input microseconds, output is not precise
278
+ * @brief Sets the PWM output of one of the PCA9685 pins based on the input
279
+ * microseconds, output is not precise
283
280
* @param num One of the PWM output pins, from 0 to 15
284
281
* @param Microseconds The number of Microseconds to turn the PWM output ON
285
282
*/
286
- void Adafruit_PWMServoDriver::writeMicroseconds (uint8_t num, uint16_t Microseconds) {
287
- #ifdef ENABLE_DEBUG_OUTPUT
283
+ void Adafruit_PWMServoDriver::writeMicroseconds (uint8_t num,
284
+ uint16_t Microseconds) {
285
+ #ifdef ENABLE_DEBUG_OUTPUT
288
286
Serial.print (" Setting PWM Via Microseconds on output" );
289
287
Serial.print (num);
290
288
Serial.print (" : " );
291
289
Serial.print (Microseconds);
292
290
Serial.println (" ->" );
293
- #endif
291
+ #endif
294
292
295
293
double pulse = Microseconds;
296
294
double pulselength;
297
- pulselength = 1000000 ; // 1,000,000 us per second
295
+ pulselength = 1000000 ; // 1,000,000 us per second
296
+
297
+ // Read prescale
298
+ uint16_t prescale = Adafruit_PWMServoDriver::readPrescale ();
299
+
300
+ #ifdef ENABLE_DEBUG_OUTPUT
301
+ Serial.print (prescale);
302
+ Serial.println (" PCA9685 chip prescale" );
303
+ #endif
298
304
299
- // Read prescale and convert to frequency
300
- double prescale = Adafruit_PWMServoDriver::readPrescale ();
305
+ // Calculate the pulse for PWM based on Equation 1 from the datasheet section
306
+ // 7.3.5
301
307
prescale += 1 ;
302
- uint32_t freq = 25000000 ; // Chip frequency is 25MHz
303
- freq /= prescale;
304
- freq /= 4096 ; // 12 bits of resolution
305
-
306
- #ifdef ENABLE_DEBUG_OUTPUT
307
- Serial.print (freq); Serial.println (" Calculated PCA9685 chip PWM Frequency" );
308
- #endif
309
-
310
- pulselength /= freq; // us per period from PCA9685 chip PWM Frequency using prescale reverse frequency calc
311
-
312
- #ifdef ENABLE_DEBUG_OUTPUT
313
- Serial.print (pulselength); Serial.println (" us per period" );
314
- #endif
315
-
316
- pulselength /= 4096 ; // 12 bits of resolution
317
-
318
- #ifdef ENABLE_DEBUG_OUTPUT
319
- Serial.print (pulselength); Serial.println (" us per bit" );
320
- #endif
308
+ pulselength *= prescale;
309
+ pulselength /= _oscillator_freq;
310
+
311
+ #ifdef ENABLE_DEBUG_OUTPUT
312
+ Serial.print (pulselength);
313
+ Serial.println (" us per bit" );
314
+ #endif
321
315
322
316
pulse /= pulselength;
323
317
324
- #ifdef ENABLE_DEBUG_OUTPUT
325
- Serial.print (pulse);Serial.println (" pulse for PWM" );
326
- #endif
318
+ #ifdef ENABLE_DEBUG_OUTPUT
319
+ Serial.print (pulse);
320
+ Serial.println (" pulse for PWM" );
321
+ #endif
327
322
328
323
Adafruit_PWMServoDriver::setPWM (num, 0 , pulse);
329
324
}
330
325
326
+ /* !
327
+ * @brief Getter for the internally tracked oscillator used for freq
328
+ * calculations
329
+ * @returns The frequency the PCA9685 thinks it is running at (it cannot
330
+ * introspect)
331
+ */
332
+ uint32_t Adafruit_PWMServoDriver::getOscillatorFrequency (void ) {
333
+ return _oscillator_freq;
334
+ }
335
+
336
+ /* !
337
+ * @brief Setter for the internally tracked oscillator used for freq
338
+ * calculations
339
+ * @param freq The frequency the PCA9685 should use for frequency calculations
340
+ */
341
+ void Adafruit_PWMServoDriver::setOscillatorFrequency (uint32_t freq) {
342
+ _oscillator_freq = freq;
343
+ }
344
+
345
+ /* ****************** Low level I2C interface */
331
346
uint8_t Adafruit_PWMServoDriver::read8 (uint8_t addr) {
332
347
_i2c->beginTransmission (_i2caddr);
333
348
_i2c->write (addr);
0 commit comments