1 /*
2 * Author: Jon Trulson <jtrulson@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
PCA9685(int bus,uint8_t address,bool raw)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
~PCA9685()74 PCA9685::~PCA9685()
75 {
76 setModeSleep(true);
77 mraa_i2c_stop(m_i2c);
78 }
79
writeByte(uint8_t reg,uint8_t byte)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
writeWord(uint8_t reg,uint16_t word)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
readByte(uint8_t reg)108 uint8_t PCA9685::readByte(uint8_t reg)
109 {
110 return mraa_i2c_read_byte_data(m_i2c, reg);
111 }
112
readWord(uint8_t reg)113 uint16_t PCA9685::readWord(uint8_t reg)
114 {
115 return mraa_i2c_read_word_data(m_i2c, reg);
116 }
117
setModeSleep(bool sleep)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
enableAutoIncrement(bool ai)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
ledFullOn(uint8_t led,bool val)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
ledFullOff(uint8_t led,bool val)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
ledOnTime(uint8_t led,uint16_t time)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
ledOffTime(uint8_t led,uint16_t time)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
setPrescale(uint8_t prescale)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
setPrescaleFromHz(float hz,float oscFreq)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