mirror of
https://github.com/eclipse/upm.git
synced 2025-06-08 14:20:38 +03:00
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:
parent
970d6a083f
commit
2aa24162c3
@ -98,6 +98,7 @@ add_executable (l298-example l298.cxx)
|
||||
add_executable (l298-stepper-example l298-stepper.cxx)
|
||||
add_executable (at42qt1070-example at42qt1070.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/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/at42qt1070)
|
||||
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 (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 (at42qt1070-example at42qt1070 ${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
78
examples/c++/pca9685.cxx
Normal 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;
|
||||
}
|
85
examples/javascript/pca9685.js
Normal file
85
examples/javascript/pca9685.js
Normal 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();
|
||||
});
|
5
src/pca9685/CMakeLists.txt
Normal file
5
src/pca9685/CMakeLists.txt
Normal 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()
|
9
src/pca9685/jsupm_pca9685.i
Normal file
9
src/pca9685/jsupm_pca9685.i
Normal 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
283
src/pca9685/pca9685.cxx
Normal 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
315
src/pca9685/pca9685.h
Normal 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
13
src/pca9685/pyupm_pca9685.i
Normal file
13
src/pca9685/pyupm_pca9685.i
Normal 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"
|
||||
%}
|
Loading…
x
Reference in New Issue
Block a user