forked from RobTillaart/PCA9635
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPCA9635.cpp
More file actions
183 lines (161 loc) · 3.73 KB
/
PCA9635.cpp
File metadata and controls
183 lines (161 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// FILE: PCA9635.cpp
// AUTHOR: Rob Tillaart
// DATE: 23-apr-2016
// VERSION: 0.2.0
// PURPOSE: Arduino library for PCA9635 I2C LED driver
// URL: https://github.com/RobTillaart/PCA9635
//
// HISTORY:
// 0.2.0 2020-05-26 major refactor; ESP32 support
// 0.1.2 2020-05-07 fix for PCA9635_MODE1
// 0.1.1 2016-04-24 set autoincr in constructor
// 0.1.0 2016-04-23 initial BETA version
//
#include "PCA9635.h"
#include <Wire.h>
PCA9635::PCA9635(const uint8_t deviceAddress)
{
_address = deviceAddress;
}
#if defined (ESP8266) || defined(ESP32)
void PCA9635::begin(uint8_t sda, uint8_t scl)
{
Wire.begin(sda, scl);
reset();
}
#endif
void PCA9635::begin()
{
Wire.begin();
reset();
}
void PCA9635::reset()
{
_data = 0;
_error = 0;
writeReg(PCA9635_MODE1, 0x81); // AUTOINCR | NOSLEEP | ALLADRR
}
// write value to single PWM registers
uint8_t PCA9635::write1(uint8_t channel, uint8_t value)
{
return writeN(channel, &value, 1);
}
// write three values in consecutive PWM registers
// typically for RGB values
uint8_t PCA9635::write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
{
uint8_t arr[3] = { R, G, B };
return writeN(channel, arr, 3);
}
// write count values in consecutive PWM registers
// does not check if [channel + count > 16]
uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count)
{
if (channel + count > 16)
{
_error = PCA9635_ERR_WRITE;
return PCA9635_ERROR;
}
uint8_t base = PCA9635_PWM(channel);
Wire.beginTransmission(_address);
Wire.write(base);
for(uint8_t i = 0; i < count; i++)
{
Wire.write(arr[i]);
}
_error = Wire.endTransmission();
if (_error != 0)
{
_error = PCA9635_ERR_I2C;
return PCA9635_ERROR;
}
return PCA9635_OK;
}
uint8_t PCA9635::writeMode(uint8_t reg, uint8_t value)
{
if ((reg == PCA9635_MODE1) || (reg == PCA9635_MODE2))
{
writeReg(reg, value);
return PCA9635_OK;
}
_error = PCA9635_ERR_REG;
return PCA9635_ERROR;
}
// Note 0xFF can also mean an error....
uint8_t PCA9635::readMode(uint8_t reg)
{
if ((reg == PCA9635_MODE1) || (reg == PCA9635_MODE2))
{
uint8_t value = readReg(reg);
return value;
}
_error = PCA9635_ERR_REG;
return PCA9635_ERROR;
}
uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode)
{
if (channel > 15)
{
_error = PCA9635_ERR_CHAN;
return PCA9635_ERROR;
}
if (mode > 3)
{
_error = PCA9635_ERR_MODE;
return PCA9635_ERROR;
}
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
// some bit magic
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
uint8_t setmask = mode << shift;
uint8_t clrmask = ~(0x03 << shift);
uint8_t value = (readReg(reg) & clrmask) | setmask;
writeReg(reg, value);
return PCA9635_OK;
}
// returns 0..3 if OK, other values indicate an error
uint8_t PCA9635::getLedDriverMode(uint8_t channel)
{
if (channel > 15)
{
_error = PCA9635_ERR_CHAN;
return PCA9635_ERROR;
}
uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2);
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
uint8_t value = (readReg(reg) >> shift ) & 0x03;
return value;
}
// note error flag is reset after read!
int PCA9635::lastError()
{
int e = _error;
_error = 0;
return e;
}
/////////////////////////////////////////////////////
//
// PRIVATE
//
void PCA9635::writeReg(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(value);
_error = Wire.endTransmission();
}
uint8_t PCA9635::readReg(uint8_t reg)
{
Wire.beginTransmission(_address);
Wire.write(reg);
_error = Wire.endTransmission();
if (Wire.requestFrom(_address, (uint8_t)1) != 1)
{
_error = PCA9635_ERROR;
return 0;
}
_data = Wire.read();
return _data;
}
// -- END OF FILE --