Skip to content

Commit 76d61f4

Browse files
committed
create PWMServoDriverGroup
1 parent 73cf3ec commit 76d61f4

File tree

2 files changed

+298
-0
lines changed

2 files changed

+298
-0
lines changed

Adafruit_PWMServoDriverGroup.cpp

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#include "Adafruit_PWMServoDriverGroup.h"
2+
3+
/*!
4+
* @brief Instantiates new PCA9685 PWM driver chips with consecutive
5+
* I2C addresses begining with the default on a TwoWire interface
6+
* @param nDrivers Number of PWM driver chips to instantiate
7+
* @param nServosEach Number of servos to allocate on each driver
8+
*/
9+
Adafruit_PWMServoDriverGroup::Adafruit_PWMServoDriverGroup(const uint8_t nDrivers, const uint8_t nServosEach) {
10+
_nDrivers = nDrivers;
11+
_nServosEach = nServosEach;
12+
13+
_drivers = (Adafruit_PWMServoDriver **) malloc(nDrivers * sizeof(Adafruit_PWMServoDriver *));
14+
15+
for(uint8_t i=0; i < _nDrivers; i++) {
16+
_drivers[i] = new Adafruit_PWMServoDriver(PCA9685_I2C_ADDRESS + i);
17+
}
18+
}
19+
20+
/*!
21+
* @brief Instantiates new PCA9685 PWM driver chips with user defined
22+
* I2C addresses on a TwoWire interface
23+
* @param nDrivers Number of PWM driver chips to instantiate
24+
* @param nServosEach Number of servos to allocate on each driver
25+
* @param addr Array of 7-bit I2C addresses to locate the chips, default is 0x40 through 0x44
26+
*/
27+
Adafruit_PWMServoDriverGroup::Adafruit_PWMServoDriverGroup(const uint8_t nDrivers, const uint8_t nServosEach, const uint8_t *addr) {
28+
_nDrivers = nDrivers;
29+
_nServosEach = nServosEach;
30+
31+
_drivers = (Adafruit_PWMServoDriver **) malloc(nDrivers * sizeof(Adafruit_PWMServoDriver *));
32+
33+
for(uint8_t i=0; i < _nDrivers; i++) {
34+
_drivers[i] = new Adafruit_PWMServoDriver(addr[i], Wire);
35+
}
36+
}
37+
38+
/*!
39+
* @brief Instantiates new PCA9685 PWM driver chips with I2C addresses on a
40+
* TwoWire interface
41+
* @param nDrivers Number of PWM driver chips to instantiate
42+
* @param nServosEach Number of servos to allocate on each driver
43+
* @param addr Array of 7-bit I2C addresses to locate the chips, default is 0x40 thorugh 0x44
44+
* @param i2c A reference to a 'TwoWire' object that we'll use to communicate with
45+
*/
46+
Adafruit_PWMServoDriverGroup::Adafruit_PWMServoDriverGroup(const uint8_t nDrivers, const uint8_t nServosEach, const uint8_t *addr, TwoWire &i2c)
47+
{
48+
_nDrivers = nDrivers;
49+
_nServosEach = nServosEach;
50+
51+
_drivers = (Adafruit_PWMServoDriver **) malloc(nDrivers * sizeof(Adafruit_PWMServoDriver *));
52+
53+
for(uint8_t i=0; i < _nDrivers; i++) {
54+
_drivers[i] = new Adafruit_PWMServoDriver(addr[i], i2c);
55+
}
56+
}
57+
58+
/* @brief Gets the number of PCA9685 PWM driver chips connected to this class
59+
*/
60+
uint8_t Adafruit_PWMServoDriverGroup::getNumDrivers() {
61+
return _nDrivers;
62+
}
63+
64+
/* @brief Gets the number of servos associated with each PCA9685 PWM chip
65+
*/
66+
uint8_t Adafruit_PWMServoDriverGroup::getNumServosEach() {
67+
return _nServosEach;
68+
}
69+
70+
/* @brief Gets the total number of servos associated with this class
71+
*/
72+
uint8_t Adafruit_PWMServoDriverGroup::getNumServos() {
73+
return _nDrivers * _nServosEach;
74+
}
75+
76+
/*!
77+
* @brief Gets the Adafruit_PWMServoDriver associated with a given servo and
78+
* the servo number on that device
79+
* @param num Number of servo in master list
80+
* @param localId returns the number of the servo as known to the PCA9685 chip
81+
* @return The Adafruit_PWMServoDriver associated with the requested servo
82+
*/
83+
Adafruit_PWMServoDriver* Adafruit_PWMServoDriverGroup::getDriver(uint8_t num, uint8_t& localId){
84+
uint8_t driverId = 0;
85+
if(num > _nServosEach - 1) driverId = num/_nServosEach;
86+
localId = num - (driverId * _nServosEach);
87+
88+
return _drivers[driverId];
89+
}
90+
91+
/*!
92+
* @brief Setups the I2C interface and hardware
93+
* @param prescale
94+
* Sets External Clock (Optional)
95+
* @return true if successful, otherwise false
96+
*/
97+
bool Adafruit_PWMServoDriverGroup::begin(uint8_t prescale) {
98+
bool status = true;
99+
for(int i = 0; i < _nDrivers; i++) status &= _drivers[i]->begin(prescale);
100+
101+
return status;
102+
}
103+
104+
/*!
105+
* @brief Sends a reset command to the PCA9685 chips over I2C
106+
*/
107+
void Adafruit_PWMServoDriverGroup::reset() {
108+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->reset();
109+
}
110+
111+
/*!
112+
* @brief Puts boards into sleep mode
113+
*/
114+
void Adafruit_PWMServoDriverGroup::sleep(){
115+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->sleep();
116+
}
117+
118+
/*!
119+
* @brief Wakes boards from sleep
120+
*/
121+
void Adafruit_PWMServoDriverGroup::wakeup(){
122+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->wakeup();
123+
}
124+
125+
/*!
126+
* @brief Sets EXTCLK pin to use the external clock
127+
* @param prescale
128+
* Configures the prescale value to be used by the external clock
129+
*/
130+
void Adafruit_PWMServoDriverGroup::setExtClk(uint8_t prescale){
131+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setExtClk(prescale);
132+
}
133+
134+
/*!
135+
* @brief Sets the PWM frequency for all chips, up to ~1.6 KHz
136+
* @param freq Floating point frequency that we will attempt to match
137+
*/
138+
void Adafruit_PWMServoDriverGroup::setPWMFreq(float freq){
139+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setPWMFreq(freq);
140+
}
141+
142+
/*!
143+
* @brief Sets the output mode of the PCA9685s to either
144+
* open drain or push pull / totempole.
145+
* Warning: LEDs with integrated zener diodes should
146+
* only be driven in open drain mode.
147+
* @param totempole Totempole if true, open drain if false.
148+
*/
149+
void Adafruit_PWMServoDriverGroup::setOutputMode(bool totempole){
150+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setOutputMode(totempole);
151+
}
152+
153+
/*!
154+
* @brief Gets the PWM output of one of the PCA9685 pins
155+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
156+
* @param off If true, returns PWM OFF value, otherwise PWM ON
157+
* @return requested PWM output value
158+
*/
159+
uint16_t Adafruit_PWMServoDriverGroup::getPWM(uint8_t num, bool off){
160+
uint8_t localId = 0;
161+
auto driver = getDriver(num, localId);
162+
return driver->getPWM(localId, off);
163+
}
164+
165+
/*!
166+
* @brief Sets the PWM output of one of the PCA9685 pins
167+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
168+
* @param on At what point in the 4096-part cycle to turn the PWM output ON
169+
* @param off At what point in the 4096-part cycle to turn the PWM output OFF
170+
* @return 0 if successful, otherwise 1
171+
*/
172+
uint8_t Adafruit_PWMServoDriverGroup::setPWM(uint8_t num, uint16_t on, uint16_t off){
173+
uint8_t localId = 0;
174+
auto driver = getDriver(num, localId);
175+
return driver->setPWM(localId, on, off);
176+
}
177+
178+
/*!
179+
* @brief Helper to set pin PWM output. Sets pin without having to deal with
180+
* on/off tick placement and properly handles a zero value as completely off and
181+
* 4095 as completely on. Optional invert parameter supports inverting the
182+
* pulse for sinking to ground.
183+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
184+
* @param val The number of ticks out of 4096 to be active, should be a value
185+
* from 0 to 4095 inclusive.
186+
* @param invert If true, inverts the output, defaults to 'false'
187+
*/
188+
void Adafruit_PWMServoDriverGroup::setPin(uint8_t num, uint16_t val, bool invert){
189+
uint8_t localId = 0;
190+
auto driver = getDriver(num, localId);
191+
driver->setPin(localId, val, invert);
192+
}
193+
194+
/*!
195+
* @brief Reads set Prescale from PCA9685
196+
* @return prescale value
197+
*/
198+
uint8_t Adafruit_PWMServoDriverGroup::readPrescale(){
199+
return _drivers[0]->readPrescale();
200+
}
201+
202+
/*!
203+
* @brief Sets the PWM output of one of the PCA9685 pins based on the input
204+
* microseconds, output is not precise
205+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
206+
* @param Microseconds The number of Microseconds to turn the PWM output ON
207+
*/
208+
void Adafruit_PWMServoDriverGroup::writeMicroseconds(uint8_t num, uint16_t microseconds){
209+
uint8_t localId = 0;
210+
auto driver = getDriver(num, localId);
211+
212+
driver->writeMicroseconds(localId, microseconds);
213+
}
214+
215+
/*!
216+
* @brief Getter for the internally tracked oscillator used for freq
217+
* calculations
218+
* @returns The frequency the PCA9685 thinks it is running at (it cannot
219+
* introspect)
220+
*/
221+
void Adafruit_PWMServoDriverGroup::setOscillatorFrequency(uint32_t freq){
222+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setOscillatorFrequency(freq);
223+
}
224+
225+
void Adafruit_PWMServoDriverGroup::setOscillatorFrequency(uint8_t id, uint32_t freq){
226+
_drivers[id]->setOscillatorFrequency(freq);
227+
}
228+
229+
/*!
230+
* @brief Setter for the internally tracked oscillator used for freq
231+
* calculations
232+
* @param freq The frequency the PCA9685 should use for frequency calculations
233+
*/
234+
uint32_t Adafruit_PWMServoDriverGroup::getOscillatorFrequency(uint8_t id){
235+
return _drivers[id]->getOscillatorFrequency();
236+
}

