File Coverage

blib/lib/RPi/MultiPCA9685.pm
Criterion Covered Total %
statement 20 73 27.4
branch 0 8 0.0
condition n/a
subroutine 7 10 70.0
pod 3 3 100.0
total 30 94 31.9


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__