| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package RPi::MultiPCA9685; |
|
2
|
1
|
|
|
1
|
|
138588
|
use 5.006; |
|
|
1
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.08'; |
|
4
|
|
|
|
|
|
|
our @ISA = qw(); |
|
5
|
1
|
|
|
1
|
|
8
|
use strict; |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
49
|
|
|
6
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
39
|
|
|
|
1
|
|
|
|
|
81
|
|
|
7
|
1
|
|
|
1
|
|
671
|
use POSIX qw/ceil floor/; |
|
|
1
|
|
|
|
|
10808
|
|
|
|
1
|
|
|
|
|
6
|
|
|
8
|
1
|
|
|
1
|
|
2735
|
use RPi::I2C; |
|
|
1
|
|
|
|
|
14893
|
|
|
|
1
|
|
|
|
|
70
|
|
|
9
|
1
|
|
|
1
|
|
10
|
use vars qw/@dev $num_PWMPCBs/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
67
|
|
|
10
|
1
|
|
|
1
|
|
6
|
use Exporter 'import'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
715
|
|
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw(init_PWM setChannelPWM disablePWM); |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
14
|
|
|
|
|
|
|
# init all PWM PCBs - the number of boards is determined by the number of Servos (Servos /16) |
|
15
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
16
|
|
|
|
|
|
|
sub init_PWM { |
|
17
|
0
|
|
|
0
|
1
|
|
my $i2cport=shift; |
|
18
|
0
|
|
|
|
|
|
my $i2c_address=shift; |
|
19
|
0
|
|
|
|
|
|
my $i2c_freq=shift; |
|
20
|
0
|
|
|
|
|
|
my $num_servos=shift; |
|
21
|
0
|
|
|
|
|
|
my $presc=int(25000000/(4096*$i2c_freq));# calc the prescaler value for register FEh(254) |
|
22
|
0
|
|
|
|
|
|
$num_PWMPCBs=ceil($num_servos/16); |
|
23
|
0
|
|
|
|
|
|
my $j; |
|
24
|
0
|
|
|
|
|
|
@dev=(); |
|
25
|
0
|
|
|
|
|
|
for ($j=0;$j<=$num_PWMPCBs;$j++){ # init all PWM PCBs - every 16 ports switch to the next i2c address |
|
26
|
0
|
|
|
|
|
|
$dev[$j] = RPi::I2C->new($i2c_address+$j,$i2cport); |
|
27
|
0
|
|
|
|
|
|
$dev[$j]->write_byte(16,0); # allow to program the prescale register (only possible when PWM is inactive) |
|
28
|
0
|
|
|
|
|
|
$dev[$j]->write_byte($presc,254); # set the calculated prescaler value to achieve the desired frequency |
|
29
|
0
|
|
|
|
|
|
$dev[$j]->write_block([32,14],0); # init the pca9685 chip to output the PWM |
|
30
|
|
|
|
|
|
|
} |
|
31
|
0
|
|
|
|
|
|
return 1; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
34
|
|
|
|
|
|
|
# Disable PWM - powers off all devices |
|
35
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
36
|
|
|
|
|
|
|
sub disablePWM { |
|
37
|
0
|
0
|
|
0
|
1
|
|
return unless defined $num_PWMPCBs; # Only disable if init has been done before |
|
38
|
0
|
|
|
|
|
|
my $j; |
|
39
|
0
|
|
|
|
|
|
for ($j=0;$j<=$num_PWMPCBs;$j++){ # disable all PWM PCBs - every 16 ports switch to the next i2c address |
|
40
|
0
|
|
|
|
|
|
$dev[$j]->write_block([0,0,0,0],250); # disable PWM for all channels via chip Register FAh(250) |
|
41
|
|
|
|
|
|
|
} |
|
42
|
0
|
|
|
|
|
|
return 1; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
45
|
|
|
|
|
|
|
# send the pwm values to the PCA9685 chip |
|
46
|
|
|
|
|
|
|
# use the auto address increment of the chip |
|
47
|
|
|
|
|
|
|
# Switches to the next chip if channel 15,31,47,63.... is exceeded |
|
48
|
|
|
|
|
|
|
#---------------------------------------------------------- |
|
49
|
|
|
|
|
|
|
sub setChannelPWM { |
|
50
|
0
|
|
|
0
|
1
|
|
my $servo=shift; # The first servo we send moves |
|
51
|
0
|
|
|
|
|
|
my $mref=shift; # contains a reference for an array that contains moves for perhaps several servos |
|
52
|
0
|
|
|
|
|
|
my @split=(); |
|
53
|
0
|
|
|
|
|
|
my $h; # MSB of the servo move |
|
54
|
|
|
|
|
|
|
my $l; # LSB of the servo move |
|
55
|
0
|
|
|
|
|
|
my $i=0; # start with the first array element |
|
56
|
0
|
|
|
|
|
|
my $rc=0; # set the register count to 0 |
|
57
|
0
|
|
|
|
|
|
my $startreg=6+($servo*4%64); # the first servo register we write to modulo 70 to reset with every new board |
|
58
|
0
|
|
|
|
|
|
my $numref=$#$mref; # the number of positions to write |
|
59
|
0
|
|
|
|
|
|
my $splitref=\@split; # RPI::I2C needs all moves in an array reference |
|
60
|
0
|
|
|
|
|
|
my $brd=int($servo*2/32); # calc the board number - the pwm board to write to |
|
61
|
0
|
|
|
|
|
|
my $obrd=$brd; # previous board is identical with current |
|
62
|
0
|
|
|
|
|
|
while ($i <= $numref){ # $i points onto array element of input array (2 elements per servo) |
|
63
|
0
|
|
|
|
|
|
$brd=int(($i+$servo*2)/32); # calc the board number |
|
64
|
0
|
0
|
|
|
|
|
if ($rc > 15) { |
|
65
|
0
|
|
|
|
|
|
$dev[$obrd]->write_block($splitref,$startreg); # pass all moves of the first block to the PCA9685 chip |
|
66
|
0
|
|
|
|
|
|
@split=(); # empty, because we switch to a new board |
|
67
|
0
|
|
|
|
|
|
$rc=0; # continue with register reset to 0 |
|
68
|
0
|
|
|
|
|
|
$startreg+=32; # make sure the next 8 registers will be higher |
|
69
|
0
|
0
|
|
|
|
|
if ($obrd < $brd) { # in addition a board border is reached ? |
|
70
|
0
|
|
|
|
|
|
$obrd=$brd; # note the change |
|
71
|
0
|
|
|
|
|
|
$startreg=6; # after the chip change start with register 6 of the chip (PWM 0) |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
0
|
0
|
|
|
|
|
if ($obrd < $brd) { |
|
75
|
0
|
|
|
|
|
|
$dev[$obrd]->write_block($splitref,$startreg); # pass all moves of the first block to the PCA9685 chip |
|
76
|
0
|
|
|
|
|
|
@split=(); # empty, because we switch to a new board |
|
77
|
0
|
|
|
|
|
|
$obrd=$brd; # note the change |
|
78
|
0
|
|
|
|
|
|
$startreg=6; # after the chip change start with register 6 of the chip (PWM 0) |
|
79
|
0
|
|
|
|
|
|
$rc=0; # continue with register reset to 0 |
|
80
|
|
|
|
|
|
|
} |
|
81
|
0
|
|
|
|
|
|
$h=int($mref->[$i]) >> 8; # calc MSB |
|
82
|
0
|
|
|
|
|
|
$l=int($mref->[$i]) & 255; # and LSB |
|
83
|
0
|
|
|
|
|
|
push(@split,($l,$h)); # Put all into an array |
|
84
|
0
|
|
|
|
|
|
$rc++; # count the registers in buffer (must not exceed 7 since i2c lib can only write 32 byte at once) |
|
85
|
0
|
|
|
|
|
|
$i++; # point to the next element |
|
86
|
|
|
|
|
|
|
} |
|
87
|
0
|
|
|
|
|
|
$dev[$brd]->write_block($splitref,$startreg); # pass remaining moves to the PCA9685 chip |
|
88
|
0
|
|
|
|
|
|
return 1; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
1; |
|
91
|
|
|
|
|
|
|
__END__ |