The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.


RPi::WiringPi::FAQ - FAQ and Tutorial for RPi::WiringPi


This document will hopefully provide enough information in a sane way to get you well on your way with manipulating your Raspberry Pi with the RPi::WiringPi and related distributions.

In this document we use constants that are provided with the :all tag in RPi::Const module.


    HIGH         -  connected to 3.3v (positive)
    LOW          -  connected to 0v (ground)
    floating     -  state where a pin is not stable at HIGH or LOW
    PWM          -  Pulse Width Modulation (potentiometer-like)
    INPUT        -  pin is listening only
    OUTPUT       -  pin is active in turning things on/off
    PWM_OUT      -  pin is OUTPUT, but PWM capable
    GPIO_CLOCK   -  pin is used for timing
    PUD          -  internal pull up/down resistor
    PUD_UP       -  PUD resistor pulled to HIGH
    PUD_DOWN     -  PUD resistor pulled to LOW
    EDGE_FALLING -  a state when a pin goes from HIGH to LOW
    EDGE_RISING  -  a state when a pin goes from LOW to HIGH
    EDGE_BOTH    -  both of the above states
    OLED         -  Organic Light Emitting Diode
    DPOT         -  digital potentiometer
    ADC          -  analog to digital converter (in)
    DAC          -  digital to analog converter (out)
    IC           -  integrated circuit
    GPS          -  Global Positioning System
    TPV          -  Time-Position Velocity
    RTC          -  Real-Time Clock (RTC)


Perlbrew configuration

If you want to avoid using your system installed Perl installation to use this software (or you want to use interrupts), you should do some pre-configuration of your system. Note that the system installed Perl does not use threads, which is required for interrupts to function.

As your normal, every day user, install perlbrew:

    \wget -O - | bash
    echo "source /home/pi/perl5/perlbrew/etc/bashrc" >> ~/.bashrc
    sudo reboot

First thing to do is to install the appropriate cpanm version:

    perlbrew install-cpanm

Then, install an instance of Perl, and switch to it:

    perlbrew install perl-5.28.1
    perlbrew switch perl-5.28.1

sudo configuration

NOTE: Only when using PWM features do you need to use sudo. All other aspects of this software work properly with a non-privileged user account.

To use sudo to run your scripts within the appropriate Perl installation, you need to modify the /etc/sudoers file. Prepend the string value for the secure_path directive to include the path to the new perlbrew managed perl, followed by a colon. For example: /home/pi/perl5/perlbrew/perls/perl-5.26.0/bin:. Leave the existing part of the string in place.

Test that it looks correctly:

    sudo echo $PATH

...your new path should be the first entry in the environment variable.

Now, you can do everything with the normal user account, using their personal installation of Perl, and you just need sudo to run your scripts, leaving your default system installation intact.

NOTE: If you get errors about "Permission Denied" accessing /dev/mem or /dev/gpiomem, you need to add the pi user to the gpio group:

    sudo adduser pi gpio

I2C configuration

You need to have some core software installed before using the I2C bus. The Raspberry Pi 3 already has everything pre-loaded. On a typical Unix computer, you'd do something along these lines:

    sudo apt-get install libi2c-dev i2c-tools build-essential

To test your I2C bus:

    i2cdetect -y 1

...or on some machines:

    i2cdetect -y 0

First thing you need to do is enable the I2C bus. You can do so in raspi-config, or ensure the ram=i2c_arm directive is set to on in the /boot/config.txt file:


NOTE: If you get permission errors accessing the I2C bus, you may need to add the pi user to the i2c group:

    sudo adduser pi i2c

Arduino I2C configuration

Often, the default speed of the I2C bus master is too fast for an Arduino. If you do not get any results, try changing the speed. On a Raspberry Pi, you do that by setting the dtparam=i2c_arm_baudrate directive in the /boot/config.txt file:


SPI configuration

