This is a library for the PCA9685 ported from the Adafruit Ardiuno library.

Committer:
rvasquez6089
Date:
Fri Feb 13 22:02:35 2015 +0000
Revision:
0:1ecf26e0cf3c
Child:
2:ec40a85eba51
This is the first Revision of the PCA9685 Library.; I have ported this library from the Adafruit PWM Servo Library and added 1 new feature.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rvasquez6089 0:1ecf26e0cf3c 1 /*
rvasquez6089 0:1ecf26e0cf3c 2 This is a library for our Adafruit 16-channel PWM & Servo driver
rvasquez6089 0:1ecf26e0cf3c 3
rvasquez6089 0:1ecf26e0cf3c 4 Pick one up today in the adafruit shop!
rvasquez6089 0:1ecf26e0cf3c 5 ------> http://www.adafruit.com/products/815
rvasquez6089 0:1ecf26e0cf3c 6
rvasquez6089 0:1ecf26e0cf3c 7 These displays use I2C to communicate, 2 pins are required to
rvasquez6089 0:1ecf26e0cf3c 8 interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
rvasquez6089 0:1ecf26e0cf3c 9
rvasquez6089 0:1ecf26e0cf3c 10 Adafruit invests time and resources providing this open source code,
rvasquez6089 0:1ecf26e0cf3c 11 please support Adafruit and open-source hardware by purchasing
rvasquez6089 0:1ecf26e0cf3c 12 products from Adafruit!
rvasquez6089 0:1ecf26e0cf3c 13
rvasquez6089 0:1ecf26e0cf3c 14 Written by Limor Fried/Ladyada for Adafruit Industries.
rvasquez6089 0:1ecf26e0cf3c 15 BSD license, all text above must be included in any redistribution
rvasquez6089 0:1ecf26e0cf3c 16 ****************************************************/
rvasquez6089 0:1ecf26e0cf3c 17
rvasquez6089 0:1ecf26e0cf3c 18 /*****************************
rvasquez6089 0:1ecf26e0cf3c 19 This program was ported from https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library.
rvasquez6089 0:1ecf26e0cf3c 20 I also added some functions.
rvasquez6089 0:1ecf26e0cf3c 21 Shundo Kishi
rvasquez6089 0:1ecf26e0cf3c 22 */
rvasquez6089 0:1ecf26e0cf3c 23
rvasquez6089 0:1ecf26e0cf3c 24 #include "PCA9685Lib.h"
rvasquez6089 0:1ecf26e0cf3c 25
rvasquez6089 0:1ecf26e0cf3c 26
rvasquez6089 0:1ecf26e0cf3c 27 void LEDarr::operator=(uint16_t duty)
rvasquez6089 0:1ecf26e0cf3c 28 {
rvasquez6089 0:1ecf26e0cf3c 29 PCALib->setDuty(LEDnum, duty);
rvasquez6089 0:1ecf26e0cf3c 30 }
rvasquez6089 0:1ecf26e0cf3c 31
rvasquez6089 0:1ecf26e0cf3c 32 PCA9685Lib::PCA9685Lib(I2C i2cobj, int addr) : _i2caddr(addr) , i2c(i2cobj)
rvasquez6089 0:1ecf26e0cf3c 33 {
rvasquez6089 0:1ecf26e0cf3c 34 for(int i = 0; i<16 ; i++)
rvasquez6089 0:1ecf26e0cf3c 35 {
rvasquez6089 0:1ecf26e0cf3c 36 LED[i].PCALib = this;
rvasquez6089 0:1ecf26e0cf3c 37 LED[i].LEDnum = i;
rvasquez6089 0:1ecf26e0cf3c 38 }
rvasquez6089 0:1ecf26e0cf3c 39 }
rvasquez6089 0:1ecf26e0cf3c 40
rvasquez6089 0:1ecf26e0cf3c 41 void PCA9685Lib::i2c_probe(void)
rvasquez6089 0:1ecf26e0cf3c 42 {
rvasquez6089 0:1ecf26e0cf3c 43 printf("Searching for I2C devices...\n");
rvasquez6089 0:1ecf26e0cf3c 44
rvasquez6089 0:1ecf26e0cf3c 45 int count = 0;
rvasquez6089 0:1ecf26e0cf3c 46 for (int address=4; address<256; address+=2) {
rvasquez6089 0:1ecf26e0cf3c 47 if (!i2c.write(address, NULL, 0)) { // 0 returned is ok
rvasquez6089 0:1ecf26e0cf3c 48 printf(" - I2C device found at address 0x%02X\r\n", address);
rvasquez6089 0:1ecf26e0cf3c 49 count++;
rvasquez6089 0:1ecf26e0cf3c 50 }
rvasquez6089 0:1ecf26e0cf3c 51 }
rvasquez6089 0:1ecf26e0cf3c 52 printf("%d devices found\r\n", count);
rvasquez6089 0:1ecf26e0cf3c 53 }
rvasquez6089 0:1ecf26e0cf3c 54
rvasquez6089 0:1ecf26e0cf3c 55 void PCA9685Lib::begin(void) {
rvasquez6089 0:1ecf26e0cf3c 56 reset();
rvasquez6089 0:1ecf26e0cf3c 57 }
rvasquez6089 0:1ecf26e0cf3c 58
rvasquez6089 0:1ecf26e0cf3c 59 void PCA9685Lib::setI2Cfreq(int freq) {
rvasquez6089 0:1ecf26e0cf3c 60 i2c.frequency(freq);
rvasquez6089 0:1ecf26e0cf3c 61 }
rvasquez6089 0:1ecf26e0cf3c 62
rvasquez6089 0:1ecf26e0cf3c 63 void PCA9685Lib::reset(void) {
rvasquez6089 0:1ecf26e0cf3c 64 write8(PCA9685_MODE1, 0x0);
rvasquez6089 0:1ecf26e0cf3c 65 }
rvasquez6089 0:1ecf26e0cf3c 66
rvasquez6089 0:1ecf26e0cf3c 67 void PCA9685Lib::setPrescale(uint8_t prescale) {
rvasquez6089 0:1ecf26e0cf3c 68 uint8_t oldmode = read8(PCA9685_MODE1);
rvasquez6089 0:1ecf26e0cf3c 69 uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
rvasquez6089 0:1ecf26e0cf3c 70 write8(PCA9685_MODE1, newmode); // go to sleep
rvasquez6089 0:1ecf26e0cf3c 71 wait_ms(5);
rvasquez6089 0:1ecf26e0cf3c 72 write8(PCA9685_PRESCALE, prescale); // set the prescaler
rvasquez6089 0:1ecf26e0cf3c 73 write8(PCA9685_MODE1, oldmode);
rvasquez6089 0:1ecf26e0cf3c 74 wait_ms(5);
rvasquez6089 0:1ecf26e0cf3c 75 write8(PCA9685_MODE1, oldmode | 0xa1);
rvasquez6089 0:1ecf26e0cf3c 76 }
rvasquez6089 0:1ecf26e0cf3c 77
rvasquez6089 0:1ecf26e0cf3c 78 void PCA9685Lib::setPWMFreq(float freq) {
rvasquez6089 0:1ecf26e0cf3c 79 //Serial.print("Attempting to set freq ");
rvasquez6089 0:1ecf26e0cf3c 80 //Serial.println(freq);
rvasquez6089 0:1ecf26e0cf3c 81 float prescaleval = 25000000;
rvasquez6089 0:1ecf26e0cf3c 82 prescaleval /= 4096;
rvasquez6089 0:1ecf26e0cf3c 83 prescaleval /= freq;
rvasquez6089 0:1ecf26e0cf3c 84 //Serial.print("Estimated pre-scale: "); Serial.println(prescaleval);
rvasquez6089 0:1ecf26e0cf3c 85 uint8_t prescale = floor(prescaleval + 0.5) - 1;
rvasquez6089 0:1ecf26e0cf3c 86 //Serial.print("Final pre-scale: "); Serial.println(prescale);
rvasquez6089 0:1ecf26e0cf3c 87 setPrescale(prescale);
rvasquez6089 0:1ecf26e0cf3c 88 }
rvasquez6089 0:1ecf26e0cf3c 89
rvasquez6089 0:1ecf26e0cf3c 90 void PCA9685Lib::setPWM(uint8_t num, uint16_t on, uint16_t off) {
rvasquez6089 0:1ecf26e0cf3c 91 // hmm doesnt work, whyso? ( Not in AI mode. See line 54 above. ( Works now!! :D )
rvasquez6089 0:1ecf26e0cf3c 92
rvasquez6089 0:1ecf26e0cf3c 93 char cmd[5];
rvasquez6089 0:1ecf26e0cf3c 94 cmd[0] = LED0_ON_L + 4 * num;
rvasquez6089 0:1ecf26e0cf3c 95 cmd[1] = on;
rvasquez6089 0:1ecf26e0cf3c 96 cmd[2] = on >> 8;
rvasquez6089 0:1ecf26e0cf3c 97 cmd[3] = off;
rvasquez6089 0:1ecf26e0cf3c 98 cmd[4] = off >> 8;
rvasquez6089 0:1ecf26e0cf3c 99 i2c.write(_i2caddr, cmd, 5);
rvasquez6089 0:1ecf26e0cf3c 100
rvasquez6089 0:1ecf26e0cf3c 101 /*write8(LED0_ON_L+4*num, on);
rvasquez6089 0:1ecf26e0cf3c 102 write8(LED0_ON_H+4*num, on >> 8);
rvasquez6089 0:1ecf26e0cf3c 103 write8(LED0_OFF_L+4*num, off);
rvasquez6089 0:1ecf26e0cf3c 104 write8(LED0_OFF_H+4*num, off >> 8);*/
rvasquez6089 0:1ecf26e0cf3c 105 }
rvasquez6089 0:1ecf26e0cf3c 106
rvasquez6089 0:1ecf26e0cf3c 107 // Set pwm duty in us order
rvasquez6089 0:1ecf26e0cf3c 108 void PCA9685Lib::setDuty(uint8_t num, uint16_t duty) {
rvasquez6089 0:1ecf26e0cf3c 109 float pulselength = 10000; // 10,000 us per second
rvasquez6089 0:1ecf26e0cf3c 110 duty = 4094 * duty / pulselength;
rvasquez6089 0:1ecf26e0cf3c 111 setPWM(num, 0, duty);
rvasquez6089 0:1ecf26e0cf3c 112 }
rvasquez6089 0:1ecf26e0cf3c 113
rvasquez6089 0:1ecf26e0cf3c 114 uint8_t PCA9685Lib::read8(char addr) {
rvasquez6089 0:1ecf26e0cf3c 115 i2c.write(_i2caddr, &addr, 1);
rvasquez6089 0:1ecf26e0cf3c 116 char rtn;
rvasquez6089 0:1ecf26e0cf3c 117 i2c.read(_i2caddr, &rtn, 1);
rvasquez6089 0:1ecf26e0cf3c 118 return rtn;
rvasquez6089 0:1ecf26e0cf3c 119 }
rvasquez6089 0:1ecf26e0cf3c 120
rvasquez6089 0:1ecf26e0cf3c 121 void PCA9685Lib::write8(char addr, char d) {
rvasquez6089 0:1ecf26e0cf3c 122 char cmd[2];
rvasquez6089 0:1ecf26e0cf3c 123 cmd[0] = addr;
rvasquez6089 0:1ecf26e0cf3c 124 cmd[1] = d;
rvasquez6089 0:1ecf26e0cf3c 125 i2c.write(_i2caddr, cmd, 2);
rvasquez6089 0:1ecf26e0cf3c 126 }
rvasquez6089 0:1ecf26e0cf3c 127
rvasquez6089 0:1ecf26e0cf3c 128