P015 GPIO with PWM


The P015/6 is a general purpose input / output chip that also has 4 x PWM outputs. Using this Chip can not only save on I/O pins but should anything untoward happen it will also protect the host (RPi, Arduino or ByPic system).

The Chips come in two flavours, P015 (Serial) and P016 (I2C). Both work in identical ways except that the interface is different.

The Chip can be used in a stand alone project or it can be used with the purpose made PCB that attaches to the back of the display. The circuit diagram for the PCB is on the data sheet.

When using the IC without the PCB make sure that the reset and F pins are tied high. The reset of course can be tied with a resistor and an external device can use this line to do a hard reset.

Windows Serial

The chip has TX and RX connections that can be connected to a USB to serial device. If the PCB is not used then only one device at a time can be connected to the serial bus. If the PCB is used then many can be used as the PCB TX attaches to an open collector (more or less) output.

No handshaking is required simply connect TX to RX and RX to TX as shown. It is important that the F and reset pins are tied to +V.

Once connected use BV_COM, this is free and does not need installing, just run the exe.

Set echo on, set the correct COM port.

The P011 has a default address of 'l' (lower case L)

For here some commands can be entered through the terminal for example:

  • lH - check if it is connected okay
  • lg - get value on ports (see inversion below)
  • lm1,512 - set PWM channel to 1/2


If the prompt coming back from the device is '>' then it needs inverting do this by entering:

  • lI

The return should be [06]

This mechanism is provided so that the IC can be used directly or with an open collector output as is the case when using the PCB10. The invert command is a toggle and it will stay even after power remove, so it is a one time operation.

The '>' is easy to detect on automated systems and so can be handled by them.

A much easier way to use the device on windows is to run the sws software that works with the Python language. It is not that difficult to install, the instructions are given here.

This is the Python screen that can be seen with Windows and Linux systems, either using serial or I2C the screen is the same. Actually this screen shot was taken on a Windows box running I2C via a BV4221, the '54' on the status line is the device address.

Windows I2C

There is no output on a Windows PC that will give I2C and so some other device is required. For this a BV4221_V2 device is used that allows an I2C device to be connected via the USB. The Python code 'BV4221_i2c.py' is given in the link as the BV4221_V2 does require setting up for this it is best to follow the instructions on that link. If you have the dialog box running above then you can run the 'swsi2c.py' code and obtain the dialog box as above but this time via the I2C interface.

Raspberry Pi Serial

Voltages: A feature of using PCB 10 is that it has the circuit shown below. This means that you can run the IC at 5V but yet still use the 3.3V host wich would otherwise be a problem. This is because the TX output will be at the voltage supplied to the +V pin, i.e. 5V. The PCB however that can be supplied with this IC has the following circuit:

RB7 is the TX pin form the IC and D1 is a 3.3V* zener diode thus limiting the output to the RPi and providing a safe serial interface. This circuit also has the added bonus that multiple devices can share the TX line and thus the same serial bus.

*The diode may in fact be rated at a higher voltage due to the low resistance characteristic of zener diodes at low current.

Install the serial software as given in the instructions on this site. The connections to the RPi are as shown above. Note that the 5V supply is used to provide the power, it is therefore important to have the above circuit, which the PCB has.

If using the IC without the PCB then it must be supplied with 3V3.

Raspberry Pi I2C

Connection to the RPi via the I2C lines. Here the logic voltage is not important as the PRi will control this with its own internal pull up resistors. (+L goes to 5V)

(Updated May 2017)

Check everything is connected okay

  • Older rpi: sudo i2cdetect -y 0
  • Newer rpi: sudo i2cdetect -y 1

If it can't find i2cdetect then the software has not been installed correctly, go back to step 1) For just the P016 connected it should look exactly like the above 0x36 (decimal 54) is the address of the device.

This is a simple demonstration that will set the PWM channels to low voltage, medium voltage and high voltage

Create a directory and get the two files

wget http://www.byvac.com/downloads/py/easyi2c.py
wget http://www.byvac.com/downloads/py/p015/p016simple.py

Run by:

python simple.py

Then check channels 1 to 3 with a volt meter

Mini Project

This just shows an example of how to drive high current / power loads using the PWM outputs.

The circuit uses a BUZ71 that can switch up to 110A at 250V (do not try this on mains voltages, it is only suitable for DC) The PWM signal is applied to the gate and so this can control the 12V bulb attached from off to full on in 1023 steps.

The only thing to watch out for when choosing a FET like the BUZ71 is the gate threshold voltage and it should be within the range that you have. This is designed to work with 5V logic as the BUZ71 gate threshold is 3V to 5V, it will not work very well if at all on 3.3V. For that a more expensive FET is required., of which there are plenty to choose from.

