line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::Chip::PCA9685; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
77871
|
use strict; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
86
|
|
4
|
4
|
|
|
4
|
|
13
|
use warnings; |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
130
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = 'v0.9'; |
7
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
20
|
use base qw/Device::Chip/; |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
610
|
|
9
|
|
|
|
|
|
|
|
10
|
4
|
|
|
4
|
|
7817
|
use Future; |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
66
|
|
11
|
4
|
|
|
4
|
|
13
|
use Time::HiRes q/usleep/; |
|
4
|
|
|
|
|
3
|
|
|
4
|
|
|
|
|
17
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
C - A C implementation for the PCA9685 chip |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 DESCRIPTION |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
This class implements a L interface for the PCA9685 chip, a 12-bit 16 channel PWM driver. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 SYNOPSIS |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
use Device::Chip::PCA9685; |
24
|
|
|
|
|
|
|
use Device::Chip::Adapter; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $adapter = Device::Chip::Adapter->new_from_description("LinuxKernel"); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $chip = Device::Chip::PCA9685->new(); |
29
|
|
|
|
|
|
|
# This is the i2c bus on an RPI 2 B+ |
30
|
|
|
|
|
|
|
$chip->mount($adapter, bus => '/dev/i2c-1')->get; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
$chip->enable()->get; |
33
|
|
|
|
|
|
|
$chip->set_frequency(400)->get; # 400 Hz |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
$chip->set_channel_value(10, 1024)->get; # Set channel 10 to 25% (1024/4096) |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
$chip->set_channel_full_value(10, 1024, 3192)->get; # Set channel 10 to ON at COUNTER=1024, and OFF at COUNTER=3192 (50% duty cycle, with 25% phase difference) |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 METHODS |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=cut |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my %REGS = ( |
44
|
|
|
|
|
|
|
MODE1 => {addr => 0}, |
45
|
|
|
|
|
|
|
MODE2 => {addr => 1}, |
46
|
|
|
|
|
|
|
SUBADR1 => {addr => 2}, |
47
|
|
|
|
|
|
|
SUBADR2 => {addr => 3}, |
48
|
|
|
|
|
|
|
SUBADR3 => {addr => 4}, |
49
|
|
|
|
|
|
|
ALLCALLADR => {addr => 5}, |
50
|
|
|
|
|
|
|
ALL_CHAN_ON => {addr => 0xFA}, # 16bit |
51
|
|
|
|
|
|
|
ALL_CHAN_OFF => {addr => 0xFC}, # 16bit |
52
|
|
|
|
|
|
|
PRE_SCALE => {addr => 0xFE}, |
53
|
|
|
|
|
|
|
TEST_MODE => {addr => 0xFF}, |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
for my $n (0..15) { |
57
|
|
|
|
|
|
|
$REGS{"CHAN${n}_ON"} = {addr => 0x06 + $n * 4}; # 16bit |
58
|
|
|
|
|
|
|
$REGS{"CHAN${n}_OFF"} = {addr => 0x08 + $n * 4}; # 16bit |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
4
|
|
|
4
|
|
1209
|
use utf8; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
14
|
|
62
|
|
|
|
|
|
|
|
63
|
4
|
|
|
4
|
|
78
|
use constant PROTOCOL => "I2C"; |
|
4
|
|
|
|
|
3
|
|
|
4
|
|
|
|
|
1704
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub _read_u8 { |
66
|
1
|
|
|
1
|
|
1
|
my $self = shift; |
67
|
1
|
|
|
|
|
1
|
my ($register) = @_; |
68
|
|
|
|
|
|
|
|
69
|
1
|
|
|
|
|
3
|
my $regv = $REGS{$register}{addr}; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$self->protocol->write_then_read("\0", 1)->then( sub { |
72
|
1
|
|
|
1
|
|
94
|
my ($value) = @_; |
73
|
1
|
|
|
|
|
3
|
return Future->done(unpack("C", $value)); |
74
|
1
|
|
|
|
|
2
|
}); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub _write_u8 { |
78
|
5
|
|
|
5
|
|
46
|
my $self = shift; |
79
|
5
|
|
|
|
|
8
|
my ($register, $value) = @_; |
80
|
|
|
|
|
|
|
|
81
|
5
|
|
|
|
|
10
|
my $regv = $REGS{$register}{addr}; |
82
|
|
|
|
|
|
|
|
83
|
5
|
|
|
|
|
12
|
$self->protocol->write(pack("C C", $regv, $value)); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub _write_u16 { |
87
|
3
|
|
|
3
|
|
3
|
my $self = shift; |
88
|
3
|
|
|
|
|
5
|
my ($register, @values) = @_; |
89
|
|
|
|
|
|
|
|
90
|
3
|
|
|
|
|
5
|
my $regv = $REGS{$register}{addr}; |
91
|
|
|
|
|
|
|
|
92
|
3
|
|
|
|
|
7
|
$self->protocol->write(pack("C (S<)*", $regv, @values)); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
3
|
|
|
3
|
0
|
496
|
sub I2C_options {my $self = shift; return (addr => 0x40, @_)}; # pass it through, but allow the address to change if passed in, should use a constructor instead |
|
3
|
|
|
|
|
11
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head2 set_channel_value |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
$chip->set_channel_value($channel, $time_on, $offset = 0)->get |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Sets a channel PWM time based on a single value from 0-4095. Starts the channel to turn on at COUNTER = 0, and off at $time_on. |
102
|
|
|
|
|
|
|
C<$offset> lets you stagger the time that the channel comes on and off. This lets you vary the times that channels go on and off |
103
|
|
|
|
|
|
|
to reduce noise effects and power supply issues from large loads all coming on at once. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
C<$on_time> := 0; C<$off_time> := $time_on; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=cut |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub set_channel_value { |
110
|
1
|
|
|
1
|
1
|
78
|
my $self = shift; |
111
|
1
|
|
|
|
|
1
|
my ($chan, $time_on, $offset) = @_; |
112
|
1
|
|
50
|
|
|
5
|
$offset //= 0; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# set the high parts first, we shouldn't ever have backtracking then |
115
|
|
|
|
|
|
|
|
116
|
1
|
50
|
33
|
|
|
7
|
if ($time_on < 0 || $time_on >= 4096) { |
117
|
0
|
0
|
|
|
|
0
|
$time_on = $time_on >= 4096 ? 4095 : 0; |
118
|
0
|
|
|
|
|
0
|
warn "Channel outside allowed value, clamping: $chan, $time_on\n"; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
1
|
|
|
|
|
2
|
$offset %= 4096; # wrap the offset around, that way you can increment it by any amount and have it work as expected |
122
|
1
|
|
|
|
|
1
|
$time_on = ($time_on + $offset) % 4096; # wrap it around based on the offset. |
123
|
|
|
|
|
|
|
|
124
|
1
|
|
|
|
|
3
|
$self->set_channel_full_value($chan, $offset, $time_on); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=head2 set_channel_full_value |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$chip->set_channel_full_value($channel, $on_time, $off_time)->get |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Set a channel value, on and off time. Lets you control the full on and off time based on the 12 bit counter on the device. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=cut |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub set_channel_full_value { |
136
|
1
|
|
|
1
|
1
|
2
|
my ($self, $chan, $on_t, $off_t) = @_; |
137
|
|
|
|
|
|
|
|
138
|
1
|
|
|
|
|
5
|
$self->_write_u16("CHAN${chan}_ON" => ($on_t & 0x0FFF), ($off_t & 0x0FFF)); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 set_channel_on |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
$chip->set_channel_on($channel)->get |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Set a channel to full on. No off time at all. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=cut |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub set_channel_on { |
150
|
1
|
|
|
1
|
1
|
1072
|
my ($self, $chan) = @_; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Set bit 4 of ON high, this is the bit that sets the channel to full on |
153
|
1
|
|
|
|
|
4
|
$self->_write_u16("CHAN${chan}_ON" => 0x1000, 0x0000); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head2 set_channel_off |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
$chip->set_channel_off($channel)->get |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Set a channel to full off. No on time at all. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=cut |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub set_channel_off { |
165
|
1
|
|
|
1
|
1
|
806
|
my ($self, $chan) = @_; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# Set bit 4 of OFF high, this is the bit that sets the channel to full off |
168
|
1
|
|
|
|
|
4
|
$self->_write_u16("CHAN${chan}_ON" => 0x0000, 0x1000); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 set_default_mode |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
$chip->set_default_mode()->get |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Reset the default mode back to the PCA9685. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=cut |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub set_default_mode { |
180
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
181
|
|
|
|
|
|
|
# Sets all the mode registers to the chip defaults |
182
|
0
|
|
|
|
|
0
|
Future->needs_all( |
183
|
|
|
|
|
|
|
$self->_write_u8(MODE1 => 0b0000_0001), |
184
|
|
|
|
|
|
|
$self->_write_u8(MODE2 => 0b000_00100), |
185
|
|
|
|
|
|
|
); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head2 set_frequency |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$chip->set_frequency() |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Set the prescaler to the desired frequency for PWM. Returns the real frequency due to rounding. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub set_frequency { |
197
|
1
|
|
|
1
|
1
|
106
|
my $self = shift; |
198
|
1
|
|
|
|
|
1
|
my ($freq) = @_; |
199
|
4
|
|
|
4
|
|
4010
|
use Data::Dumper; |
|
4
|
|
|
|
|
17882
|
|
|
4
|
|
|
|
|
857
|
|
200
|
|
|
|
|
|
|
|
201
|
1
|
|
|
|
|
6
|
my $divisor = int( ( 25000000 / ( 4096 * $freq ) ) + 0.5 ) - 1; |
202
|
1
|
50
|
|
|
|
2
|
if ($divisor < 3) { die "PCA9685 forces the scaler to be at least >= 3 (1526 Hz)." }; |
|
0
|
|
|
|
|
0
|
|
203
|
1
|
50
|
|
|
|
3
|
if ($divisor > 255) { die "PCA9685 forces the scaler to be <= 255 (24Hz)." }; |
|
0
|
|
|
|
|
0
|
|
204
|
|
|
|
|
|
|
|
205
|
1
|
|
|
|
|
1
|
my $realfreq = 25000000 / (($divisor + 1)*(4096)); |
206
|
|
|
|
|
|
|
|
207
|
1
|
|
|
|
|
1
|
my $old_mode1; |
208
|
|
|
|
|
|
|
$self->_read_u8("MODE1")->then( sub { |
209
|
1
|
|
|
1
|
|
57
|
( $old_mode1 ) = @_; |
210
|
|
|
|
|
|
|
|
211
|
1
|
|
|
|
|
2
|
my $new_mode1 = ($old_mode1 & 0x7f) | 0x10; # Set the chip to sleep, make sure reset is disabled while we do this to avoid noise/phase differences |
212
|
|
|
|
|
|
|
|
213
|
1
|
|
|
|
|
4
|
$self->_write_u8(MODE1 => $new_mode1); |
214
|
|
|
|
|
|
|
})->then( sub { |
215
|
1
|
|
|
1
|
|
92
|
Future->needs_all( |
216
|
|
|
|
|
|
|
$self->_write_u8(PRE_SCALE => $divisor), |
217
|
|
|
|
|
|
|
$self->_write_u8(MODE1 => $old_mode1), |
218
|
|
|
|
|
|
|
); |
219
|
|
|
|
|
|
|
})->then( sub { |
220
|
1
|
|
|
1
|
|
5248
|
usleep(5000); |
221
|
1
|
|
|
|
|
7
|
$self->_write_u8(MODE1 => $old_mode1 | 0x80); # turn on the external clock, should this be optional? |
222
|
|
|
|
|
|
|
})->then( sub { |
223
|
1
|
|
|
1
|
|
109
|
return Future->done( $realfreq ); |
224
|
1
|
|
|
|
|
4
|
}); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=head2 enable |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
$chip->enable()->get |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Enable the device. Must be the first thing done with the device. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=cut |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub enable { |
236
|
1
|
|
|
1
|
1
|
78
|
my $self = shift; |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# 0x20 == AI, auto-increment addresses during register transfer |
239
|
|
|
|
|
|
|
# Useful for 16bit read/write |
240
|
1
|
|
|
|
|
3
|
$self->_write_u8(MODE1 => 0x20); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head1 AUTHOR |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Ryan Voots, |
246
|
|
|
|
|
|
|
Paul 'LeoNerd' Evans |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=cut |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
1; |