Library for interfacing with the NXP PCA9685 PWM controller over an I2C connection. Designed with the Adafruit breakout board (of the same name) in mind.

Committer:
el13cj
Date:
Thu Apr 07 20:12:00 2016 +0000
Revision:
2:8017239aa374
Parent:
1:9d6633a308ba
Child:
3:a3410f2f061d
Added header guards in cpp file

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el13cj 2:8017239aa374 1 #ifndef PCA9685_LIBRARY_CPP
el13cj 2:8017239aa374 2 #define PCA9685_LIBRARY_CPP
el13cj 2:8017239aa374 3
el13cj 2:8017239aa374 4
el13cj 0:aa965d6b1f8f 5 #include "mbed.h"
el13cj 0:aa965d6b1f8f 6 #include "PCA9685.h"
el13cj 0:aa965d6b1f8f 7 #include "definitions.h"
el13cj 0:aa965d6b1f8f 8
el13cj 2:8017239aa374 9
el13cj 0:aa965d6b1f8f 10 PCA9685::PCA9685(uint8_t i2c_address, I2C i2c_object, float frequency) : i2c_addr(i2c_address), freq(frequency), i2c(i2c_object)
el13cj 0:aa965d6b1f8f 11 {
el13cj 0:aa965d6b1f8f 12 //int two = 1 + 1;
el13cj 0:aa965d6b1f8f 13
el13cj 0:aa965d6b1f8f 14 }
el13cj 0:aa965d6b1f8f 15
el13cj 0:aa965d6b1f8f 16 void PCA9685::init(void) {
el13cj 0:aa965d6b1f8f 17
el13cj 0:aa965d6b1f8f 18 reset();
el13cj 0:aa965d6b1f8f 19
el13cj 1:9d6633a308ba 20 uint8_t prescale = (uint8_t) (OSC_CLOCK / (4096 * PWM_SCALER * freq)) - 1;
el13cj 0:aa965d6b1f8f 21
el13cj 0:aa965d6b1f8f 22 write_8(MODE1, 0x21); //0010 0001 : AI ENABLED
el13cj 0:aa965d6b1f8f 23 write_8(MODE2, 0x07); //0000 0111 : NOT INVRT, CHANGE ON STOP, TOTEM POLE, \OE = 1, LEDn = HIGH IMP
el13cj 0:aa965d6b1f8f 24
el13cj 0:aa965d6b1f8f 25 set_prescale(prescale);
el13cj 0:aa965d6b1f8f 26
el13cj 0:aa965d6b1f8f 27
el13cj 0:aa965d6b1f8f 28
el13cj 0:aa965d6b1f8f 29 }
el13cj 0:aa965d6b1f8f 30
el13cj 0:aa965d6b1f8f 31 void PCA9685::reset(void) {
el13cj 0:aa965d6b1f8f 32
el13cj 0:aa965d6b1f8f 33 write_8(MODE1,0x00);
el13cj 0:aa965d6b1f8f 34
el13cj 0:aa965d6b1f8f 35 }
el13cj 0:aa965d6b1f8f 36
el13cj 0:aa965d6b1f8f 37 void PCA9685::set_prescale(uint8_t prescale) {
el13cj 0:aa965d6b1f8f 38
el13cj 0:aa965d6b1f8f 39 uint8_t oldmode = read_8(MODE1);
el13cj 0:aa965d6b1f8f 40 uint8_t newmode = (oldmode&0x7F) | 0x10; // set the sleep bit
el13cj 0:aa965d6b1f8f 41
el13cj 0:aa965d6b1f8f 42 write_8(MODE1, newmode); // send the device to sleep
el13cj 0:aa965d6b1f8f 43 wait_ms(5);
el13cj 0:aa965d6b1f8f 44 write_8(PRESCALE, prescale); // set the prescaler
el13cj 0:aa965d6b1f8f 45 write_8(MODE1, oldmode);
el13cj 0:aa965d6b1f8f 46 wait_ms(5);
el13cj 0:aa965d6b1f8f 47 write_8(MODE1, oldmode | 0xa1); // wake up the device
el13cj 0:aa965d6b1f8f 48
el13cj 0:aa965d6b1f8f 49 }
el13cj 0:aa965d6b1f8f 50
el13cj 0:aa965d6b1f8f 51
el13cj 0:aa965d6b1f8f 52 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
el13cj 0:aa965d6b1f8f 53 //0 <= pwm_output <= 15
el13cj 0:aa965d6b1f8f 54 //0 <= (count_on || count_off) <= 4095
el13cj 0:aa965d6b1f8f 55 void PCA9685::set_pwm_output(int pwm_output, uint16_t count_on, uint16_t count_off) {
el13cj 0:aa965d6b1f8f 56
el13cj 0:aa965d6b1f8f 57 char msg[5];
el13cj 0:aa965d6b1f8f 58
el13cj 0:aa965d6b1f8f 59 msg[0] = LED0_ON_L + (4 * pwm_output);
el13cj 0:aa965d6b1f8f 60 msg[1] = count_on;
el13cj 0:aa965d6b1f8f 61 msg[2] = count_on >> 8;
el13cj 0:aa965d6b1f8f 62 msg[3] = count_off;
el13cj 0:aa965d6b1f8f 63 msg[4] = count_off >> 8;
el13cj 0:aa965d6b1f8f 64
el13cj 0:aa965d6b1f8f 65 i2c.write(ADDR, msg, 5);
el13cj 0:aa965d6b1f8f 66
el13cj 0:aa965d6b1f8f 67 }
el13cj 0:aa965d6b1f8f 68
el13cj 0:aa965d6b1f8f 69
el13cj 0:aa965d6b1f8f 70 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
el13cj 0:aa965d6b1f8f 71 //0 <= pwm_output <= 15
el13cj 0:aa965d6b1f8f 72 void PCA9685::set_pwm_duty(int pwm_output, float duty_cycle) {
el13cj 0:aa965d6b1f8f 73
el13cj 0:aa965d6b1f8f 74 if (duty_cycle > 1.0) { duty_cycle = 1.0; }
el13cj 0:aa965d6b1f8f 75 if (duty_cycle < 0.0) { duty_cycle = 0.0; }
el13cj 0:aa965d6b1f8f 76
el13cj 0:aa965d6b1f8f 77 uint16_t count_off = (uint16_t) (duty_cycle * 4095);
el13cj 0:aa965d6b1f8f 78 uint16_t count_on = 0x0000;
el13cj 0:aa965d6b1f8f 79
el13cj 0:aa965d6b1f8f 80 set_pwm_output(pwm_output, count_on, count_off);
el13cj 0:aa965d6b1f8f 81
el13cj 0:aa965d6b1f8f 82 }
el13cj 0:aa965d6b1f8f 83
el13cj 0:aa965d6b1f8f 84
el13cj 0:aa965d6b1f8f 85 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
el13cj 0:aa965d6b1f8f 86 //0 <= pwm_output <= 15
el13cj 0:aa965d6b1f8f 87 void PCA9685::set_pwm_pw(int pwm_output, float pulse_width_us) {
el13cj 0:aa965d6b1f8f 88
el13cj 0:aa965d6b1f8f 89 float period_us = (1e6/freq);
el13cj 0:aa965d6b1f8f 90
el13cj 0:aa965d6b1f8f 91 float duty = pulse_width_us/period_us;
el13cj 0:aa965d6b1f8f 92
el13cj 0:aa965d6b1f8f 93 set_pwm_duty(pwm_output, duty);
el13cj 0:aa965d6b1f8f 94
el13cj 0:aa965d6b1f8f 95 }
el13cj 0:aa965d6b1f8f 96
el13cj 0:aa965d6b1f8f 97
el13cj 0:aa965d6b1f8f 98 void PCA9685::update(void) {
el13cj 0:aa965d6b1f8f 99
el13cj 0:aa965d6b1f8f 100 i2c.stop();
el13cj 0:aa965d6b1f8f 101
el13cj 0:aa965d6b1f8f 102 }
el13cj 0:aa965d6b1f8f 103
el13cj 0:aa965d6b1f8f 104
el13cj 0:aa965d6b1f8f 105
el13cj 0:aa965d6b1f8f 106 void PCA9685::write_8(uint8_t reg, uint8_t msg) {
el13cj 0:aa965d6b1f8f 107
el13cj 0:aa965d6b1f8f 108 char send[2]; //Store the address and data in an array
el13cj 0:aa965d6b1f8f 109 send[0] = reg;
el13cj 0:aa965d6b1f8f 110 send[1] = msg;
el13cj 0:aa965d6b1f8f 111 i2c.write(i2c_addr, send, 2);
el13cj 0:aa965d6b1f8f 112
el13cj 0:aa965d6b1f8f 113 }
el13cj 0:aa965d6b1f8f 114
el13cj 0:aa965d6b1f8f 115 uint8_t PCA9685::read_8(uint8_t reg) {
el13cj 0:aa965d6b1f8f 116
el13cj 0:aa965d6b1f8f 117 char send[1] ;
el13cj 0:aa965d6b1f8f 118 send[0] = reg;
el13cj 0:aa965d6b1f8f 119 i2c.write(i2c_addr, send, 1);
el13cj 0:aa965d6b1f8f 120 char recieve[1];
el13cj 0:aa965d6b1f8f 121 i2c.read(i2c_addr, recieve, 1);
el13cj 0:aa965d6b1f8f 122 return recieve[0];
el13cj 0:aa965d6b1f8f 123
el13cj 0:aa965d6b1f8f 124 }
el13cj 0:aa965d6b1f8f 125
el13cj 0:aa965d6b1f8f 126 int PCA9685::convert_pwm_value(float pulse_width_us, float period_us) {
el13cj 0:aa965d6b1f8f 127
el13cj 0:aa965d6b1f8f 128 int result;
el13cj 0:aa965d6b1f8f 129 float interim;
el13cj 0:aa965d6b1f8f 130
el13cj 0:aa965d6b1f8f 131 interim = ((pulse_width_us / period_us) * 4095); //scale the pulse width to a 12-bit scale
el13cj 0:aa965d6b1f8f 132 result = (int) interim; //round the value to the nearest integer
el13cj 0:aa965d6b1f8f 133
el13cj 0:aa965d6b1f8f 134 return result;
el13cj 0:aa965d6b1f8f 135
el13cj 2:8017239aa374 136 }
el13cj 2:8017239aa374 137
el13cj 2:8017239aa374 138 #endif