Pi IoT In Python Using Linux Drivers - GPIO Using Ioct
Written by Mike James & Harry Fairhead   
Monday, 29 July 2024
Article Index
Pi IoT In Python Using Linux Drivers - GPIO Using Ioct
The struct module
GPIO Output
The complete program

Putting all this together, including definitions for unused constants, gives:

import fcntl
import struct
import io
GPIO_GET_CHIPINFO_IOCTL = 0x8044B401
GPIO_GET_LINEHANDLE_IOCTL = 0xC16CB403
GPIOHANDLE_SET_LINE_VALUES_IOCTL = 0xC040B409
GPIOHANDLE_GET_LINE_VALUES_IOCTL =0xC040B408
GPIOHANDLE_REQUEST_OUTPUT = 0x02
GPIOHANDLE_REQUEST_INPUT = 0x01
GPIOHANDLE_REQUEST_ACTIVE_LOW = 0x04
GPIOHANDLE_REQUEST_OPEN_DRAIN = 0x08
GPIOHANDLE_REQUEST_OPEN_SOURCE = 0x10
gpiochip_info = struct.Struct("32s 32s L")
gpiohandle_request = struct.Struct("64L L 64B 32s L L")
gpiohandle_data = struct.Struct("64B")
lines = [0]*64
lines[0] = 4
lines[1] = 17
values = [0]*64
buffer = gpiohandle_request.pack(*lines, 
GPIOHANDLE_REQUEST_OUTPUT,*values, b"Output test",
2, 0) f = io.open("/dev/gpiochip0", "rb", buffering=0) result = fcntl.ioctl(f, GPIO_GET_LINEHANDLE_IOCTL,
buffer) f.close() fL = struct.unpack_from("L", result, 360)[0] values[0] = 1 values[1] = 0 state1 = gpiohandle_data.pack(*values) values[0] = 0 values[1] = 1 state2 = gpiohandle_data.pack(*values) while(True): result = fcntl.ioctl(fL,
GPIOHANDLE_SET_LINE_VALUES_IOCTL, state1) result = fcntl.ioctl(fL,
GPIOHANDLE_SET_LINE_VALUES_IOCTL, state2)

Remember to change gpiochip0 to gpiochip4 if you are running on a Pi 5.
If you try this out on a Pi Zero you will find that the pulses are faster than you might expect – a pulse width of 40µs giving a frequency of 12kHz. Notice that the switching of the two lines is not in sync. There is a 150ns lag between switching each line. On a Pi Zero 2W the pulse is 10.8µs and 45kHz with a lag of 96ns.

On a Pi 4, the pulse is 4.5µs and 115kHz with a lag of 50ns. On a Pi 5 the pulse is 2.3µs and 218kHz with a lag of 10ns.

These figures should be compared to the performance of the obsolete sysfs approach, which produced 130kHz and a pulse width of 3.6µs on a Pi Zero and 450kHz and 1.1µs on a Pi 4, i.e. the new system is roughly twice as fast as sysfs. However, compared to using the hardware directly from C, when the Pi Zero pulses at about 70ns and the Pi 4 at around 75ns, it is more than ten times slower.

GPIO Input

Reading data from GPIO lines follow the same steps as writing, but with obvious changes:

import fcntl
import struct
import io
import os
GPIO_GET_CHIPINFO_IOCTL = 0x8044B401
GPIO_GET_LINEHANDLE_IOCTL = 0xC16CB403
GPIOHANDLE_SET_LINE_VALUES_IOCTL = 0xC040B409
GPIOHANDLE_GET_LINE_VALUES_IOCTL =0xC040B408
GPIOHANDLE_REQUEST_OUTPUT = 0x02
GPIOHANDLE_REQUEST_INPUT = 0x01
GPIOHANDLE_REQUEST_ACTIVE_LOW = 0x04
GPIOHANDLE_REQUEST_OPEN_DRAIN = 0x08
GPIOHANDLE_REQUEST_OPEN_SOURCE = 0x10
gpiochip_info = struct.Struct("32s 32s L")
gpiohandle_request = struct.Struct("64L L 64B 32s L L")
gpiohandle_data = struct.Struct("64B")
lines = [0]*64
lines[0] = 4
lines[1] = 17
values = [0]*64
buffer = gpiohandle_request.pack(*lines, 
GPIOHANDLE_REQUEST_INPUT,*values, b"Input test",
2, 0) f = io.open("/dev/gpiochip0", "rb", buffering=0) result = fcntl.ioctl(f, GPIO_GET_LINEHANDLE_IOCTL,
buffer) f.close() fL = struct.unpack_from("L", result, 360)[0] inputBuffer=gpiohandle_data.pack(*values) result = fcntl.ioctl(fL,
GPIOHANDLE_GET_LINE_VALUES_IOCTL, inputBuffer) os.close(fL) print(result[0],result[1])

Remember to change gpiochip0 to gpiochip4 if you are running on a Pi 5.

You can see that now the request is to set an input line and the reading part of the program uses the GET and then displays the values in the data structure.

 

In chapter but not in book

  • Measuring R And C Using I/O Control

Summary

  • The raw GPIO character driver is easy to use once you know the ioctl operations supported and their structs.

  • The big problem with using ioctl is finding out the request numbers to use for any particular driver. Despite attempts to organize the allocation of values, this hasn’t really worked.

  • The C structs have to be converted into Python Struct objects and set to appropriate values using pack. Results are similarly unpacked into standard variables.

  • The GPIO lines have to remain open while you use them and you need to remember to close them when you have finished using them.

  • You can set and read multiple GPIO lines in a single function call.

  • The GPIO character driver is about twice as fast as the deprecated sysfs-based interface, but still ten times slower than direct access.

Raspberry Pi IoT In PythonUsing Linux Drivers
Second Edition

By Harry Fairhead & Mike James

DriverPython2e360

Buy from Amazon.

Contents

  1.  Choosing A Pi For IoT
  2.  Getting Started With Python
  3.   Drivers: A First Program
  4.  The GPIO Character Driver 
  5.  GPIO Using Ioct ***NEW!!
  6.  GPIO Events
  7.  The Device Tree
       Extract: The DHT22
  8.  Some Electronics
  9.  Pulse Width Modulation
       Extract: PWM *
  10. SPI Devices
  11. I2C Basics
       Extract: I2C *
  12. The I2C Linux Driver
  13. Advanced I2C
  14. Sensor Drivers
  15. 1-Wire Bus
       Extract 1-Wire And The DS18B20 *
  16. Going Further With Drivers
  17. Appendix I

*From the first edition waiting for update.

 <ASIN:B0CT46R6LF>

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


Postgres And Kubernetes Together In Harmony
17/10/2024

Yes, they can coexist thanks to CloudNativePG, the PostgreSQL Operator for Kubernetes. Furthermore, if you want to try before you buy you can, thanks to the new learning environment, CNPG Playground.

 [ ... ]



52nd Mersenne Prime Found
27/10/2024

It has been nearly six years since the last Mersenne prime was discovered. Now, at last, we have Mersenne prime number 52 and it has 41,024,320 digits!


More News

espbook

 

Comments




or email your comment to: comments@i-programmer.info

 



Last Updated ( Tuesday, 30 July 2024 )