GY-63_MS5611/libraries/PCA9685/PCA9685.cpp
RobTillaart 6f2041f470 + fixed setON() and setOFF(),
+ add setFrequency(),
+ refactor
2019-01-30 14:28:59 +01:00

195 lines
3.9 KiB
C++

//
// FILE: PCA9685.cpp
// AUTHOR: Rob Tillaart
// DATE: 24-apr-2016
// VERSION: 0.1.1
// PURPOSE: I2C PCA9685 library for Arduino
// URL:
//
// HISTORY:
// 0.1.0 2016-04-24 initial BETA version
// 0.1.1 2019-01-30 testing && fixing
//
#include <Wire.h>
#include "PCA9685.h"
// check datasheet for details
#define PCA9685_MODE1 0x00
#define PCA9685_MODE2 0x01
// MODE1 REGISTERS
#define PCA9685_RESTART 0x80
#define PCA9685_EXTCLK 0x40
#define PCA9685_AUTOINCR 0x20
#define PCA9685_SLEEP 0x10
#define PCA9685_SUB1 0x08
#define PCA9685_SUB2 0x04
#define PCA9685_SUB3 0x02
#define PCA9685_ALLCALL 0x01
// MODE2 REGISTERS (see datasheet)
#define PCA9685_INVERT 0x10
#define PCA9685_OCH 0x08
#define PCA9685_OUTDRV 0x04
#define PCA9685_OUTNE 0x03
// SPECIAL REGISTER - FREQUENCY
#define PCA9685_PRE_SCALE 0xFE
// NOT IMPLEMENTED YET
#define PCA9685_SUBADR(x) (0x01+(x)) // x = 1..3
#define PCA9685_ALLCALLADR 0x05
#define PCA9685_TESTMODE 0xFF
//////////////////////////////////////////////////////////////
PCA9685::PCA9685(const uint8_t deviceAddress)
{
_address = deviceAddress;
_error = 0;
}
void PCA9685::begin()
{
Wire.begin();
_error = 0;
uint8_t mode1 = PCA9685_AUTOINCR | PCA9685_ALLCALL;
writeReg(PCA9685_MODE1, mode1);
uint8_t mode2 = PCA9685_OUTDRV;
writeReg(PCA9685_MODE2, mode2);
}
void PCA9685::writeMode(uint8_t reg, uint8_t value)
{
if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2)
{
_error = PCA9685_ERR_MODE;
return;
}
writeReg(reg, value);
}
uint8_t PCA9685::readMode(uint8_t reg)
{
if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2)
{
_error = PCA9685_ERR_MODE;
return 0;
}
uint8_t value = readReg(reg);
return value;
}
// write value to single PWM channel
void PCA9685::setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime)
{
if (channel > 15)
{
_error = PCA9685_ERR_CHANNEL;
return;
}
uint8_t reg = 0x06 + (channel << 2);
writeReg2(reg, onTime, offTime);
}
// write value to single PWM channel
void PCA9685::setPWM(uint8_t channel, uint16_t offTime)
{
setPWM(channel, 0, offTime);
}
// read value from single PWM channel
void PCA9685::getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime)
{
if (channel > 15)
{
_error = PCA9685_ERR_CHANNEL;
return;
}
uint8_t reg = 0x06 + (channel << 2);
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)4) != 4)
{
_error = PCA9685_ERROR;
return;
}
uint16_t _data = Wire.read();
*onTime = (Wire.read() * 256) + _data;
_data = Wire.read();
*offTime = (Wire.read() * 256) + _data;
}
// set update frequency for all channels
void PCA9685::setFrequency(uint16_t freq)
{
if (freq < 24) freq = 24;
if (freq > 1526) freq = 1526;
// removed float operation for speed
// uint8_t scaler = round(25e6 / (4096 * freq)) - 1;
uint8_t scaler = 6104 / freq - 1;
writeReg(PCA9685_PRE_SCALE, scaler);
}
void PCA9685::setON(uint8_t channel)
{
setPWM(channel, 0x1000, 0x0000);
}
void PCA9685::setOFF(uint8_t channel)
{
setPWM(channel, 0x0000, 0x1000);
}
int PCA9685::lastError()
{
int e = _error;
_error = 0;
return e;
}
void PCA9685::writeReg(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(value);
_error = Wire.endTransmission();
}
void PCA9685::writeReg2(uint8_t reg, uint16_t a, uint16_t b)
{
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(a & 0xFF);
Wire.write((a >> 8) & 0x0F);
Wire.write(b & 0xFF);
Wire.write((b >> 8) & 0x0F);
_error = Wire.endTransmission();
}
//
uint8_t PCA9685::readReg(uint8_t reg)
{
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)1) != 1)
{
_error = PCA9685_ERROR;
return 0;
}
uint8_t _data = Wire.read();
return _data;
}
//
// END OF FILE
//