Pi IoT In Python Using GPIO Zero - Pins
Written by Harry Fairhead & Mike James   
Tuesday, 20 February 2024
Article Index
Pi IoT In Python Using GPIO Zero - Pins
Setting a Pin Factory
How Fast?

Which Pin Factory?

If you are happy with the default pin factory there is no need to get deeply involved in selecting a pin factory and you can skip this section and return to it if you ever need to find out more.

The lower-level GPIO libraries interact directly with the hardware and as such they have to be written to work with specific versions of the Pi. Until the Pi 5 this wasn’t difficult as the GPIO implementation was fairly standard. The Pi 5 implements GPIO and other I/O in a new way and this means that the existing GPIO libraries don’t work with it. At the time of writing the only way of using the GPIO and other I/O in the same way across all version of the Pi is to use Linux drivers. The Linux drivers are uniform across all versions of the Pi and this is why they make a good foundation for the default LGPIOFactory. The problem is that Linux drivers tend to be slow and there are faster pin libraries. Indeed, speed is about the only good reason for using something other than the default.

If GPIO Zero is let down by anything, it is the lack of a really high quality high speed GPIO library that works across all versions of the Pi to base a pin factory on. As a result each of the alternative pin factories have advantages and disadvantages.

For GPIO Zero 2 the default pin factory was changed to be LGPIOFactory, which is currently the only factory that works on all versions of the Pi, including the Pi 5. In principle, it should work on any Linux-based system as it uses the standard gpiochip devices. For this reason it is advised that you use the default pin factory unless you have a good reason not to.

Before GPIO Zero 2 the default pin factory, and hence the most commonly used, was RpiGPIOFactory. However, it doesn’t work on the Pi 5 nor does it support the SPI bus, I2C, hardware pulse width modulation (PWM) or the 1-wire bus. It also isn’t undergoing much development and so these features are unlikely to be added in the future. It is faster than the new default pin factory and as such is sometimes worth using in its place if you are sure that you don’t need your program to work on a Pi 5.

The other alternative pin factories are mostly only of historical interest and are included here in case you have to deal with some old software that makes use of them.

RPIOFactory is faster, doesn’t load the CPU and supports a clever software implementation of PWM using DMA (Direct Memory Access), but it doesn’t support the Pi 5, Pi 4 or the Pi Zero and it is no longer supplied as part of GPIO Zero 2. No work has been done on the project since 2014 and the project’s GitHub page notes that it is no longer maintained and is looking for a new maintainer.

The pigpio library also uses DMA to create software PWM on any line, but it currently has only experimental support for the Pi 4 and no support for the Pi 5. Its use of a daemon to control the GPIO lines also seems to have some stability problems. However, the project is still on-going and, if you are prepared for slightly more complexity, it is worth trying. This pin factory is also the only one that supports remote GPIO. It does at least seem to be a well-implemented current project.

The final choice is NativeFactory which is completely Python-based. You can read the code to see how it works and it is very educational. Sadly, it isn’t fully implemented and, while it supports the SPI bus in hardware and software, it doesn’t support PWM at all.

There is also MockFactory which creates software pins that can be used for testing when a Pi isn’t available.

To summarize:

For most applications the default LGPIOFactory is the best choice simply because it is the default, supports all version of the Pi including the Pi 5 and is likely to be the one supported in the future. Its only disadvantage is that it is slower than some alternatives.

The only other pin factory worth considering is the RpiGPIOFactory which is faster but it doesn’t run on the Pi 5 and isn’t likely to see much development in the future.

Currently LGPIOFactory has no ability to work with I2C or 1-wire devices. For these you need to work directly with Linux Drivers as explained in RaspberrPi IOT in Python with Linux Drivers, ISBN:9781871962659.

GPIOZero2E360

Setting a Pin Factory

If you don’t bother to specify a pin factory, GPIO Zero will try to locate one for you and if it can’t find one, because none are installed, it will use the NativeFactory which is always available. In most cases this means that LGPIOFactory will be used as it is installed by default.

You can also set the pin factory to use on the command line using the export command:

export GPIOZERO_PIN_FACTORY = name of pin Factory

You can explicitly select a pin factory from within Python by setting Device.pin_factory:

Device.pin_factory = factoryClass()

where factoryClass is the name for the factory as listed in the table below.

You can also read Device.pin_factory to discover which pin factory is in use.

Each pin factory generates a pin class with a specific name but these all work in the same way and have the same methods and properties. Wbat this means is that you can treat pins produced by any pin factory in the same way.

The Factory and Pin classes corresponding to each of the options are:

Name

Factory class

Pin class

lgpio‍
gpiozero.pins.lgpio.LGPIOFactory
gpiozero.pins.lgpio.LGPIOPin
rpigpio
gpiozero.pins.rpigpio.RPiGPIOFactory
gpiozero.pins.rpigpio.RPiGPIOPin
pigpio
gpiozero.pins.pigpio.PiGPIOFactory
gpiozero.pins.pigpio.PiGPIOPin
native
gpiozero.pins.native.NativeFactory
gpiozero.pins.native.NativePin

You can also specify the pin factory as a parameter in each device constructor:

LED(7,pin_factory=factoryClass())

However, this approach has little value and you should only ever use a single pin factory in a given program. The best advice is to ignore the pin_factory parameter unless you have a good reason not to. Set the pin factory at the start of your program and don’t change it.

You can also create and use a pin factory object directly:

from gpiozero.pins.native import NativeFactory
myFactory = NativeFactory()

pin = myFactory.pin(4)



Last Updated ( Tuesday, 20 February 2024 )