First thing you need to do is enable the SPI bus. You can do so in raspi-config, or ensure the dtparam=spi directive is set to on in the /boot/config.txt file:


NOTE: If you get permission errors accessing the SPI bus, you may need to add the pi user to the spi group:

    sudo adduser pi spi

Serial configuration

In order to use GPIO pins 14 and 15 as a serial interface on the Raspberry Pi, you need to disable the built-in Bluetooth adaptor. This distribution's serial functionality will not operate correctly without this being done.

First, in raspi-config, in the Serial section in Interfacing Options, disable "login shell" on the serial interface, then disable Bluetooth by editing the /boot/config.txt, and add the following line:


Save the file, then reboot the Pi.


Create a Raspberry Pi object

First thing that needs doing is some back-end Pi configuration. We take care of that automatically during the Raspberry Pi object creation. Upon instantiation, we set the system to use the GPIO pin numbering scheme.

    my $pi = RPi::WiringPi->new;

Board revision

The board revision is the same as the GPIO pin layout on the board:

    my $revision = $pi->gpio_layout;

Identifying which Raspberry Pi hardware you're working on

WARNING: This methods call system command line commands using sudo internally!

In addition to the following methods, we also install a pre-written command-line script pidentify that can be used.

    pidentify [20]

The 20 is optional. By default, we stay in "identify" state for 5 seconds. The argument specifies that we'll stay in "identify" state for 20 seconds.

While in "identify" state, the green disk I/O LED will stay on completely, and the red power LED will remain off completely.

Turn the green activity LED on full-time, and turn off the red power LED for the default 5 seconds:


Send in an integer as the number of seconds to hold the leds in identify mode:


The above identify() method sleeps the duration. If you wish to enable or disable the above LEDs indefinitely without sleeping in the meantime:

Disk I/O LED toggling

Turn the disk I/O LED on permanently:


Return it to default state of acting as disk I/O indicator:

    $pi->io_led(0); # or just $pi->io_led;

Power LED toggling

Turn the power LED off permanently:


Turn it back to indicate power:

    $pi->pwr_led(0); # or just $pi->pwr_led;

Setting a label/name for your Pi object

You can set, and then retrieve a label/name within your Pi object for easy identification within your scripts.

    print $pi->label . "\n"; # pi-test-01

System Information

We inherit all functionality from the RPi::SysInfo distribution, which provides the following functionality:

CPU usage percent

    my $cpu_percent = $pi->cpu_percent;
    say "CPU utilization: $cpu_percent%";

Example output:

    CPU utilization: 3.80%

Memory usage percent

    my $mem_percent = $pi->mem_percent;
    say "RAM utilization: $mem_percent%";

Example output:

    RAM utilization: 71.01%

CPU core temperature

    my $tC = $pi->core_temp;
    my $tF = $pi->core_temp('f');

    say "Core CPU temperature: $tC C : $tF F";

Example output:

    Core CPU temperature: 46.7 C : 116.06 F

GPIO information

Note: if you do not supply an array reference with pin numbers, by default, we'll return the information for *all* GPIO pins.

    my $pin_21_info = $pi->gpio_info([21]);

    my $multi_pin_info = $pi->gpio_info([2, 4, 6]);

    say "Pin 21 info:";
    say "$pin_21_info\n";

    say "Multi-pin info:";
    say $multi_pin_info;

Example output:

    Pin 21 info:
    GPIO 21: level=0 fsel=0 func=INPUT

    Multi-pin info:
    GPIO 2: level=1 fsel=4 alt=0 func=SDA1
    GPIO 4: level=0 fsel=1 func=OUTPUT
    GPIO 6: level=0 fsel=1 func=OUTPUT

Boot configuration settings

    say $pi->raspi_config;

Example output (significantly snipped for brevity):


Network configuration information

    say $pi->network_info;

This method simply returns the information from the ifconfig system call.

File system information

    say $pi->file_system;