Adafruit_PWMServoDriverGroup.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*!
2+
* @file Adafruit_PWMServoDriverGroup.h
3+
*
4+
* This Library sets up a group of Adafruit_PWMServoDrivers
5+
* to act like a Adafruit_PWMServoDrivers object
6+
*
7+
*
8+
* Designed specifically to work with the Adafruit 16-channel PWM & Servo
9+
* driver.
10+
*
11+
* BSD license, all text above must be included in any redistribution
12+
*/
13+
#ifndef _ADAFRUIT_PWMServoDriverGroup_H
14+
#define _ADAFRUIT_PWMServoDriverGroup_H
15+
16+
#include "Adafruit_PWMServoDriver.h"
17+
18+
#define PCA9685_I2C_ADDRESS_1 0x40
19+
#define PCA9685_I2C_ADDRESS_2 0x41
20+
#define PCA9685_I2C_ADDRESS_3 0x42
21+
#define PCA9685_I2C_ADDRESS_4 0x43
22+
#define PCA9685_I2C_ADDRESS_5 0x44
23+
24+
/*!
25+
* @brief Class that stores state and functions for interacting with multiple PCA9685
26+
* PWM chips as if they are a single instance
27+
*/
28+
class Adafruit_PWMServoDriverGroup {
29+
public:
30+
31+
Adafruit_PWMServoDriverGroup(const uint8_t ndrivers, const uint8_t nServosEach);
32+
Adafruit_PWMServoDriverGroup(const uint8_t ndrivers, const uint8_t nServosEach, const uint8_t *addr);
33+
Adafruit_PWMServoDriverGroup(const uint8_t ndrivers, const uint8_t nServosEach, const uint8_t *addr, TwoWire &i2c);
34+
35+
Adafruit_PWMServoDriver* getDriver(uint8_t num, uint8_t& localNum);
36+
bool begin(uint8_t prescale = 0);
37+
void reset();
38+
void sleep();
39+
void wakeup();
40+
void setExtClk(uint8_t prescale);
41+
void setPWMFreq(float freq);
42+
void setOutputMode(bool totempole);
43+
uint16_t getPWM(uint8_t num, bool off = false);
44+
uint8_t setPWM(uint8_t num, uint16_t on, uint16_t off);
45+
void setPin(uint8_t num, uint16_t val, bool invert = false);
46+
uint8_t readPrescale(void);
47+
void writeMicroseconds(uint8_t num, uint16_t microseconds);
48+
void setOscillatorFrequency(uint32_t freq);
49+
void setOscillatorFrequency(uint8_t id, uint32_t freq);
50+
uint32_t getOscillatorFrequency(uint8_t id);
51+
52+
uint8_t getNumDrivers();
53+
uint8_t getNumServos();
54+
uint8_t getNumServosEach();
55+
56+
private:
57+
uint8_t _nDrivers;
58+
uint8_t _nServosEach;
59+
Adafruit_PWMServoDriver** _drivers;
60+
};
61+
62+
#endif

0 commit comments

Comments
 (0)