Adafruit_PWMServoDriver.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*!
  2. * @file Adafruit_PWMServoDriver.cpp
  3. *
  4. * @mainpage Adafruit 16-channel PWM & Servo driver
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * This is a library for the 16-channel PWM & Servo driver.
  9. *
  10. * Designed specifically to work with the Adafruit PWM & Servo driver.
  11. *
  12. * Pick one up today in the adafruit shop!
  13. * ------> https://www.adafruit.com/product/815
  14. *
  15. * These displays use I2C to communicate, 2 pins are required to interface.
  16. *
  17. * Adafruit invests time and resources providing this open source code,
  18. * please support Adafruit andopen-source hardware by purchasing products
  19. * from Adafruit!
  20. *
  21. * @section author Author
  22. *
  23. * Limor Fried/Ladyada (Adafruit Industries).
  24. *
  25. * @section license License
  26. *
  27. * BSD license, all text above must be included in any redistribution
  28. */
  29. #include "Adafruit_PWMServoDriver.h"
  30. #include <Wire.h>
  31. //#define ENABLE_DEBUG_OUTPUT
  32. /*!
  33. * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
  34. * TwoWire interface
  35. */
  36. Adafruit_PWMServoDriver::Adafruit_PWMServoDriver()
  37. : _i2caddr(PCA9685_I2C_ADDRESS), _i2c(&Wire) {}
  38. /*!
  39. * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
  40. * TwoWire interface
  41. * @param addr The 7-bit I2C address to locate this chip, default is 0x40
  42. */
  43. Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr)
  44. : _i2caddr(addr), _i2c(&Wire) {}
  45. /*!
  46. * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a
  47. * TwoWire interface
  48. * @param addr The 7-bit I2C address to locate this chip, default is 0x40
  49. * @param i2c A reference to a 'TwoWire' object that we'll use to communicate
  50. * with
  51. */
  52. Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr,
  53. TwoWire &i2c)
  54. : _i2caddr(addr), _i2c(&i2c) {}
  55. /*!
  56. * @brief Setups the I2C interface and hardware
  57. * @param prescale
  58. * Sets External Clock (Optional)
  59. */
  60. void Adafruit_PWMServoDriver::begin(uint8_t prescale) {
  61. _i2c->begin();
  62. reset();
  63. if (prescale) {
  64. setExtClk(prescale);
  65. } else {
  66. // set a default frequency
  67. setPWMFreq(1000);
  68. }
  69. // set the default internal frequency
  70. setOscillatorFrequency(FREQUENCY_OSCILLATOR);
  71. }
  72. /*!
  73. * @brief Sends a reset command to the PCA9685 chip over I2C
  74. */
  75. void Adafruit_PWMServoDriver::reset() {
  76. write8(PCA9685_MODE1, MODE1_RESTART);
  77. delay(10);
  78. }
  79. /*!
  80. * @brief Puts board into sleep mode
  81. */
  82. void Adafruit_PWMServoDriver::sleep() {
  83. uint8_t awake = read8(PCA9685_MODE1);
  84. uint8_t sleep = awake | MODE1_SLEEP; // set sleep bit high
  85. write8(PCA9685_MODE1, sleep);
  86. delay(5); // wait until cycle ends for sleep to be active
  87. }
  88. /*!
  89. * @brief Wakes board from sleep
  90. */
  91. void Adafruit_PWMServoDriver::wakeup() {
  92. uint8_t sleep = read8(PCA9685_MODE1);
  93. uint8_t wakeup = sleep & ~MODE1_SLEEP; // set sleep bit low
  94. write8(PCA9685_MODE1, wakeup);
  95. }
  96. /*!
  97. * @brief Sets EXTCLK pin to use the external clock
  98. * @param prescale
  99. * Configures the prescale value to be used by the external clock
  100. */
  101. void Adafruit_PWMServoDriver::setExtClk(uint8_t prescale) {
  102. uint8_t oldmode = read8(PCA9685_MODE1);
  103. uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep
  104. write8(PCA9685_MODE1, newmode); // go to sleep, turn off internal oscillator
  105. // This sets both the SLEEP and EXTCLK bits of the MODE1 register to switch to
  106. // use the external clock.
  107. write8(PCA9685_MODE1, (newmode |= MODE1_EXTCLK));
  108. write8(PCA9685_PRESCALE, prescale); // set the prescaler
  109. delay(5);
  110. // clear the SLEEP bit to start
  111. write8(PCA9685_MODE1, (newmode & ~MODE1_SLEEP) | MODE1_RESTART | MODE1_AI);
  112. #ifdef ENABLE_DEBUG_OUTPUT
  113. Serial.print("Mode now 0x");
  114. Serial.println(read8(PCA9685_MODE1), HEX);
  115. #endif
  116. }
  117. /*!
  118. * @brief Sets the PWM frequency for the entire chip, up to ~1.6 KHz
  119. * @param freq Floating point frequency that we will attempt to match
  120. */
  121. void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
  122. #ifdef ENABLE_DEBUG_OUTPUT
  123. Serial.print("Attempting to set freq ");
  124. Serial.println(freq);
  125. #endif
  126. // Range output modulation frequency is dependant on oscillator
  127. if (freq < 1)
  128. freq = 1;
  129. if (freq > 3500)
  130. freq = 3500; // Datasheet limit is 3052=50MHz/(4*4096)
  131. float prescaleval = ((_oscillator_freq / (freq * 4096.0)) + 0.5) - 1;
  132. if (prescaleval < PCA9685_PRESCALE_MIN)
  133. prescaleval = PCA9685_PRESCALE_MIN;
  134. if (prescaleval > PCA9685_PRESCALE_MAX)
  135. prescaleval = PCA9685_PRESCALE_MAX;
  136. uint8_t prescale = (uint8_t)prescaleval;
  137. #ifdef ENABLE_DEBUG_OUTPUT
  138. Serial.print("Final pre-scale: ");
  139. Serial.println(prescale);
  140. #endif
  141. uint8_t oldmode = read8(PCA9685_MODE1);
  142. uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep
  143. write8(PCA9685_MODE1, newmode); // go to sleep
  144. write8(PCA9685_PRESCALE, prescale); // set the prescaler
  145. write8(PCA9685_MODE1, oldmode);
  146. delay(5);
  147. // This sets the MODE1 register to turn on auto increment.
  148. write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);
  149. #ifdef ENABLE_DEBUG_OUTPUT
  150. Serial.print("Mode now 0x");
  151. Serial.println(read8(PCA9685_MODE1), HEX);
  152. #endif
  153. }
  154. /*!
  155. * @brief Sets the output mode of the PCA9685 to either
  156. * open drain or push pull / totempole.
  157. * Warning: LEDs with integrated zener diodes should
  158. * only be driven in open drain mode.
  159. * @param totempole Totempole if true, open drain if false.
  160. */
  161. void Adafruit_PWMServoDriver::setOutputMode(bool totempole) {
  162. uint8_t oldmode = read8(PCA9685_MODE2);
  163. uint8_t newmode;
  164. if (totempole) {
  165. newmode = oldmode | MODE2_OUTDRV;
  166. } else {
  167. newmode = oldmode & ~MODE2_OUTDRV;
  168. }
  169. write8(PCA9685_MODE2, newmode);
  170. #ifdef ENABLE_DEBUG_OUTPUT
  171. Serial.print("Setting output mode: ");
  172. Serial.print(totempole ? "totempole" : "open drain");
  173. Serial.print(" by setting MODE2 to ");
  174. Serial.println(newmode);
  175. #endif
  176. }
  177. /*!
  178. * @brief Reads set Prescale from PCA9685
  179. * @return prescale value
  180. */
  181. uint8_t Adafruit_PWMServoDriver::readPrescale(void) {
  182. return read8(PCA9685_PRESCALE);
  183. }
  184. /*!
  185. * @brief Gets the PWM output of one of the PCA9685 pins
  186. * @param num One of the PWM output pins, from 0 to 15
  187. * @return requested PWM output value
  188. */
  189. uint8_t Adafruit_PWMServoDriver::getPWM(uint8_t num) {
  190. _i2c->requestFrom((int)_i2caddr, PCA9685_LED0_ON_L + 4 * num, (int)4);
  191. return _i2c->read();
  192. }
  193. /*!
  194. * @brief Sets the PWM output of one of the PCA9685 pins
  195. * @param num One of the PWM output pins, from 0 to 15
  196. * @param on At what point in the 4096-part cycle to turn the PWM output ON
  197. * @param off At what point in the 4096-part cycle to turn the PWM output OFF
  198. */
  199. void Adafruit_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
  200. #ifdef ENABLE_DEBUG_OUTPUT
  201. Serial.print("Setting PWM ");
  202. Serial.print(num);
  203. Serial.print(": ");
  204. Serial.print(on);
  205. Serial.print("->");
  206. Serial.println(off);
  207. #endif
  208. _i2c->beginTransmission(_i2caddr);
  209. _i2c->write(PCA9685_LED0_ON_L + 4 * num);
  210. _i2c->write(on);
  211. _i2c->write(on >> 8);
  212. _i2c->write(off);
  213. _i2c->write(off >> 8);
  214. _i2c->endTransmission();
  215. }
  216. /*!
  217. * @brief Helper to set pin PWM output. Sets pin without having to deal with
  218. * on/off tick placement and properly handles a zero value as completely off and
  219. * 4095 as completely on. Optional invert parameter supports inverting the
  220. * pulse for sinking to ground.
  221. * @param num One of the PWM output pins, from 0 to 15
  222. * @param val The number of ticks out of 4096 to be active, should be a value
  223. * from 0 to 4095 inclusive.
  224. * @param invert If true, inverts the output, defaults to 'false'
  225. */
  226. void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) {
  227. // Clamp value between 0 and 4095 inclusive.
  228. val = min(val, (uint16_t)4095);
  229. if (invert) {
  230. if (val == 0) {
  231. // Special value for signal fully on.
  232. setPWM(num, 4096, 0);
  233. } else if (val == 4095) {
  234. // Special value for signal fully off.
  235. setPWM(num, 0, 4096);
  236. } else {
  237. setPWM(num, 0, 4095 - val);
  238. }
  239. } else {
  240. if (val == 4095) {
  241. // Special value for signal fully on.
  242. setPWM(num, 4096, 0);
  243. } else if (val == 0) {
  244. // Special value for signal fully off.
  245. setPWM(num, 0, 4096);
  246. } else {
  247. setPWM(num, 0, val);
  248. }
  249. }
  250. }
  251. /*!
  252. * @brief Sets the PWM output of one of the PCA9685 pins based on the input
  253. * microseconds, output is not precise
  254. * @param num One of the PWM output pins, from 0 to 15
  255. * @param Microseconds The number of Microseconds to turn the PWM output ON
  256. */
  257. void Adafruit_PWMServoDriver::writeMicroseconds(uint8_t num,
  258. uint16_t Microseconds) {
  259. #ifdef ENABLE_DEBUG_OUTPUT
  260. Serial.print("Setting PWM Via Microseconds on output");
  261. Serial.print(num);
  262. Serial.print(": ");
  263. Serial.print(Microseconds);
  264. Serial.println("->");
  265. #endif
  266. double pulse = Microseconds;
  267. double pulselength;
  268. pulselength = 1000000; // 1,000,000 us per second
  269. // Read prescale
  270. uint16_t prescale = readPrescale();
  271. #ifdef ENABLE_DEBUG_OUTPUT
  272. Serial.print(prescale);
  273. Serial.println(" PCA9685 chip prescale");
  274. #endif
  275. // Calculate the pulse for PWM based on Equation 1 from the datasheet section
  276. // 7.3.5
  277. prescale += 1;
  278. pulselength *= prescale;
  279. pulselength /= _oscillator_freq;
  280. #ifdef ENABLE_DEBUG_OUTPUT
  281. Serial.print(pulselength);
  282. Serial.println(" us per bit");
  283. #endif
  284. pulse /= pulselength;
  285. #ifdef ENABLE_DEBUG_OUTPUT
  286. Serial.print(pulse);
  287. Serial.println(" pulse for PWM");
  288. #endif
  289. setPWM(num, 0, pulse);
  290. }
  291. /*!
  292. * @brief Getter for the internally tracked oscillator used for freq
  293. * calculations
  294. * @returns The frequency the PCA9685 thinks it is running at (it cannot
  295. * introspect)
  296. */
  297. uint32_t Adafruit_PWMServoDriver::getOscillatorFrequency(void) {
  298. return _oscillator_freq;
  299. }
  300. /*!
  301. * @brief Setter for the internally tracked oscillator used for freq
  302. * calculations
  303. * @param freq The frequency the PCA9685 should use for frequency calculations
  304. */
  305. void Adafruit_PWMServoDriver::setOscillatorFrequency(uint32_t freq) {
  306. _oscillator_freq = freq;
  307. }
  308. /******************* Low level I2C interface */
  309. uint8_t Adafruit_PWMServoDriver::read8(uint8_t addr) {
  310. _i2c->beginTransmission(_i2caddr);
  311. _i2c->write(addr);
  312. _i2c->endTransmission();
  313. _i2c->requestFrom((uint8_t)_i2caddr, (uint8_t)1);
  314. return _i2c->read();
  315. }
  316. void Adafruit_PWMServoDriver::write8(uint8_t addr, uint8_t d) {
  317. _i2c->beginTransmission(_i2caddr);
  318. _i2c->write(addr);
  319. _i2c->write(d);
  320. _i2c->endTransmission();
  321. }