1 /* 2 * Author: Jon Trulson <jtrulson (at) ics.com> 3 * Copyright (c) 2015 Intel Corporation. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <unistd.h> 26 #include <math.h> 27 #include <iostream> 28 #include <string> 29 #include <stdexcept> 30 31 #include "pca9685.h" 32 33 using namespace upm; 34 using namespace std; 35 36 37 PCA9685::PCA9685(int bus, uint8_t address, bool raw) 38 { 39 m_addr = address; 40 41 // setup our i2c link 42 if ( raw ) 43 { 44 m_i2c = mraa_i2c_init_raw(bus); 45 } 46 else 47 { 48 m_i2c = mraa_i2c_init(bus); 49 } 50 51 if ( !m_i2c) 52 { 53 throw std::invalid_argument(std::string(__FUNCTION__) + 54 ": mraa_i2c_init() failed"); 55 return; 56 } 57 58 mraa_result_t rv; 59 60 if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS) 61 { 62 throw std::runtime_error(std::string(__FUNCTION__) + 63 ": mraa_i2c_address() failed"); 64 return; 65 } 66 67 // enable auto-increment mode by default 68 enableAutoIncrement(true); 69 70 // enable restart by default. 71 enableRestart(true); 72 } 73 74 PCA9685::~PCA9685() 75 { 76 setModeSleep(true); 77 mraa_i2c_stop(m_i2c); 78 } 79 80 bool PCA9685::writeByte(uint8_t reg, uint8_t byte) 81 { 82 mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg); 83 84 if (rv != MRAA_SUCCESS) 85 { 86 throw std::runtime_error(std::string(__FUNCTION__) + 87 ": mraa_i2c_write_byte_data() failed"); 88 return false; 89 } 90 91 return true; 92 } 93 94 bool PCA9685::writeWord(uint8_t reg, uint16_t word) 95 { 96 mraa_result_t rv = mraa_i2c_write_word_data(m_i2c, word, reg); 97 98 if (rv != MRAA_SUCCESS) 99 { 100 throw std::runtime_error(std::string(__FUNCTION__) + 101 ": mraa_i2c_write_word_data() failed"); 102 return false; 103 } 104 105 return true; 106 } 107 108 uint8_t PCA9685::readByte(uint8_t reg) 109 { 110 return mraa_i2c_read_byte_data(m_i2c, reg); 111 } 112 113 uint16_t PCA9685::readWord(uint8_t reg) 114 { 115 return mraa_i2c_read_word_data(m_i2c, reg); 116 } 117 118 bool PCA9685::setModeSleep(bool sleep) 119 { 120 uint8_t mode1 = readByte(REG_MODE1); 121 uint8_t restartBit = mode1 & MODE1_RESTART; 122 123 if (sleep) 124 mode1 |= MODE1_SLEEP; 125 else 126 mode1 &= ~MODE1_SLEEP; 127 128 // if we are waking up, then preserve but don't write restart bit if set 129 if (!sleep && restartBit) 130 mode1 &= ~MODE1_RESTART; 131 132 writeByte(REG_MODE1, mode1); 133 134 // Need a delay of 500us after turning sleep mode off for the oscillator 135 // to stabilize 136 if (!sleep) 137 usleep(500); 138 139 // now check to see if we want to (and can) restart when waking up 140 if (restartBit && m_restartEnabled && !sleep) 141 { 142 mode1 |= restartBit; 143 writeByte(REG_MODE1, mode1); 144 } 145 146 return true; 147 } 148 149 bool PCA9685::enableAutoIncrement(bool ai) 150 { 151 uint8_t mode1 = readByte(REG_MODE1); 152 153 if (ai) 154 mode1 |= MODE1_AI; 155 else 156 mode1 &= ~MODE1_AI; 157 158 return writeByte(REG_MODE1, mode1); 159 } 160 161 bool PCA9685::ledFullOn(uint8_t led, bool val) 162 { 163 if (led > 15 && (led != PCA9685_ALL_LED)) 164 { 165 throw std::out_of_range(std::string(__FUNCTION__) + 166 ": led value must be between 0-15 or " + 167 "PCA9685_ALL_LED (255)"); 168 return false; 169 } 170 171 // figure out the register offset (*_ON_H) 172 uint8_t regoff; 173 174 if (led == PCA9685_ALL_LED) 175 regoff = REG_ALL_LED_ON_H; 176 else 177 regoff = REG_LED0_ON_L + (led * 4) + 1; 178 179 uint8_t bits = readByte(regoff); 180 181 if (val) 182 bits |= 0x10; 183 else 184 bits &= ~0x10; 185 186 return writeByte(regoff, bits); 187 } 188 189 bool PCA9685::ledFullOff(uint8_t led, bool val) 190 { 191 if (led > 15 && (led != PCA9685_ALL_LED)) 192 { 193 throw std::out_of_range(std::string(__FUNCTION__) + 194 ": led value must be between 0-15 or " + 195 "PCA9685_ALL_LED (255)"); 196 return false; 197 } 198 199 // figure out the register offset (*_OFF_H) 200 uint8_t regoff; 201 202 if (led == PCA9685_ALL_LED) 203 regoff = REG_ALL_LED_OFF_H; 204 else 205 regoff = REG_LED0_ON_L + (led * 4) + 3; 206 207 uint8_t bits = readByte(regoff); 208 209 if (val) 210 bits |= 0x10; 211 else 212 bits &= ~0x10; 213 214 return writeByte(regoff, bits); 215 } 216 217 bool PCA9685::ledOnTime(uint8_t led, uint16_t time) 218 { 219 if (led > 15 && (led != PCA9685_ALL_LED)) 220 { 221 throw std::out_of_range(std::string(__FUNCTION__) + 222 ": led value must be between 0-15 or " + 223 "PCA9685_ALL_LED (255)"); 224 return false; 225 } 226 227 if (time > 4095) 228 { 229 throw std::out_of_range(std::string(__FUNCTION__) + 230 ": time value must be between 0-4095"); 231 return false; 232 } 233 234 // figure out the register offset (*_ON_L) 235 uint8_t regoff; 236 237 if (led == PCA9685_ALL_LED) 238 regoff = REG_ALL_LED_ON_L; 239 else 240 regoff = REG_LED0_ON_L + (led * 4); 241 242 // we need to preserve the full ON bit in *_ON_H 243 uint8_t onbit = (readByte(regoff + 1) & 0x10); 244 245 time = (time & 0x0fff) | (onbit << 8); 246 247 return writeWord(regoff, time); 248 } 249 250 bool PCA9685::ledOffTime(uint8_t led, uint16_t time) 251 { 252 if (led > 15 && (led != PCA9685_ALL_LED)) 253 { 254 throw std::out_of_range(std::string(__FUNCTION__) + 255 ": led value must be between 0-15 or " + 256 "PCA9685_ALL_LED (255)"); 257 return false; 258 } 259 260 if (time > 4095) 261 { 262 throw std::out_of_range(std::string(__FUNCTION__) + 263 ": time value must be between 0-4095"); 264 return false; 265 } 266 267 // figure out the register offset (*_OFF_L) 268 uint8_t regoff; 269 270 if (led == PCA9685_ALL_LED) 271 regoff = REG_ALL_LED_OFF_L; 272 else 273 regoff = REG_LED0_ON_L + (led * 4) + 2; 274 275 // we need to preserve the full OFF bit in *_OFF_H 276 uint8_t offbit = (readByte(regoff + 1) & 0x10); 277 278 time = (time & 0x0fff) | (offbit << 8); 279 280 return writeWord(regoff, time); 281 } 282 283 bool PCA9685::setPrescale(uint8_t prescale) 284 { 285 // This will be ignored if the device isn't in SLEEP mode 286 return writeByte(REG_PRESCALE, prescale); 287 } 288 289 bool PCA9685::setPrescaleFromHz(float hz, float oscFreq) 290 { 291 float prescale = round( oscFreq / (4096.0 * hz) ) - 1; 292 293 return setPrescale(uint8_t(prescale)); 294 } 295