Example output:

    Filesystem     1K-blocks    Used Available Use% Mounted on
    /dev/root       61289372 3375520  55373576   6% /
    devtmpfs          470116       0    470116   0% /dev
    tmpfs             474724       0    474724   0% /dev/shm
    tmpfs             474724   24140    450584   6% /run
    tmpfs               5120       4      5116   1% /run/lock
    tmpfs             474724       0    474724   0% /sys/fs/cgroup
    /dev/mmcblk0p1     43234   22035     21199  51% /boot
    tmpfs              94944       0     94944   0% /run/user/1000

    Filename                                Type            Size    Used    Priority
    /var/swap                               file            102396  0       -2

Pi board and OS details

    say $pi->pi_details;

    Raspberry Pi 3 Model B Rev 1.2

    PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
    NAME="Raspbian GNU/Linux"
    VERSION="9 (stretch)"

    Linux pi-test 4.14.98-v7+ #1200 SMP Tue Feb 12 20:27:48 GMT 2019 armv7l GNU/Linux

    Hardware        : BCM2835
    Revision        : a22082
    Serial          : 000000005d916dc3
    Throttled flag  : throttled=0x50000
    Camera          : supported=0 detected=0


Creating and using a GPIO pin object

The RPi::Pin class provides you with objects that directly map to the Raspberry Pi's onboard GPIO pins. You generate a pin object through the main $pi object we created above. See that documentation for full usage information.

    my $pin = $pi->pin(27);

    # set the mode to output, presumably to power an external device


    # by default, pins are set to LOW (ie. 0 voltage). Turn it on...


    # get the current status of a pin (HIGH or LOW, ie. on or off)

    my $state = $pin->read;

    # get a pin's pin number

    my $num = $pin->num;

Internal pull up/down resistor

All GPIO pins on the Raspberry Pi have built-in pull up/down resistors to prevent pins being in a "floating" state when not connected to either ground or power. This is very important in many situations, particularly when using things like interrupts, buttons etc.

    # HIGH when not in use


    # LOW when not in use


    # disable the resistors entirely (go back to floating)


Pulse Width Modulation (PWM)


