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
/* !
@@ -146,21 +148,17 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
146
148
Serial.println (freq);
147
149
#endif
148
150
// Range output modulation frequency is dependant on oscillator
149
- if (freq < 1 ) freq = 1 ;
150
- if (freq > 3500 ) freq = 3500 ; // Datasheet limit is 3052=50MHz/(4*4096)
151
- /*
152
- freq *= 0.9; // Correct for overshoot in the frequency setting (see issue #11)
153
- float prescaleval = FREQUENCY_OSCILLATOR;
154
- */
155
- uint32_t prescaleval = FREQUENCY_CALIBRATED;
156
- prescaleval /= freq; // required output modulation frequency
157
- // rounding to nearest number is equal to adding 0,5 and floor to nearest number
158
- prescaleval += 2048 ;
159
- prescaleval /= 4096 ;
160
- prescaleval -= 1 ;
161
- if (prescaleval < PCA9685_PRESCALE_MIN) prescaleval = PCA9685_PRESCALE_MIN;
162
- if (prescaleval > PCA9685_PRESCALE_MAX) prescaleval = PCA9685_PRESCALE_MAX;
163
- uint8_t prescale = (uint8_t ) prescaleval;
151
+ if (freq < 1 )
152
+ freq = 1 ;
153
+ if (freq > 3500 )
154
+ freq = 3500 ; // Datasheet limit is 3052=50MHz/(4*4096)
155
+
156
+ float prescaleval = ((_oscillator_freq / (freq * 4096.0 )) + 0.5 ) - 1 ;
157
+ if (prescaleval < PCA9685_PRESCALE_MIN)
158
+ prescaleval = PCA9685_PRESCALE_MIN;
159
+ if (prescaleval > PCA9685_PRESCALE_MAX)
160
+ prescaleval = PCA9685_PRESCALE_MAX;
161
+ uint8_t prescale = (uint8_t )prescaleval;
164
162
165
163
#ifdef ENABLE_DEBUG_OUTPUT
166
164
Serial.print (" Final pre-scale: " );
@@ -183,22 +181,21 @@ void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
183
181
}
184
182
185
183
/* !
186
- * @brief Sets the output mode of the PCA9685 to either
187
- * open drain or push pull / totempole.
184
+ * @brief Sets the output mode of the PCA9685 to either
185
+ * open drain or push pull / totempole.
188
186
* Warning: LEDs with integrated zener diodes should
189
- * only be driven in open drain mode.
190
- * @param totempole Totempole if true, open drain if false.
187
+ * only be driven in open drain mode.
188
+ * @param totempole Totempole if true, open drain if false.
191
189
*/
192
- void Adafruit_PWMServoDriver::setOutputMode (bool totempole) {
193
- uint8_t oldmode = read8 (PCA9685_MODE2);
190
+ void Adafruit_PWMServoDriver::setOutputMode (bool totempole) {
191
+ uint8_t oldmode = read8 (PCA9685_MODE2);
194
192
uint8_t newmode;
195
193
if (totempole) {
196
194
newmode = oldmode | MODE2_OUTDRV;
197
- }
198
- else {
195
+ } else {
199
196
newmode = oldmode & ~MODE2_OUTDRV;
200
197
}
201
- write8 (PCA9685_MODE2, newmode);
198
+ write8 (PCA9685_MODE2, newmode);
202
199
#ifdef ENABLE_DEBUG_OUTPUT
203
200
Serial.print (" Setting output mode: " );
204
201
Serial.print (totempole ? " totempole" : " open drain" );
@@ -211,8 +208,7 @@ void Adafruit_PWMServoDriver::setOutputMode(bool totempole) {
211
208
* @brief Reads set Prescale from PCA9685
212
209
* @return prescale value
213
210
*/
214
- uint8_t Adafruit_PWMServoDriver::readPrescale (void )
215
- {
211
+ uint8_t Adafruit_PWMServoDriver::readPrescale (void ) {
216
212
return read8 (PCA9685_PRESCALE);
217
213
}
218
214
@@ -288,55 +284,74 @@ void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) {
288
284
}
289
285
290
286
/* !
291
- * @brief Sets the PWM output of one of the PCA9685 pins based on the input microseconds, output is not precise
287
+ * @brief Sets the PWM output of one of the PCA9685 pins based on the input
288
+ * microseconds, output is not precise
292
289
* @param num One of the PWM output pins, from 0 to 15
293
290
* @param Microseconds The number of Microseconds to turn the PWM output ON
294
291
*/
295
- void Adafruit_PWMServoDriver::writeMicroseconds (uint8_t num, uint16_t Microseconds) {
296
- #ifdef ENABLE_DEBUG_OUTPUT
292
+ void Adafruit_PWMServoDriver::writeMicroseconds (uint8_t num,
293
+ uint16_t Microseconds) {
294
+ #ifdef ENABLE_DEBUG_OUTPUT
297
295
Serial.print (" Setting PWM Via Microseconds on output" );
298
296
Serial.print (num);
299
297
Serial.print (" : " );
300
298
Serial.print (Microseconds);
301
299
Serial.println (" ->" );
302
- #endif
300
+ #endif
303
301
304
302
double pulse = Microseconds;
305
303
double pulselength;
306
- pulselength = 1000000 ; // 1,000,000 us per second
304
+ pulselength = 1000000 ; // 1,000,000 us per second
305
+
306
+ // Read prescale
307
+ uint16_t prescale = Adafruit_PWMServoDriver::readPrescale ();
308
+
309
+ #ifdef ENABLE_DEBUG_OUTPUT
310
+ Serial.print (prescale);
311
+ Serial.println (" PCA9685 chip prescale" );
312
+ #endif
307
313
308
- // Read prescale and convert to frequency
309
- double prescale = Adafruit_PWMServoDriver::readPrescale ();
314
+ // Calculate the pulse for PWM based on Equation 1 from the datasheet section
315
+ // 7.3.5
310
316
prescale += 1 ;
311
- uint32_t freq = 25000000 ; // Chip frequency is 25MHz
312
- freq /= prescale;
313
- freq /= 4096 ; // 12 bits of resolution
314
-
315
- #ifdef ENABLE_DEBUG_OUTPUT
316
- Serial.print (freq); Serial.println (" Calculated PCA9685 chip PWM Frequency" );
317
- #endif
318
-
319
- pulselength /= freq; // us per period from PCA9685 chip PWM Frequency using prescale reverse frequency calc
320
-
321
- #ifdef ENABLE_DEBUG_OUTPUT
322
- Serial.print (pulselength); Serial.println (" us per period" );
323
- #endif
324
-
325
- pulselength /= 4096 ; // 12 bits of resolution
326
-
327
- #ifdef ENABLE_DEBUG_OUTPUT
328
- Serial.print (pulselength); Serial.println (" us per bit" );
329
- #endif
317
+ pulselength *= prescale;
318
+ pulselength /= _oscillator_freq;
319
+
320
+ #ifdef ENABLE_DEBUG_OUTPUT
321
+ Serial.print (pulselength);
322
+ Serial.println (" us per bit" );
323
+ #endif
330
324
331
325
pulse /= pulselength;
332
326
333
- #ifdef ENABLE_DEBUG_OUTPUT
334
- Serial.print (pulse);Serial.println (" pulse for PWM" );
335
- #endif
327
+ #ifdef ENABLE_DEBUG_OUTPUT
328
+ Serial.print (pulse);
329
+ Serial.println (" pulse for PWM" );
330
+ #endif
336
331
337
332
Adafruit_PWMServoDriver::setPWM (num, 0 , pulse);
338
333
}
339
334
335
+ /* !
336
+ * @brief Getter for the internally tracked oscillator used for freq
337
+ * calculations
338
+ * @returns The frequency the PCA9685 thinks it is running at (it cannot
339
+ * introspect)
340
+ */
341
+ uint32_t Adafruit_PWMServoDriver::getOscillatorFrequency (void ) {
342
+ return _oscillator_freq;
343
+ }
344
+
345
+ /* !
346
+ * @brief Setter for the internally tracked oscillator used for freq
347
+ * calculations
348
+ * @param freq The frequency the PCA9685 should use for frequency calculations
349
+ */
350
+ void Adafruit_PWMServoDriver::setOscillatorFrequency (uint32_t freq) {
351
+ _oscillator_freq = freq;
352
+ }
353
+
354
+ /* ****************** Low level I2C interface */
340
355
uint8_t Adafruit_PWMServoDriver::read8 (uint8_t addr) {
341
356
_i2c->beginTransmission (_i2caddr);
342
357
_i2c->write (addr);
0 commit comments