Calum Johnston / PCA9685

Dependents:   Hexapod_Library main_robot_gant_v22

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PCA9685.cpp Source File

PCA9685.cpp

00001 #ifndef PCA9685_LIBRARY_CPP
00002 #define PCA9685_LIBRARY_CPP
00003 
00004 
00005 #include "mbed.h"
00006 #include "PCA9685.h"
00007 #include "definitions.h"
00008 
00009 
00010 PCA9685::PCA9685(uint8_t i2c_address, I2C i2c_object, float frequency) :
00011 
00012     i2c_addr(i2c_address),
00013     freq(frequency),
00014     i2c(i2c_object)
00015 
00016 {
00017 
00018 }
00019 
00020 void PCA9685::init(void)
00021 {
00022 
00023     reset();
00024 
00025     uint8_t prescale = (uint8_t) (OSC_CLOCK / (4096 * PWM_SCALER * freq)) - 1;
00026 
00027     write_8(MODE1, 0x21); //0010 0001 : AI ENABLED
00028     write_8(MODE2, 0x07); //0000 0111 : NOT INVRT, CHANGE ON STOP, TOTEM POLE, \OE = 1, LEDn = HIGH IMP
00029 
00030     set_prescale(prescale);
00031 
00032 }
00033 
00034 void PCA9685::reset(void)
00035 {
00036 
00037     write_8(MODE1,0x00);
00038 
00039 }
00040 
00041 void PCA9685::set_prescale(uint8_t prescale)
00042 {
00043 
00044     uint8_t oldmode = read_8(MODE1);
00045     uint8_t newmode = (oldmode&0x7F) | 0x10; // set the sleep bit
00046 
00047     write_8(MODE1, newmode); // send the device to sleep
00048     wait_ms(5);
00049     write_8(PRESCALE, prescale); // set the prescaler
00050     write_8(MODE1, oldmode);
00051     wait_ms(5);
00052     write_8(MODE1, oldmode | 0xa1); // wake up the device
00053 
00054 }
00055 
00056 
00057 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
00058 //0 <= pwm_output <= 15
00059 //0 <= (count_on || count_off) <= 4095
00060 void PCA9685::set_pwm_output(int pwm_output, uint16_t count_on, uint16_t count_off)
00061 {
00062 
00063     char msg[5];
00064 
00065     msg[0] = LED0_ON_L + (4 * pwm_output);
00066     msg[1] = count_on;
00067     msg[2] = count_on >> 8;
00068     msg[3] = count_off;
00069     msg[4] = count_off >> 8;
00070 
00071     i2c.write(i2c_addr, msg, 5);
00072 
00073 }
00074 
00075 void PCA9685::set_pwm_output_on_0(int pwm_output, uint16_t count_off)
00076 {
00077 
00078     char msg[3];
00079 
00080     msg[0] = LED0_ON_L + 2 + (4 * pwm_output);
00081     msg[1] = count_off;
00082     msg[2] = count_off >> 8;
00083 
00084     i2c.write(i2c_addr,msg,3);
00085 
00086 }
00087 
00088 
00089 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
00090 //0 <= pwm_output <= 15
00091 void PCA9685::set_pwm_duty(int pwm_output, float duty_cycle)
00092 {
00093 
00094     if (duty_cycle > 1.0) {
00095         duty_cycle = 1.0;
00096     }
00097     if (duty_cycle < 0.0) {
00098         duty_cycle = 0.0;
00099     }
00100 
00101     uint16_t count_off = (uint16_t) (duty_cycle * 4095);
00102     uint16_t count_on = 0x0000;
00103 
00104     set_pwm_output(pwm_output, count_on, count_off);
00105 
00106 }
00107 
00108 
00109 //NB REQUIRES AUTO-INCREMENT MODE ENABLED
00110 //0 <= pwm_output <= 15
00111 void PCA9685::set_pwm_pw(int pwm_output, float pulse_width_us)
00112 {
00113 
00114     float period_us = (1e6/freq);
00115 
00116     float duty = pulse_width_us/period_us;
00117 
00118     set_pwm_duty(pwm_output, duty);
00119 
00120 }
00121 
00122 
00123 void PCA9685::update(void)
00124 {
00125 
00126     i2c.stop();
00127 
00128 }
00129 
00130 
00131 
00132 void PCA9685::write_8(uint8_t reg, uint8_t msg)
00133 {
00134 
00135     char send[2]; //Store the address and data in an array
00136     send[0] = reg;
00137     send[1] = msg;
00138     i2c.write(i2c_addr, send, 2);
00139 
00140 }
00141 
00142 uint8_t PCA9685::read_8(uint8_t reg)
00143 {
00144 
00145     char send[1] ;
00146     send[0] = reg;
00147     i2c.write(i2c_addr, send, 1);
00148     char recieve[1];
00149     i2c.read(i2c_addr, recieve, 1);
00150     return recieve[0];
00151 
00152 }
00153 
00154 int PCA9685::convert_pwm_value(float pulse_width_us, float period_us)
00155 {
00156 
00157     int result;
00158     float interim;
00159 
00160     interim = ((pulse_width_us / period_us) * 4095); //scale the pulse width to a 12-bit scale
00161     result = (int) interim; //round the value to the nearest integer
00162 
00163     return result;
00164 
00165 }
00166 
00167 #endif