Pulse Width Modulation kind of acts like a potentiometer (or a variable switch... like a light dimmer). They are used to send pulses of electricity to a device across time. It is required for things like stepper motors, or dimming an LED. Note that only physical pin 12 on the Raspberry Pi has hardware-based PWM (GPIO #18).

    # set the pin to PWM_OUT mode. Must be physical pin 12


    # values are 0-1023 which represent 0% to 100% power

    $pin->pwm(512); # pin output is ~50%

    # make pin go from off to bright gradually...
    # requires Time::HiRes qw(usleep);

    my $pin = $pi->pin(18);

    for (0..1023){
        usleep 50000;

PWM Clock

The PWM clock can be set to control the PWM pulse widths. The PWM clock is derived from a 19.2MHz clock. You can set any divider.

For example, say you wanted to drive a DC motor with PWM at about 1kHz, and control the speed in 1/1024 increments from 0/1023 (stopped) through to 1023/1023 (full on). In that case you might set the clock divider to be 16, and the RANGE to 1024. The pulse repetition frequency will be 1.2MHz/1024 = 1171.875Hz.



PWM Mode

Each PWM channel can run in either Balanced or Mark-Space mode. In Balanced mode, the hardware sends a combination of clock pulses that results in an overall DATA pulses per RANGE pulses. In Mark-Space mode, the hardware sets the output HIGH for DATA clock pulses wide, followed by LOW for RANGE-DATA clock pulses.

The Raspberry Pi default is balanced mode.

0 for Mark-Space or 1 for balanced. If you're using RPi::Const, you can also use PWM_MODE_MS or PWM_MODE_BAL.



PWM Range

The PWM range is the numeric range in which PWM will go from off to on full. The parameter always uses 0 as its reference, so whatever you send in will become the new top-end of the PWM range:

The default is 1023.


    $pi->pwm_range(511);  # range is now 0-511

    $pi->pwm_range(1023); # back to the default

Interrupt usage

Built in is the ability to have Perl code you define executed when a pin's edge changes (a pin goes from LOW to HIGH or vice-versa). This code acts as an interrupt handler. The Interrupt Service Request that listens for the change runs in a separate C thread than your application.

Interrupts are useful in many cases, but think of a button; you want an action to happen when someone presses a physical button on your prototype, but you obviously want to be doing other things while waiting for that button press.

    # set an interrupt handler for when the pin goes from
    # LOW to HIGH. The second parameter is the string name
    # of the Perl subroutine at the bottom of this example

    $pin->interrupt_set(EDGE_RISING, 'handler');

    # HIGH to LOW

    $pin->interrupt_set(EDGE_FALLING, 'handler');

    # HIGH and LOW (handler will be called on both changes)

    $pin->interrupt_set(EDGE_BOTH, 'handler');

    sub handler {
        print "in handler\n";
        # do other stuff, perhaps turning on/off other pins

NOTE: If you receive errors about the handler callback not being found, simply specify the callback with the full package (eg. 'main::handler').


Allows you to read and write to devices on the I2C bus using the external RPi::I2C distribution. Please refer to that documentation for full usage instructions.

Aruino note: The Arduino may not be able to keep up with the I2C bus speed of the Pi. If this is the case, lower the I2C bus speed on the Pi:


Instantiation and communication

    my $device_addr = 0x04;

    my $device = $pi->i2c($device_addr);

    # read a single byte at the default register address

    print $device->read;

    # read a single byte at a specified register

    print $device->read_byte(0x15);

    # read a block of five bytes (register param optional, not shown)

    my @bytes = $device->read_block(5);

    # write a byte


    # write a byte to a register location

    $device->write_byte(255, 0x0A);

    # write a block of bytes (register param left out again)

    $device->write_block([1, 2, 3, 4]);


Allows you to perform basic read and write operations on a standard serial interface using the RPi::Serial library. See that documentation for full usage information.


Bluetooth on the Pi overlays the serial pins (14, 15) on the Pi. To use serial, you must disable bluetooth in the /boot/config.txt file:



    my $dev  = "/dev/ttyS0";
    my $baud = 115200;

    my $ser = $pi->serial($dev, $baud);


    my $char = $ser->getc;

    $ser->puts("hello, world!");

    my $num_bytes = 12;
    my $str  = $ser->gets($num_bytes);


    my $bytes_available = $ser->avail;


Set up and communication

Allows you to write to and read from devices attached to the SPI bus, using the external RPi::SPI distribution. Please refer to that documentation for full usage instructions.

    # generate a new SPI object

    my $channel = 0; # /dev/spidev0.0

    my $spi = $pi->spi($channel);

    my $buf = [0x01, 0x02];
    my $len = 2;

    # write the two bytes in the buffer to channel /dev/spidev0.0

    $spi->rw($buf, $len);

    # do a read-only call. Send in the number of bytes you want back as dummy
    # bytes (eg. 0)

    my $dummy = [0x00, 0x00, 0x00];

    my @read_buf = $spi->rw($dummy, 3);


Initialization and reading input

We provide access to both the ADS1x15 and MCP3008 ADCs.

The default is to return an ADS1115 object from RPi::ADC::ADS. Please review that documentation for full usage instructions.

    # fetch a new ADC object

    my $adc = $pi->adc;

    # fetch the voltage level on pin A0 on the ADC

    my $v = $adc->volts(0);

    # fetch the percentage of input on pin A1

    my $p = $adc->percent(1);

You can also request an MCP300x ADC from RPi::ADC::MCP3008. Again, for full details, see that documentation.

    my $adc = $pi->adc(model => 'MCP3008', channel => 0);

    my $raw = $adc->raw(0);         # 1st analog input
    my $volts = $adc->volts(2);     # 3rd analog input
    my $percent = $adc->percent(7); # 8th analog input


Configuration, initialization and setting analog output levels

This functionality is brought in from RPi::DAC::MCP4922. Please refer to that documentation for full configuration and usage instructions.

    # prepare and fetch a new DAC object

    my $dac_cs_pin = $pi->pin(29);
    my $spi_chan = 0;

    my $dac = $pi->dac(
        model   => 'MCP4922',
        channel => $spi_chan,
        cs      => $dac_cs_pin

    my ($dacA, $dacB) = (0, 1);

    $dac->set($dacA, 4095); # 100% output
    $dac->set($dacB, 0);    # 0% output


Initialization and usage

This functionality is brought in from RPi::DigiPot::MCP4XXXX. Please refer to that documentation for full usage instructions.

    my $cs = 18;     # GPIO pin connected to dpot CS pin
    my $channel = 0; # SPI channel /dev/spidev0.0

    my $dpot = $pi->dpot($cs, $channel);

    # set to 50% output


    # shutdown (sleep) the potentiometer




This software has the capability to utilize 74HC595 shift registers.

Each register contains 8 digital outputs, and four can be daisy-chained together for a total of 32 extra output pins.

Each register (or chain of registers) require only three GPIO pins.


We'll get right into the code:

    # the new register pins will start at GPIO 100.
    # this can be any number outside of existing GPIO

    my $base = 100;
    # the number of pins on the register(s) you plan on
    # using. Maximum eight per register

    my $num_pins = 8;

    # the GPIO pin number that the register's DS pin (14)
    # is connected to

    my $data = 5;

    # the GPIO pin number that the register's SHCP pin (11)
    # is connected to. This is the register's clock

    my $clk = 6;

    # the GPIO pin number that the register's STCP pin (12)
    # is connected to. This is the register's latch pin

    my $latch = 13;

    # initialize the register

    $pi->shift_register($base, $num_pins, $data, $clk, $latch);

    # now you have full access to the register's eight outputs
    # through standard methods

    for (100..107){
        my $pin = $pi->pin($_);


Allows you to track your current position and various other information. gpsd library must be installed and running. See the GPSD::Parse documentation for full usage instructions.


    my gps = $pi->gps;

    print $gps->lat;        # latitude
    print $gps->lon;        # longitude
    print $gps->speed;      # current speed
    print $gps->direction;  # current heading


Typical 16-pin, 2-4 row and 16-20 column LCD screens work here. You can use 4-bit or 8-bit mode (4-bit requires 6 GPIO pins, 8-bit requires 10). If you need a higher rate of data transmission to the LCD, use 8-bit mode. Typically, 4-bit has always worked perfectly for me.


Before an LCD can be used, it must be initialized. This may look like a lot, but you only need to do it once. Essentially, you're configuring all pins up front.

NOTE: When in 4-bit mode, although you're setting d0 through d3 pins up and leaving d4 through d7 as 0, the wiring must connect to LCD pins d4 through d7. Look at LCD pin 4-7 as LCD pin 0-3 when in 4-bit mode.

    my %lcd_args = (
        rows  => 2,     # number of display rows, 2 or 4
        cols  => 16,    # number of display columns 16 or 20
        bits  => 4,     # data width in bits, 4 or 8
        rs    => 1,     # GPIO pin for the LCD RS pin
        strb  => 2,     # GPIO pin for the LCD strobe (E) pin
        d0    => 3,     #
        ...             # d0-d3 GPIO pinout numbers
        d3    => 6,     #
        d4    => 7,     # set d4-d7 to all 0 (zero) if in 4-bit mode
        ...             # otherwise, set them to their respective
        d7    => 11     # GPIO pins

    my $lcd = $pi->lcd(%lcd_args);

Display operations

Now that we've initialized the LCD, we're ready to use it.

    # turn the display on/off. It's on by default

    $lcd->display(ON);  # or OFF

    # put the cursor at col 0, row 0


    # clear the display and move cursor to home


Cursor operations

    # move the cursor to a position

    $lcd->position(0, 0);   # col 0 (first slot), row 0 (top row)
    $lcd->position(0, 1);   # col 0 (first slot), row 1 (bottom row on 2 row LCD)
    $lcd->positon(5, 1);    # col 5 (6th slot), row 1

    # turn on/off cursor (on by default)

    $lcd->cursor(OFF);  # or ON

    # make the cursor blink (off by default)

    $lcd->cursor_blink(ON); # or OFF

Output operations

By default, output starts at col 0 and row 0 of the display. Use position() to move it around before outputting.

    # print out a string

    $lcd->print("My name is stevieb");

Putting it all together

Here's a trivial script that outputs information to specific LCD positions (we'll start right after an LCD init()).

    my $perl_ver = '5.24.0';
    my $name = 'stevieb';


    $lcd->print("${name}'s RPi, on");
    $lcd->position(0, 1);
    $lcd->print("Perl $perl_ver...");


There's support for the BMP085 and BMP180 barometric pressure and altimiter sensors, which also include a temperature sensor. This functionality is provided by the RPi::BMP180 distribution.


A full use-case example of using the barometric/temperature sensor:

    my $pin_base = 200; # any number higher than the highest GPIO

    my $bmp = $pi->bmp($pin_base);

    my $f = $bmp->temp;
    my $c = $bmp->temp('c');
    my $p = $bmp->pressure; # kPa


We provide access to the DHT11 temperature/humidity sensors through the RPi::DHT11 distribution.


    my $sensor_pin = 21;

    my $env = $pi->hygrometer($sensor_pin);

    my $humidity  = $env->humidity;
    my $temp      = $env->temp; # celcius
    my $farenheit = $env->temp('f');


We provide access to the HCSR04 ultrasonic distance measurement sensor through the RPi::HCSR04 distribution.


    my $trig_pin = 23;
    my $echo_pin = 24;

    my $ruler = $pi->hcsr04($trig_pin, $echo_pin);

    my $inches = $sensor->inch;
    my $cm     = $sensor->cm;
    my $raw    = $sensor->raw;


We provide access to the DS3231 and DS1307 real-time clock modules (RTC) via the RPi::RTC::DS3231 distribution. Please see its documentation for full usage instructions.


    my $rtc = $pi->rtc;

    my $dt_string = $rtc->date_time;


    my $meridien = $rtc->am_pm;


We provide access to OLED displays. Currently, only the 128x64 size is available, and is brought in by the RPi::OLED::SSD1306::128_64 distribution. Please see its documentation for full usage information.


    my $oled = $pi->oled('128x64');

    $oled->string("hello, world!");


    $oled->rect(0, 0, 10, 10); # X, Y, width, height



We provide access to the MCP23017 GPIO expander chip via the RPi::GPIOExpander::MCP23017 distribution. See that documentation for full usage information.


    my $i2c_addr = 0x20;            # default

    my $exp = $pi->expander($i2c_addr); # param not required if using default

    # pins are INPUT by default. Turn the first pin to OUTPUT

    $exp->mode(0, 0); # or MCP23017_OUTPUT if using RPi::Const

    # turn the pin on (HIGH)

    $exp->write(0, 1); # or HIGH

    # read the pin's status (HIGH or LOW)


    # turn the first bank (0) of pins (0-7) to OUTPUT, and make them live (HIGH)

    $exp->mode_bank(0, 0);  # bank A, OUTPUT
    $exp->write_bank(0, 1); # bank A, HIGH

    # enable internal pullup resistors on the entire bank A (0)

    $exp->pullup_bank(0, 1); # bank A, pullup enabled

    # put all 16 pins as OUTPUT, and put them on (HIGH)

    $exp->mode_all(0);  # or OUTPUT
    $exp->write_all(1); # or HIGH

    # cleanup all pins and reset them to default before exiting your program




This method configures PWM clock and divisor to operate a typical 50Hz servo, and returns a special RPi::Pin object. These servos have a left pulse of 50, a centre pulse of 150 and a right pulse of 250. On exit of your program (or a crash), we reset everything back to default.


    my $servo = $pi->servo(18);

    $servo->pwm(150); # centre position
    $servo->pwm(50);  # all the way left
    $servo->pwm(250); # all the way right



This method provides access to the RPi::StepperMotor library to drive a 28BYJ-48 stepper motor through a ULN2003 driver chip.


    my $sm = $pi->stepper_motor(pins => [12, 16, 20, 21]);

    $sm->cw(180);   # clockwise, 180 degrees
    $sm->ccw(240);  # counter-clockwise, 240 degrees

You can also use the stepper motor with a GPIO expander IC, and use those pins instead of the GPIO on the Pi:

    my $expander = $pi->expander;

    my $sm = $pi->stepper_motor(
        epander => $expander,
        pins => [0, 1, 2, 3]    # first four GPIO expander pins




The included RPi::WiringPi::Core module contains a few helper-type methods along with some low-level operations for the hardware itself. for internal and external use. Most of these you won't need, but others are very helpful when writing your own scripts that go beyond trivial.

You can transform pin numbers from one scheme to another, get full pin number maps/translation hashes, manually export and unexport GPIO pins etc.

It's worth having a look at...


Setup and configuration

First off, please review the t/README file for the GPIO pins we use for the test physical configuration, and set up the Pi according to the unit test diagram.

Base information

Before running the tests, you need to set a special environment variable so that we know we're on a Pi board. This ensures CPAN testers won't run the tests across all of its platforms:

    export PI_BOARD=1

Personally, I set all the environment variables in my /etc/environment file.

There are a couple of test files that require root privileges, but we handle this internally by re-running the file with sudo enabled. This allows all tests but these couple to be run as a standard user.

Author Testing

To run the author tests (manifest, POD etc), set:


We use this instead of RELEASE_TESTING, because that typically caused all sorts of grief when installing prerequisites from the CPAN. Other people's distribution's author tests often fail due to having it set.


For testing the RPi::I2C module, we have a dedicated Arduino sketch in the docs/sketch directory that we test against. Install the sketch, hook up the I2C between the Pi and the Arduino, and connect a ground pin on the Arduino to the ground bus on the Pi.

The Arudino has a slower I2C bus than the Pi, so we must lower our bus speed. Add the following line to the /boot/config.txt file, then reboot:


You then set the following environment variable:

    export RPI_ARDUINO=1

These tests skip by default.

Serial Port Testing

To test the serial port RPi::Serial library, you must have a loopback between the Tx and Rx pins, and:

    export RPI_SERIAL=1

These tests will skip by default otherwise.

Note that you must enable serial in raspi-config, disable "terminal over serial", and then reboot after adding the following line in the /boot/config.txt file (this disabled Bluetooth on the Serial interface):


BMP Barometric Pressure Sensor Testing

To test the temperature and barometric pressure from the BMPx80 sensors:

    export RPI_BMP=1

These tests skip by default.

HCSR04 Ultrasonic Testing

For this test, please see the documentation for RPi::HCSR04, and check the test files for the pins that are needed. After confirmed and connected, set

    export RPI_HCSR04=1

These tests only occur in automated mode when building on a Perl that doesn't have prerequisites installed.

OLED Display Testing

These tests use the RPi::OLED::SSD1306::128_64 distribution with a 128x64 pixel I2C OLED display. To have these tests execute, set:

    export RPI_OLED=1

There's a functional script that will display aspects of the system (time, date, temperature and barometric pressure sensor) on an available OLED. While the OLED tests are running, the script automatically disables itself. To operate this functionality:

    perl examples/ &

LCD Testing

In order to perform the RPi::LCD test, a 2 row by 16 column or 4 row by 20 column LCD must be connected and operable. Then, set the following environment variable to a true value:

    export RPI_LCD=1

RTC Testing

To test the RPi::RTC::DS3231 distribution, you must set the following environment variable:

    export RPI_RTC=1

MCP23017 GPIO Expander Testing

To test the RPi::GPIOExpander::MCP23017 distribution, set the following environment variable:

    export RPI_MCP23017=1

PWM/SPI Testing

In order to run tests for PWM and SPI, the following environment variable is required to be set:

    export RPI_ADC=1

Shift Register Testing

To test the shift register functionality, the following environment variables need to be set:

    export RPI_SHIFTREG=1
    export RPI_MCP3008=1

Digital Potentiometer Testing

Set the following environment variable:

    export RPI_DIGIPOT=1

We also need the ADS1115 connected and enabled:

    export RPI_ADC=1

Digital to Analog Converter Testing

To test the functionality of the RPi::DAC::MCP4922, set the following environment variable:

    export RPI_MCP4922=1

Automated with Test::BrewBuild

Test::BrewBuild has some special features specifically to facilitate the automatic testing of this distribution while on a Raspberry Pi, with provisions that allow you to display the last test run results on an LCD if desired.

WARNING: Note that seemingly from perlbrew 0.86, the output of its exec command doesn't display the perl version if only a single instance of perl is installed. Simply ensure you've got more than one Perl instance installed.

Installing Test::BrewBuild

On the Raspberry Pi, we have to install an SSL development library before the Net::SSLeay dependency can be installed:

    sudo apt-get install libssl-dev

Now you can carry on installing Test::BrewBuild in the normal way:

    cpanm Test::BrewBuild

First, on the Pi you're running, you need to set the PI_BOARD environment variable to ensure all tests run. I set this to 1 in /etc/environment.

NEXT, install Test::BrewBuild. Then, start the bbtester software in the background:

    bbtester start -a

The above bbtester command string will only trigger a test build if the local repository commit checksum differs from the remote. To bypass this check and execute a test run every cycle regardless if the checksums differ or not, send in the --csum|-c flag to bbtester:

    bbtester start -a -c

Next, run a bbdispatch run against the local tester in --auto mode. The -a flag with no parameters runs continuously, sleeping for a default of 60 seconds between runs. Simply send in an integer value that represents a certain number of runs if desired.

    bbdispatch -t localhost -r stevieb9/rpi-wiringpi -a

To use the LCD functionality which displays the last date/time that a test run succeeded, along with the last commit tested and its result (PASS/FAIL), set up an environment variable that contains a comma-separated list of GPIO pin numbers that the LCD is connected to (leave off the last two digits if all you have is a two row by 16 column LCD.

    export BB_RPI_LCD=5,6,4,17,27,22,4,20

...which represents LCD pins:

    RS, E, D4, D5, D6, D7

To make it work. I set this one in /etc/environment as well. You then need to restart the dispatcher with the --rpi or the equivalent -R flag:

    bbdispatch -t localhost -r stevieb9/rpi-wiringpi -a --rpi

The --rpi flag is rather hidden (but it *is* documented subtly), as this is a feature that most likely I'll be the only consumer of.

Testing Environment Variable List

Here's the contents of my /etc/environment file, setting the various testing environment variables for the full test platform. For LCD, the last two digits (4, 20) are for four row, 20 column units. If you only have a two row by 16 column unit, leave those last two digits off.



Section that describes some particulars when developing or adding new external devices to RPi::WiringPi. This section is new, and very incomplete. I'll add things as I think of them.


Any time you accept a pin number to pass along to an external module for use, you *must* call $pi->register_pin($pin_num) in order to have the cleanup functionality tidy things up properly. Neglecting to do this will prevent the cleanup regimen from knowing about these pins, and therefore will be left in an inconsistent state, possibly causing damage on a different run.


Steve Bertrand, <>


Copyright (C) 2016-2019 by Steve Bertrand

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.