pca9685: Initial implementation

This library implements generic support for the pca9685 16 channel 12
bit PWM LED controller.  This controller is used on some Adafruit
motor shields.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Zion Orent <zorent@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Jon Trulson 2015-02-26 18:27:24 -07:00 committed by Mihai Tudor Panu
parent 970d6a083f
commit 2aa24162c3
8 changed files with 791 additions and 0 deletions

View File

@ -98,6 +98,7 @@ add_executable (l298-example l298.cxx)
add_executable (l298-stepper-example l298-stepper.cxx) add_executable (l298-stepper-example l298-stepper.cxx)
add_executable (at42qt1070-example at42qt1070.cxx) add_executable (at42qt1070-example at42qt1070.cxx)
add_executable (grovemd-example grovemd.cxx) add_executable (grovemd-example grovemd.cxx)
add_executable (pca9685-example pca9685.cxx)
include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l)
include_directories (${PROJECT_SOURCE_DIR}/src/grove) include_directories (${PROJECT_SOURCE_DIR}/src/grove)
@ -177,6 +178,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/ina132)
include_directories (${PROJECT_SOURCE_DIR}/src/l298) include_directories (${PROJECT_SOURCE_DIR}/src/l298)
include_directories (${PROJECT_SOURCE_DIR}/src/at42qt1070) include_directories (${PROJECT_SOURCE_DIR}/src/at42qt1070)
include_directories (${PROJECT_SOURCE_DIR}/src/grovemd) include_directories (${PROJECT_SOURCE_DIR}/src/grovemd)
include_directories (${PROJECT_SOURCE_DIR}/src/pca9685)
target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT})
@ -276,3 +278,4 @@ target_link_libraries (l298-example l298 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (l298-stepper-example l298 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (l298-stepper-example l298 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (at42qt1070-example at42qt1070 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (at42qt1070-example at42qt1070 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (grovemd-example grovemd ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (grovemd-example grovemd ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (pca9685-example pca9685 ${CMAKE_THREAD_LIBS_INIT})

78
examples/c++/pca9685.cxx Normal file
View File

@ -0,0 +1,78 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include "pca9685.h"
using namespace std;
int main(int argc, char **argv)
{
//! [Interesting]
// Instantiate an PCA9685 on I2C bus 0
upm::PCA9685 *leds = new upm::PCA9685(PCA9685_I2C_BUS,
PCA9685_DEFAULT_I2C_ADDR);
// put device to sleep
leds->setModeSleep(true);
// setup a period of 50Hz
leds->setPrescaleFromHz(50);
// wake device up
leds->setModeSleep(false);
// Setup a 50% duty cycle -- on time at 0, off time at 2048 (4096 / 2)
// Set for all channels
leds->ledOnTime(PCA9685_ALL_LED, 0);
leds->ledOffTime(PCA9685_ALL_LED, 2048);
// but, turn channel 3 full off and channel 4 full on
cout << "Turning channel 3 off, and channel 4 on." << endl;
cout << "All other channels will be PWM'd at a 50% duty cycle." << endl;
leds->ledFullOff(3, true);
leds->ledFullOn(4, true);
// now, just sleep for 5 seconds, reset channels 3 and 4, and exit.
cout << "Sleeping for 5 seconds..." << endl;
sleep(5);
cout << "Exiting..." << endl;
// clear the bits we set earlier
leds->ledFullOff(3, false);
leds->ledFullOn(4, false);
//! [Interesting]
delete leds;
return 0;
}

View File

@ -0,0 +1,85 @@
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
/*
* Author: Zion Orent <zorent@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
function exit()
{
console.log("Exiting");
if (myLEDController_obj)
{
// clear the bits we set earlier
myLEDController_obj.ledFullOff(3, false);
myLEDController_obj.ledFullOn(4, false);
}
myLEDController_obj = null;
if (LEDController_lib)
{
LEDController_lib.cleanUp();
LEDController_lib = null;
}
process.exit(0);
}
// The pca9685 is an led controller.
// It's being used in this case to drive motors.
var LEDController_lib = require('jsupm_pca9685');
var I2CBus = LEDController_lib.PCA9685_I2C_BUS;
var I2CAddr = LEDController_lib.PCA9685_DEFAULT_I2C_ADDR;
// Instantiate an PCA9685 on I2C bus 0
var myLEDController_obj = new LEDController_lib.PCA9685(I2CBus, I2CAddr);
// put device to sleep
myLEDController_obj.setModeSleep(true);
// setup a period of 50Hz
myLEDController_obj.setPrescaleFromHz(50);
// wake device up
myLEDController_obj.setModeSleep(false);
// Setup a 50% duty cycle -- on time at 0, off time at 2048 (4096 / 2)
// Set for all channels
var LEDNum = LEDController_lib.PCA9685_ALL_LED;
myLEDController_obj.ledOnTime(LEDNum, 0);
myLEDController_obj.ledOffTime(LEDNum, 2048);
// but, turn channel 3 full off and channel 4 full on
console.log("Turning channel 3 off, and channel 4 on.");
console.log("All other channels will be PWM'd at a 50% duty cycle.");
myLEDController_obj.ledFullOff(3, true);
myLEDController_obj.ledFullOn(4, true);
// now, just sleep for 5 seconds, reset channels 3 and 4, and exit.
console.log("Sleeping for 5 seconds...");
setTimeout(exit, 5000);
process.on('SIGINT', function()
{
exit();
});

View File

@ -0,0 +1,5 @@
set (libname "pca9685")
set (libdescription "upm pca9685 I2C 16ch, 12b pwm, LED controller")
set (module_src ${libname}.cxx)
set (module_h ${libname}.h)
upm_module_init()

View File

@ -0,0 +1,9 @@
%module jsupm_pca9685
%include "../upm.i"
%include "cpointer.i"
%{
#include "pca9685.h"
%}
%include "pca9685.h"

283
src/pca9685/pca9685.cxx Normal file
View File

@ -0,0 +1,283 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <math.h>
#include <iostream>
#include <string>
#include "pca9685.h"
using namespace upm;
using namespace std;
PCA9685::PCA9685(int bus, uint8_t address)
{
m_addr = address;
// setup our i2c link
if ( !(m_i2c = mraa_i2c_init(bus)) )
{
cerr << "PCA9685: mraa_i2c_init() failed." << endl;
return;
}
mraa_result_t rv;
if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS)
{
cerr << "PCA9685: Could not initialize i2c bus. " << endl;
mraa_result_print(rv);
return;
}
// enable auto-increment mode by default
enableAutoIncrement(true);
// enable restart by default.
enableRestart(true);
}
PCA9685::~PCA9685()
{
setModeSleep(true);
mraa_i2c_stop(m_i2c);
}
bool PCA9685::writeByte(uint8_t reg, uint8_t byte)
{
mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg);
if (rv != MRAA_SUCCESS)
{
cerr << __FUNCTION__ << ": mraa_i2c_write_byte() failed." << endl;
mraa_result_print(rv);
return false;
}
return true;
}
bool PCA9685::writeWord(uint8_t reg, uint16_t word)
{
mraa_result_t rv = mraa_i2c_write_word_data(m_i2c, word, reg);
if (rv != MRAA_SUCCESS)
{
cerr << __FUNCTION__ << ": mraa_i2c_write_word() failed." << endl;
mraa_result_print(rv);
return false;
}
return true;
}
uint8_t PCA9685::readByte(uint8_t reg)
{
return mraa_i2c_read_byte_data(m_i2c, reg);
}
uint16_t PCA9685::readWord(uint8_t reg)
{
return mraa_i2c_read_word_data(m_i2c, reg);
}
bool PCA9685::setModeSleep(bool sleep)
{
uint8_t mode1 = readByte(REG_MODE1);
uint8_t restartBit = mode1 & MODE1_RESTART;
if (sleep)
mode1 |= MODE1_SLEEP;
else
mode1 &= ~MODE1_SLEEP;
// if we are waking up, then preserve but don't write restart bit if set
if (!sleep && restartBit)
mode1 &= ~MODE1_RESTART;
bool rv = writeByte(REG_MODE1, mode1);
if (!rv)
{
cerr << __FUNCTION__ << ": write to MODE1 failed." << endl;
return rv;
}
// Need a delay of 500us after turning sleep mode off for the oscillator
// to stabilize
if (!sleep)
usleep(500);
// now check to see if we want to (and can) restart when waking up
if (restartBit && m_restartEnabled && !sleep)
{
mode1 |= restartBit;
rv = writeByte(REG_MODE1, mode1);
}
return rv;
}
bool PCA9685::enableAutoIncrement(bool ai)
{
uint8_t mode1 = readByte(REG_MODE1);
if (ai)
mode1 |= MODE1_AI;
else
mode1 &= ~MODE1_AI;
return writeByte(REG_MODE1, mode1);
}
bool PCA9685::ledFullOn(uint8_t led, bool val)
{
if (led > 15 && (led != PCA9685_ALL_LED))
{
cerr << __FUNCTION__ << ": led value must be between 0-15 or "
<< "PCA9685_ALL_LED (255)" << endl;
return false;
}
// figure out the register offset (*_ON_H)
uint8_t regoff;
if (led == PCA9685_ALL_LED)
regoff = REG_ALL_LED_ON_H;
else
regoff = REG_LED0_ON_L + (led * 4) + 1;
uint8_t bits = readByte(regoff);
if (val)
bits |= ((1 << 4) & 0xff);
else
bits &= ~((1 << 4) & 0xff);
return writeByte(regoff, bits);
}
bool PCA9685::ledFullOff(uint8_t led, bool val)
{
if (led > 15 && (led != PCA9685_ALL_LED))
{
cerr << __FUNCTION__ << ": led value must be between 0-15 or "
<< "PCA9685_ALL_LED (255)" << endl;
return false;
}
// figure out the register offset (*_OFF_H)
uint8_t regoff;
if (led == PCA9685_ALL_LED)
regoff = REG_ALL_LED_OFF_H;
else
regoff = REG_LED0_ON_L + (led * 4) + 3;
uint8_t bits = readByte(regoff);
if (val)
bits |= ((1 << 4) & 0xff);
else
bits &= ~((1 << 4) & 0xff);
return writeByte(regoff, bits);
}
bool PCA9685::ledOnTime(uint8_t led, uint16_t time)
{
if (led > 15 && (led != PCA9685_ALL_LED))
{
cerr << __FUNCTION__ << ": led value must be between 0-15 or "
<< "PCA9685_ALL_LED (255)" << endl;
return false;
}
if (time > 4095)
{
cerr << __FUNCTION__ << ": time value must be between 0-4095" << endl;
return false;
}
// figure out the register offset (*_ON_L)
uint8_t regoff;
if (led == PCA9685_ALL_LED)
regoff = REG_ALL_LED_ON_L;
else
regoff = REG_LED0_ON_L + (led * 4);
// we need to preserve the full ON bit in *_ON_H
uint8_t onbit = (readByte(regoff + 1) & 0x40);
time = (time & 0x0fff) | (onbit << 8);
return writeWord(regoff, time);
}
bool PCA9685::ledOffTime(uint8_t led, uint16_t time)
{
if (led > 15 && (led != PCA9685_ALL_LED))
{
cerr << __FUNCTION__ << ": led value must be between 0-15 or "
<< "PCA9685_ALL_LED (255)" << endl;
return false;
}
if (time > 4095)
{
cerr << __FUNCTION__ << ": time value must be between 0-4095" << endl;
return false;
}
// figure out the register offset (*_OFF_L)
uint8_t regoff;
if (led == PCA9685_ALL_LED)
regoff = REG_ALL_LED_OFF_L;
else
regoff = REG_LED0_ON_L + (led * 4) + 2;
// we need to preserve the full OFF bit in *_OFF_H
uint8_t offbit = (readByte(regoff + 1) & 0x40);
time = (time & 0x0fff) | (offbit << 8);
return writeWord(regoff, time);
}
bool PCA9685::setPrescale(uint8_t prescale)
{
// This will be ignored if the device isn't in SLEEP mode
return writeByte(REG_PRESCALE, prescale);
}
bool PCA9685::setPrescaleFromHz(float hz, float oscFreq)
{
float prescale = round( oscFreq / (4096.0 * hz) ) - 1;
return setPrescale(uint8_t(prescale));
}

315
src/pca9685/pca9685.h Normal file
View File

@ -0,0 +1,315 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <string>
#include <mraa/i2c.h>
#include <mraa/gpio.h>
#define PCA9685_I2C_BUS 0
#define PCA9685_DEFAULT_I2C_ADDR 0x60
// internal oscillator frequency
#define PCA9685_INTERNAL_OSC 25000000.0
// This is a 'special' LED number, used to refer to the ALL_LED registers
// that affect all LED outputs at once.
#define PCA9685_ALL_LED 0xff
namespace upm {
/**
* @brief UPM module for the PCA9685 16 channel, 12 bit pwm LED controller.
* @defgroup pca9685 libupm-pca9685
*/
/**
* @brief C++ API for the PCA9685 16 channel, 12 bit pwm LED controller
*
* This controller is also used on the Adafruit Motor Shield v2.3
* board to control up to 4 DC motors, 2 step motors and 2 servo
* motors.
*
* This module was tested with the Adafruit Motor Shield v2.3
*
* @ingroup i2c pca9685
* @snippet pca9685.cxx Interesting
*/
class PCA9685 {
public:
/**
* PCA9685 registers
*/
typedef enum { REG_MODE1 = 0x00,
REG_MODE2 = 0x01,
REG_I2C_SA1 = 0x02, // I2C subaddress 1
REG_I2C_SA2 = 0x03,
REG_I2C_SA3 = 0x04,
REG_ALLCALL = 0x05, // I2C all call address
// LED output PWM control
REG_LED0_ON_L = 0x06, // LED0 ON low byte
REG_LED0_ON_H = 0x07, // LED0 ON high byte
REG_LED0_OFF_L = 0x08, // LED0 OFF low byte
REG_LED0_OFF_H = 0x09, // LED0 OFF high byte
REG_LED1_ON_L = 0x0a,
REG_LED1_ON_H = 0x0b,
REG_LED1_OFF_L = 0x0c,
REG_LED1_OFF_H = 0x0d,
REG_LED2_ON_L = 0x0e,
REG_LED2_ON_H = 0x0f,
REG_LED2_OFF_L = 0x10,
REG_LED2_OFF_H = 0x11,
REG_LED3_ON_L = 0x12,
REG_LED3_ON_H = 0x13,
REG_LED3_OFF_L = 0x14,
REG_LED3_OFF_H = 0x15,
REG_LED4_ON_L = 0x16,
REG_LED4_ON_H = 0x17,
REG_LED4_OFF_L = 0x18,
REG_LED4_OFF_H = 0x19,
REG_LED5_ON_L = 0x1a,
REG_LED5_ON_H = 0x1b,
REG_LED5_OFF_L = 0x1c,
REG_LED5_OFF_H = 0x1d,
REG_LED6_ON_L = 0x1e,
REG_LED6_ON_H = 0x1f,
REG_LED6_OFF_L = 0x20,
REG_LED6_OFF_H = 0x21,
REG_LED7_ON_L = 0x22,
REG_LED7_ON_H = 0x23,
REG_LED7_OFF_L = 0x24,
REG_LED7_OFF_H = 0x25,
REG_LED8_ON_L = 0x26,
REG_LED8_ON_H = 0x27,
REG_LED8_OFF_L = 0x28,
REG_LED8_OFF_H = 0x29,
REG_LED9_ON_L = 0x2a,
REG_LED9_ON_H = 0x2b,
REG_LED9_OFF_L = 0x2c,
REG_LED9_OFF_H = 0x2d,
REG_LED10_ON_L = 0x2e,
REG_LED10_ON_H = 0x2f,
REG_LED10_OFF_L = 0x30,
REG_LED10_OFF_H = 0x31,
REG_LED11_ON_L = 0x32,
REG_LED11_ON_H = 0x33,
REG_LED11_OFF_L = 0x34,
REG_LED11_OFF_H = 0x35,
REG_LED12_ON_L = 0x36,
REG_LED12_ON_H = 0x37,
REG_LED12_OFF_L = 0x38,
REG_LED12_OFF_H = 0x39,
REG_LED13_ON_L = 0x3a,
REG_LED13_ON_H = 0x3b,
REG_LED13_OFF_L = 0x3c,
REG_LED13_OFF_H = 0x3d,
REG_LED14_ON_L = 0x3e,
REG_LED14_ON_H = 0x3f,
REG_LED14_OFF_L = 0x40,
REG_LED14_OFF_H = 0x41,
REG_LED15_ON_L = 0x42,
REG_LED15_ON_H = 0x43,
REG_LED15_OFF_L = 0x44,
REG_LED15_OFF_H = 0x45,
// 0x46-0xf9 reserved
REG_ALL_LED_ON_L = 0xfa, // write all LED ON L
REG_ALL_LED_ON_H = 0xfb, // write all LED ON H
REG_ALL_LED_OFF_L = 0xfc, // write all LED OFF L
REG_ALL_LED_OFF_H = 0xfd, // write all LED OFF H
REG_PRESCALE = 0xfe,
REG_TESTMODE = 0xff // don't use
} PCA9685_REG_T;
/**
* MODE1 bits
*/
typedef enum { MODE1_ALL_CALL = 0x01, // all call status
MODE1_SUB3 = 0x02, // subcall 3 status
MODE1_SUB2 = 0x04, // subcall 2 status
MODE1_SUB1 = 0x08, // subcall 1 status
MODE1_SLEEP = 0x10, // sleep/normal mode
MODE1_AI = 0x20, // auto-increment enable
MODE1_EXTCLK = 0x40, // external clock enable
MODE1_RESTART = 0x80 // restart status
} PCA9685_MODE1_T;
/**
* MODE2 bits
*/
typedef enum { MODE2_OUTNE0 = 0x01, // output driver enable bit 0
MODE2_OUTNE = 0x02, // output driver enable bit 1
MODE2_OUTDRV = 0x04, // output open-drain/totem pole
MODE2_OCH = 0x08, // output change on STOP or ACK
MODE2_INVRT = 0x10, // output logic state invert
MODE2_RESERVE0 = 0x20, // reserved
MODE2_RESERVE1 = 0x40, // reserved
MODE2_RESERVE2 = 0x80 // reserved
} PCA9685_MODE2_T;
/**
* pca9685 constructor
*
* @param bus i2c bus to use
* @param address the address for this device
*/
PCA9685(int bus, uint8_t address = PCA9685_DEFAULT_I2C_ADDR);
/**
* PCA9685 Destructor
*/
~PCA9685();
/**
* Write byte value into register
*
* @param reg register location to write into
* @param byte byte to write
* @return true if successful
*/
bool writeByte(uint8_t reg, uint8_t byte);
/**
* Write word value at register. Note, the device must have the
* auto-increment bit set in the MODE1 register to work.
*
* @param reg register location to write into
* @param word word to write
* @return true if successful
*/
bool writeWord(uint8_t reg, uint16_t word);
/**
* Read byte value from register
*
* @param reg register location to read from
* @return value at specified register
*/
uint8_t readByte(uint8_t reg);
/**
* Read word value from register. Note, the device must have the
* auto-increment bit set in the MODE1 register to work.
*
* @param reg register location to read from
* @return value at specified register
*/
uint16_t readWord(uint8_t reg);
/**
* Put the device into or out of Sleep mode. The device is always
* in sleep mode upon power up.
*
* @param sleep true to put into sleep mode, false to take out of
* sleep mode.
* @return true if successful
*/
bool setModeSleep(bool sleep);
/**
* set or clear the FULL ON bit for a given LED
*
* @param led led number, valid values: 0-15, PCA9685_ALL_LED
* @param val true to set the bit, false to clear it
* @return true if successful
*/
bool ledFullOn(uint8_t led, bool val);
/**
* set or clear the FULL OFF bit for a given LED. If the FULL ON
* bit is also set, then FULL OFF has precendence.
*
* @param led led number, valid values: 0-15, PCA9685_ALL_LED
* @param val true to set the bit, false to clear it
* @return true if successful
*/
bool ledFullOff(uint8_t led, bool val);
/**
* set the LED on time (0-4095). See the pca9685 datasheet for details.
*
* @param led led number, valid values: 0-15, PCA9685_ALL_LED
* @param time the 12 bit value at which point the LED will turn on
* @return true if successful
*/
bool ledOnTime(uint8_t led, uint16_t time);
/**
* set the LED off time (0-4095). See the pca9685 datasheet for details.
*
* @param led led number, valid values: 0-15, PCA9685_ALL_LED
* @param time the 12 bit value at which point the LED will turn off
* @return true if successful
*/
bool ledOffTime(uint8_t led, uint16_t time);
/**
* set the prescale value. See the pca9685 datasheet for
* details. The prescale can only be set when the device is in
* sleep mode.
*
* @param prescale the prescale value
* @return true if successful
*/
bool setPrescale(uint8_t prescale);
/**
* set the prescale value based on a desired frequency in hz. The
* prescale can only be set when the device is in sleep mode.
*
* @param hz the desired frequency in hz
* @param oscFreq the oscillator frequency, defaul 25Mhz
* @return true if successful
*/
bool setPrescaleFromHz(float hz,
float oscFreq=PCA9685_INTERNAL_OSC);
/**
* enable or disable the RESTART capability of the controller
*
* @param enabled true to enable restart, false to disable.
* Default is enabled.
*
* @return true if successful
*/
bool enableRestart(bool enabled) { m_restartEnabled = enabled; };
private:
/**
* Enable I2C register auto-increment. This needs to be enabled
* for write/readWord() to work. The contructor enables this by
* default.
*
* @param ai true to enable auto-increment of i2c regs, false otherwise
*/
bool enableAutoIncrement(bool ai);
bool m_restartEnabled;
mraa_i2c_context m_i2c;
uint8_t m_addr;
};
}

View File

@ -0,0 +1,13 @@
%module pyupm_pca9685
%include "../upm.i"
%feature("autodoc", "3");
#ifdef DOXYGEN
%include "pca9685_doc.i"
#endif
%include "pca9685.h"
%{
#include "pca9685.h"
%}