Skip to content

Commit d7e0ec9

Browse files
authored
Simplify and improve the writeMicroseconds() calculations
Checked the calculations by hand Use Datasheet 7.3.5 Equation 1 for frequency from prescale https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf Frequency = (ClockFrequency/(PreScale+1))*(1/BitRate) and from the rest of the calculation us per period = PulseLength/Frequency us per bit = us per period/BitRate we can combine to get us per bit = (PulseLength/((ClockFrequency/(PreScale+1))*(1/BitRate)))*(1/BitRate) This can be simplified to (PulseLength (PreScale + 1))/ClockFrequency this formula was implemented in proposed code checked by setting chip frequency to 60Hz read prescale = 105 us per bit = 4.069 with 25Mhz (a PWM frequency of about 57.3hz) Choosing the FREQUENCY_CALIBRATED constant listed at 104.3% higher or 26.075MHz we get us per bit = 4.1035 or a PWM frequency of about 60.056Hz much closer to the set 60Hz Overall this change makes less calculation steps, and uses fewer variables. The change should be faster and more accurate to the intended results.
1 parent 95ee436 commit d7e0ec9

File tree

1 file changed

+6
-16
lines changed

1 file changed

+6
-16
lines changed

Adafruit_PWMServoDriver.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -296,24 +296,14 @@ void Adafruit_PWMServoDriver::writeMicroseconds(uint8_t num, uint16_t Microsecon
296296
double pulselength;
297297
pulselength = 1000000; // 1,000,000 us per second
298298

299-
// Read prescale and convert to frequency
299+
// Read prescale
300300
double prescale = Adafruit_PWMServoDriver::readPrescale();
301-
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
301+
Serial.print(prescale); Serial.println(" PCA9685 chip prescale");
311302

312-
#ifdef ENABLE_DEBUG_OUTPUT
313-
Serial.print(pulselength); Serial.println(" us per period");
314-
#endif
315-
316-
pulselength /= 4096; // 12 bits of resolution
303+
// Calculate the pulse for PWM based on Equation 1 from the datasheet section 7.3.5
304+
prescale += 1;
305+
pulselength *= prescale;
306+
pulselength /= FREQUENCY_CALIBRATED;
317307

318308
#ifdef ENABLE_DEBUG_OUTPUT
319309
Serial.print(pulselength); Serial.println(" us per bit");

0 commit comments

Comments
 (0)