1765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* 2765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Author: Jon Trulson <jtrulson@ics.com> 3765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Copyright (c) 2015 Intel Corporation. 4765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 5765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Permission is hereby granted, free of charge, to any person obtaining 6765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * a copy of this software and associated documentation files (the 7765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * "Software"), to deal in the Software without restriction, including 8765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * without limitation the rights to use, copy, modify, merge, publish, 9765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * distribute, sublicense, and/or sell copies of the Software, and to 10765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * permit persons to whom the Software is furnished to do so, subject to 11765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * the following conditions: 12765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 13765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * The above copyright notice and this permission notice shall be 14765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * included in all copies or substantial portions of the Software. 15765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 16765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 24765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 25765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <unistd.h> 26765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <math.h> 27765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <iostream> 28765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <string> 29765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <stdexcept> 30765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 31765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include "pca9685.h" 32765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 33765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangusing namespace upm; 34765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangusing namespace std; 35765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 36765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 37765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun ZhangPCA9685::PCA9685(int bus, uint8_t address, bool raw) 38765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 39765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang m_addr = address; 40765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 41765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // setup our i2c link 42765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if ( raw ) 43765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 44765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang m_i2c = mraa_i2c_init_raw(bus); 45765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 46765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 47765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 48765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang m_i2c = mraa_i2c_init(bus); 49765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 50765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 51765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if ( !m_i2c) 52765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 53765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::invalid_argument(std::string(__FUNCTION__) + 54765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": mraa_i2c_init() failed"); 55765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return; 56765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 57765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 58765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mraa_result_t rv; 59765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 60765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS) 61765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 62765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::runtime_error(std::string(__FUNCTION__) + 63765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": mraa_i2c_address() failed"); 64765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return; 65765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 66765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 67765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // enable auto-increment mode by default 68765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang enableAutoIncrement(true); 69765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 70765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // enable restart by default. 71765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang enableRestart(true); 72765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 73765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 74765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun ZhangPCA9685::~PCA9685() 75765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 76765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang setModeSleep(true); 77765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mraa_i2c_stop(m_i2c); 78765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 79765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 80765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::writeByte(uint8_t reg, uint8_t byte) 81765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 82765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg); 83765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 84765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (rv != MRAA_SUCCESS) 85765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 86765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::runtime_error(std::string(__FUNCTION__) + 87765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": mraa_i2c_write_byte_data() failed"); 88765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 89765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 90765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 91765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return true; 92765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 93765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 94765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::writeWord(uint8_t reg, uint16_t word) 95765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 96765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mraa_result_t rv = mraa_i2c_write_word_data(m_i2c, word, reg); 97765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 98765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (rv != MRAA_SUCCESS) 99765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 100765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::runtime_error(std::string(__FUNCTION__) + 101765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": mraa_i2c_write_word_data() failed"); 102765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 103765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 104765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 105765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return true; 106765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 107765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 108765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhanguint8_t PCA9685::readByte(uint8_t reg) 109765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 110765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return mraa_i2c_read_byte_data(m_i2c, reg); 111765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 112765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 113765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhanguint16_t PCA9685::readWord(uint8_t reg) 114765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 115765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return mraa_i2c_read_word_data(m_i2c, reg); 116765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 117765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 118765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setModeSleep(bool sleep) 119765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 120765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t mode1 = readByte(REG_MODE1); 121765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t restartBit = mode1 & MODE1_RESTART; 122765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 123765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (sleep) 124765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 |= MODE1_SLEEP; 125765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 126765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 &= ~MODE1_SLEEP; 127765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 128765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // if we are waking up, then preserve but don't write restart bit if set 129765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (!sleep && restartBit) 130765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 &= ~MODE1_RESTART; 131765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 132765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang writeByte(REG_MODE1, mode1); 133765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 134765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // Need a delay of 500us after turning sleep mode off for the oscillator 135765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // to stabilize 136765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (!sleep) 137765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang usleep(500); 138765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 139765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // now check to see if we want to (and can) restart when waking up 140765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (restartBit && m_restartEnabled && !sleep) 141765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 142765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 |= restartBit; 143765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang writeByte(REG_MODE1, mode1); 144765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 145765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 146765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return true; 147765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 148765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 149765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::enableAutoIncrement(bool ai) 150765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 151765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t mode1 = readByte(REG_MODE1); 152765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 153765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (ai) 154765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 |= MODE1_AI; 155765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 156765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang mode1 &= ~MODE1_AI; 157765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 158765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeByte(REG_MODE1, mode1); 159765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 160765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 161765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledFullOn(uint8_t led, bool val) 162765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 163765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led > 15 && (led != PCA9685_ALL_LED)) 164765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 165765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 166765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": led value must be between 0-15 or " + 167765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang "PCA9685_ALL_LED (255)"); 168765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 169765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 170765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 171765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // figure out the register offset (*_ON_H) 172765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t regoff; 173765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 174765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led == PCA9685_ALL_LED) 175765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_ALL_LED_ON_H; 176765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 177765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_LED0_ON_L + (led * 4) + 1; 178765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 179765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t bits = readByte(regoff); 180765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 181765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (val) 182765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang bits |= 0x10; 183765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 184765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang bits &= ~0x10; 185765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 186765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeByte(regoff, bits); 187765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 188765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 189765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledFullOff(uint8_t led, bool val) 190765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 191765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led > 15 && (led != PCA9685_ALL_LED)) 192765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 193765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 194765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": led value must be between 0-15 or " + 195765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang "PCA9685_ALL_LED (255)"); 196765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 197765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 198765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 199765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // figure out the register offset (*_OFF_H) 200765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t regoff; 201765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 202765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led == PCA9685_ALL_LED) 203765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_ALL_LED_OFF_H; 204765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 205765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_LED0_ON_L + (led * 4) + 3; 206765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 207765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t bits = readByte(regoff); 208765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 209765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (val) 210765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang bits |= 0x10; 211765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 212765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang bits &= ~0x10; 213765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 214765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeByte(regoff, bits); 215765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 216765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 217765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledOnTime(uint8_t led, uint16_t time) 218765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 219765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led > 15 && (led != PCA9685_ALL_LED)) 220765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 221765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 222765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": led value must be between 0-15 or " + 223765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang "PCA9685_ALL_LED (255)"); 224765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 225765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 226765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 227765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (time > 4095) 228765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 229765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 230765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": time value must be between 0-4095"); 231765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 232765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 233765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 234765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // figure out the register offset (*_ON_L) 235765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t regoff; 236765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 237765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led == PCA9685_ALL_LED) 238765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_ALL_LED_ON_L; 239765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 240765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_LED0_ON_L + (led * 4); 241765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 242765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // we need to preserve the full ON bit in *_ON_H 243765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t onbit = (readByte(regoff + 1) & 0x10); 244765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 245765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang time = (time & 0x0fff) | (onbit << 8); 246765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 247765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeWord(regoff, time); 248765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 249765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 250765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::ledOffTime(uint8_t led, uint16_t time) 251765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 252765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led > 15 && (led != PCA9685_ALL_LED)) 253765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 254765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 255765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": led value must be between 0-15 or " + 256765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang "PCA9685_ALL_LED (255)"); 257765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 258765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 259765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 260765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (time > 4095) 261765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 262765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang throw std::out_of_range(std::string(__FUNCTION__) + 263765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ": time value must be between 0-4095"); 264765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return false; 265765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 266765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 267765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // figure out the register offset (*_OFF_L) 268765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t regoff; 269765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 270765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (led == PCA9685_ALL_LED) 271765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_ALL_LED_OFF_L; 272765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang else 273765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang regoff = REG_LED0_ON_L + (led * 4) + 2; 274765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 275765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // we need to preserve the full OFF bit in *_OFF_H 276765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t offbit = (readByte(regoff + 1) & 0x10); 277765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 278765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang time = (time & 0x0fff) | (offbit << 8); 279765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 280765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeWord(regoff, time); 281765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 282765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 283765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setPrescale(uint8_t prescale) 284765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 285765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // This will be ignored if the device isn't in SLEEP mode 286765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return writeByte(REG_PRESCALE, prescale); 287765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 288765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 289765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool PCA9685::setPrescaleFromHz(float hz, float oscFreq) 290765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 291765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang float prescale = round( oscFreq / (4096.0 * hz) ) - 1; 292765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 293765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return setPrescale(uint8_t(prescale)); 294765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 295