The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

RPi::MultiPCA9685 - control the PWM channels of several PCA9685 ICs in one go.

SYNOPSIS

    use RPi::MultiPCA9685 qw(init_PWM setChannelPWM);

    # prepare the array reference containing the PWM values.

    my $mref=[0,100,0,200,0,300,0,400,0,500,0,600,0,700,0,800,0,900,0,1000,
              0,1100,0,1200,0,1300,0,1400,0,1500,0,1600,0,1700,0,1800,0,1900,
              0,2000,0,2100,0,2200,0,2300,0,2400,0,2500,0,2600,0,2700,0,2800,
              0,2900,0,3000,0,3100,0,3200,0,3300,0,3400,0,3500,0,3600,0,3700,
              0,3800,0,3900,0,4000];

    # The number of servos or LEDS to control PWM 

    my $num_servos=40;           

    # The frequency of the PWM signal in Hz

    $i2c_freq=50;              

    # The I2C port device

    my $i2cport="/dev/i2c-0";     

    # The I2C address of the first PCA9685 Chip. If you exceed the number of
    # addressable Channels per chip, the next chip will be used 
    # (i2c_address + 1)

    my $i2c_address=0x40;         

    # The first servo or LED where you want to change the PWM. Can be any
    # number from 0 to $num_servos. If you don't want to start with 0, make
    # sure the number of array elements does not exceed the last servo or LED

    my $currentservo=0;           

    # init the PCA9685 devices - needs to be run only once at startup

    init_PWM($i2cport,$i2c_address,$i2c_freq,$num_servos);

    # send the PWM values to the various PCA96585 Chips

    setChannelPWM($currentservo,$mref);

DESCRIPTION

Interface to set the PWM values for one or several PCA9685 ICs in one go. PWM stands for "Pulse Width Modulation" - a technic for stepless control of electric devices to adjust LED brightness or Servo positions and much more. You may set the PWM channels of several consecutively addressed PCA9685 ICs by providing one single array reference that contains the pwm values for all of these chips. This Module may replace Device::PWMGenerator::PCA9685 as this Module is time consuming to install and starts slowly. MultiPCA9685.pm requires only RPi::I2C as a prequisite and not a huge module chain like Device::PWMGenerator::PCA9685. MultiPC9685.pm is especially useful in time critical applications, because it uses the continuous write feature of the chip that saves a lot of addressing time.

READ THIS FIRST

There are particular things to know how PCA9685 ICs are handled in one go.

General

A single PCA9685 chip has 16 PWM channels. Each channel can be individually set by providing a start- and stopvalue. Both values have a resolution of 12 bit, this means a value of 0 to 4096. By providing a start- and stopvalue, the phase of the PWM signal can be defined compared to other channels. So for each PWM channel two values of a range in between 0 and 4096 are reqired.

The array of PWM values passed to setChannelPWM when called can be very long. This depends on the number of PCA9685 chips attached to the I2C bus. So the channels addressed in the array may reach beyond a single PCA9685 chip. In this case the module detects the border of the previous chip and continues automatically with addressing the next chip. This imples, that the next chip has a chip address of +1 compared to the current chip. This is the reason, why only one I2C address needs to be provided during the initialization of the chips using init_PWM. The Array containing the PWM values is one dimensional, so the first element in the array ( mref->[0] ) is the start value of the first channel addressed, where the second value is the stop value of the first channel. The third value is the start value of the second channel and so on... So we can say, even array elements always contain channel start values and odd array elements always contain channel stop values. Along with the module a small sample script will be copied to your /usr/local/bin directory called PCA9685-minimal.pl When started it sets 40 channels for three PCA9685 Chips as an example.

METHODS

init_PWM($i2cport,$i2c_address,$i2c_freq,$num_servos);

Intializes all PCA9685 chips on the bus - depending on the $num_servos parameter.

Parameters:

    $i2cport

Mandatory, String: The name of the I2C device file. Defaults to /dev/i2c-1.

    $i2c_address

Mandatory, Integer (in hex): The address of the first PCA9685 on the I2C bus (i2cdetect -y 1). eg: 0x40.

    $i2c_freq

Mandatory,Integer : The frequency of the PWM in Hz

    $num_servos

Mandatory, Integer : The number of PWM channels you want to address. This defines the number of elements in the array you provide later with setChannelPWM Calc with: num_servos x 2 = number of required array elements to address all channels

setChannelPWM($currentservo,$mref)

Sets the PWM for the channels using the PWM values in the array.

Parameters:

    $currentservo

Mandatory, Integer :

Usually this value is 0 if you want to address all channels starting from the first one. This number defines the first channel you want to address to write PWM values to. All channels - even on subsequent chips have their own unique consecutive channel number. The channel number starts with 0, this is the first channel on the first PCA9685 Chip. The channel number may be quite high and is only limited by the number of PCA9685 chips on the i2C bus. Maximum channel = number of chips x 16. Example: If you have 5 PCA9685 chips attached on the Bus, your maximum Number of channels = 5 x 16 = 80. Imagine you want to start setting PWM at the 2nd channel of the 3rd chip on the bus, then the consecutive channel number for this channel is 33 (2 x 16 -1 +2). the -1 in the calculation is, because the first channel has number 0.

If you set $currentservo to different from 0, you must make sure to pass a shorter array to setChannelPWM than the full range, so you do not write beyond the existing number of channels

If you do not respect this, improper data may be sent to the I2C bus with unpredictable consequences.

    $mref

Mandatory,Array reference to an array of integer values:

This is a array reference to an array, that contains the PWM values - see also section general. The Array may be smaller than $num_servos x 2, but must be at least 2 array elements in size (one servo or LED). If the array is smaller than $num_servos x2, simply the channel PWM setting stops at the last array element. This means, using the combination $currentservo and $mref, you can set only a fraction of all consecutive channels.

disablePWM

Disables the PWM output for all channels.

Parameters: none

Disables the PWM output for all channels. This function may help to prevent of damages to servos if they run against a mechanical block. Servos usually stop moving if they get no PWM at all.

AUTHOR

Rolf Jethon, <rolf at bechele.de>

LICENSE AND COPYRIGHT

Copyright (C) 2023 by Rolf Jethon

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.18.2 or, at your option, any later version of Perl 5 you may have available.