This is the practical layout, as it is only an experiment then breadboard was used and the SWS Python software, adjusting the slider controls the brightness of the 12V bulb. On the picture the slider is set to 334.

Mini Class Project Example

This is a simple python example that uses the p015A class. The class will work with Serial (P015) or I2C (P016). In general to use the class the following is needed:

The classes are in the downloads section p015A The following files will be needed to complete the project:

The class details are:

  • gpio.mode(pin,direction) # sets a pin to be input (direction=1) or output (direction=0)
  • gpio.wpu(pin,pull) # sets weak pull ups on (pull=1) or off (pull=0) for that pin
  • gpio.get() # gets a byte value representing pins 1 to 8
  • gpio.set(value) # sets a single byte value that will be put on the pins
  • gpio.write(pin,value) # writes 1 (value=1) or 0 (value=0) to a pin
  • gpio.read(pin) # gets the value (1 or 0) that is on an input pin
  • gpio.pwn(chan,value) # set a value (0 to 1023) to a particular pwm channel (1 to 4)
  • See sv3A class for inherited methods

Below is a copy of the miniproject and is used from the command line as shown

For Windows:

python miniproj.py 0 COM21 115200 54 # I2C using BV4221 on COM21
python miniproj.py 1 COM14 9600 l # SERIAL on com14 with address 'l'

For RPi

python miniproj.py 0 1 "" 54 # I2C using bus 1
python miniproj.py 1 /dev/ttyAMA0 9600 h # SERIAL on ttyAMA0 with address 'l'

#! /usr/bin/python
# Mini Project for the PO15 GPIO see http://www.pichips.co.uk
# wget http://www.pin1.org/download/py/p015/p011A.py
# wget http://www.pin1.org/download/py/p015/sv3A.py
# wget http://www.pin1.org/download/py/p015/miniproj.py

import p015A     # gpio class
from sv3A import sv3Bus
import sys
from time import sleep
# ------------------------------------------------------------------------------
# This just ramps up and down the pwm on channel 1, if a LED is connected
# it will go bright and dim
# ------------------------------------------------------------------------------
def gpio_test(bustype,bus,adr):
    if bustype == '1':
        # serial
        gpio = p015A.p015(bus,adr) # adr is string
    if bustype == '0':
        # i2c 
        gpio = p015A.p015(bus,int(adr)) # adr will be a number 
    value = 0
    print "Device id", gpio.ID()
    print "Firemware ",gpio.FW()
    print "Ports read ",gpio.get()
    print "Setting pin 1 to output low"
    gpio.mode(1,0) # output
    gpio.write(1,0) # set low
    while 1: # do forever - probably not a good idea stop with ^ c
        value += 15
        if value > 1023:
            value = 0

if __name__ == "__main__":
    # type = 1 for serial 0 for i2c
    # usage python mimiproj.py 1 COMx Baud h // for serial
    #       python mimiproj.py 0 COMx Baud 54 // for indows i2c
    #       python mimiproj.py 0 1 "" 54// for rpi i2c using bus 1
        bus = sv3Bus(int(sys.argv[1]),sys.argv[2],sys.argv[3]) # open bus for all devices
        msg = 'Cant open comport,'+str(sys.argv[2])+' use: see file miniproj.py'
        print msg


Example of using the P015A class

1) You need to install the software as described above.

2) Type python to get the
>>> prompt

Depending on the host platform (Windows, Rpi) and the method of access (Serial, I2C) will depend on how the bus is activated.

Windows Serial
>>> import p015A
>>> from sv3A import sv3Bus
>>> bus = sv3Bus(1,'COM14',9600) # open bus for all devices
>>> gpio = p015A.p015(bus,'l')

Windows I2C using a BV4221 device
>>> import p015A
>>> from sv3A import sv3Bus
>>> bus = sv3Bus(0,'COM21',115200) # open bus for all devices
>>> gpio = p015A.p015(bus,54)

RPi Serial
>>> import p015A
>>> from sv3A import sv3Bus
>>> bus = sv3Bus(0,'/dev/ttyAMA0',115200) # open bus for all devices
>>> gpio = p015A.p015(bus,54)

>>> import p015A
>>> from sv3A import sv3Bus
>>> bus = sv3Bus(0,'1','') # change to '1' to '0' for older RPi
>>> gpio = p015A.p015(bus,54)

If any of the above reports errors then go back and re-install the software, it is likely that something has been missed.

Try a few commands:

gpio.ID() # get the identiy

gpio.read(pin) # gets the value (1 or 0) that is on an input pin