1. Control GPIOs

重要

If there is no special mention, the tutorials in this book are based on the Python 3.8.10 version (extboot partition Ubuntu20.04 image) for experiments and explanations.

There is no difference between developing pure software Python applications on Lubancat boards and PCs. The following chapters focus on how to use Python to control peripheral interfaces such as GPIO, PWM, ADC, I2C, and SPI that are rarely used in pure PC programming.

When controlling these peripheral interfaces, the following Python packages are mainly used:

  • python3-libgpiod: The python version of the standard GPIO libgpiod library, which only supports controlling IO input and output.

  • python-periphery: Support basic control of GPIO, PWM, I2C, SPI, UART and other interfaces.

  • Adafruit Blinka: It supports GPIO, PWM, I2C, SPI, UART, etc., and also has some application examples of commonly used sensors and OLED screens.

They have their own characteristics, you can try them all.

1.1. libgpiod basic concept

GPIO is mainly used to output high and low levels externally. When controlling GPIO, it will basically involve the control of libgpiod. We mainly need to know the naming method of the board pins.

The GPIO pins of the CPU are named using (chip, line), and you can view them using the following command:

# Execute the following command on the board
sudo gpioinfo

# If it prompts that the command cannot be found, use the following method to install
sudo apt -y install gpiod libgpiod-dev

# The following is the output of gpioinfo
gpiochip0 - 32 lines:
    line   0:      unnamed       unused   input  active-high
    line   1:      unnamed       unused   input  active-high
    line   2:      unnamed       unused   input  active-high
    line   3:      unnamed       unused   input  active-high
    line   4:      unnamed       unused   input  active-high
    line   5:      unnamed "headset_gpio" input active-high [used]
# ...

    line  31:      unnamed       unused   input  active-high
gpiochip1 - 32 lines:
        line   0:      unnamed       unused   input  active-high
        line   1:      unnamed       unused   input  active-high
# ...
        line  31:      unnamed       unused   input  active-high

For the correspondence between the pin headers and GPIO (chip, line) drawn from the board, please refer to the specific instructions of the board.

For a more detailed description of libgpiod, please refer to the description on the right: “Controlling IO with libgpiod”

1.2. Experiment preparation

Some GPIOs on the board may be used for other functions, you can comment out the loading of some device tree nodes or device tree plug-ins, restart the system, and release the corresponding GPIO pins. Of course, you can also change the pin test. The pins of LubanCat_RK series boards are as follows: “LubanCat-RK Series-40pin Pin Mapping”

Most of the functions of operating hardware peripherals almost require the root user authority. The simple solution is to add sudo before executing the statement or run the program as the root user.

1.3. Method 1: Use python3-libgpiod

1.3.1. Install python3-libgpiod

The python3-libgpiod package makes it easy to control GPIO pins using Python. Currently python3-libgpiod has no official documentation, you can use help to view the help after importing the package. Its installation and viewing help are as follows:

# Use the following command to install on the board
sudo apt -y install python3-libgpiod

# Enter python exchange mode, test and view help
python3
import gpiod
help(gpiod)

# The following is the help description of the output
NAME
    gpiod - Python bindings for libgpiod.

DESCRIPTION
    This module wraps the native C API of libgpiod in a set of python classes.
# ...

1.3.2. libgpiod output

The sample code for controlling GPIO lighting (output) using this python3-libgpiod package is as follows:

Companion ‘code io/gpio/libgpiod_io0.py’ file content
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time
import gpiod

# Modify the Chip and Line used according to the LED light connection of the specific board. If there is no LED, you can connect it externally
LINE_OFFSET = 8

chip0 = gpiod.Chip("0", gpiod.Chip.OPEN_BY_NUMBER)

gpio0_b0 = chip0.get_line(LINE_OFFSET)
gpio0_b0.request(consumer="gpio", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0])

print(gpio0_b0.consumer())

try:
    while True:
        gpio0_b0.set_value(1)
        time.sleep(0.5)
        gpio0_b0.set_value(0)
        time.sleep(0.5)
finally:
    gpio0_b0.set_value(1)
    gpio0_b0.release()

Code description:

  • On line 7, a gpiod.Chip object chip0 with a chip ID of 0 is created

  • Line 9, set to use line8 of the chip0 object as a pin

  • Line 10, apply for gpio, set it as output, and output low level by default

The following code directly uses the gpio0_b0 object to control the selected GPIO output high and low levels, so as to control the LED light on and off.

This example and the following content all use the LubanCat 2 board as the experimental object, so (chip, line)=(0, 8) in the code is selected according to the pin definition of the board. If you use other boards, you only need to modify the corresponding number.

1.3.2.1. Experimental operation

The sample code uses the LubanCat 2 board, the source code can refer to the supporting routine, the operation is as follows:

# Confirm that the python3-libgpiod package is installed
# Execute the following command in the directory where the board blink.py is located, and root permission is required
sudo python3 blink.py

# If an LED is connected to this pin, the light will blink

Use another terminal, use the gpioinfo command, you can see that the gpio (0, 8) pin has been applied for use:

broken

1.3.3. libgpiod input and output

Similarly, the sample code for detecting GPIO input (keypress) using this python3-libgpiod package is as follows:

Companion code ‘io/gpio/libgpiod_io1.py’ file content
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import gpiod

# Modify the Chip and Line used according to the LED light and button connection of the specific board

# Here take LubanCat 2 as an example, use GPIO0_B0 to connect to LED, and GPIO0_C2 to connect to button
LED_LINE_OFFSET = 8
BUTTON_LINE_OFFSET = 18

chip0_led = gpiod.Chip("0", gpiod.Chip.OPEN_BY_NUMBER)
chip0_button = gpiod.Chip("0", gpiod.Chip.OPEN_BY_NUMBER)

led = chip0_led.get_line(LED_LINE_OFFSET)
led.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0])

button = chip0_button.get_line(BUTTON_LINE_OFFSET)
button.request(consumer="BUTTON", type=gpiod.LINE_REQ_DIR_IN)

print(led.consumer())
print(button.consumer())

try:
    while True:
        led.set_value(button.get_value())
finally:
    led.set_value(1)
    led.release()
    button.release()

Code description:

  • Line 12, set the GPIO control direction of the LED to output

  • Line 15, set the GPIO control direction of the button as input

  • Line 23, read the input value of the button pin to control the LED

1.4. Method 2: Use python-periphery

1.4.1. Install python-periphery

python-periphery is functionally similar to python3-libgpiod. However, in addition to supporting GPIO input and output control, the periphery also supports bus protocols such as I2C and SPI.

python-periphery is installed as follows:

# Use the following command to install on the board
sudo pip3 install python-periphery

1.4.2. peripheral input and output

The sample code for input and output using this python-periphery is as follows:

Companion code ‘io/gpio/periphery_io.py’ file content
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from periphery import GPIO

# Modify the Chip and Line used according to the LED light and button connection of the specific board
# Here take LubanCat 2 as an example, use GPIO0_B0 to connect to LED, and GPIO0_C2 to connect to button
LED_CHIP = "/dev/gpiochip0"
LED_LINE_OFFSET = 8

BUTTON_CHIP = "/dev/gpiochip0"
BUTTON_LINE_OFFSET = 18

led = GPIO(LED_CHIP, LED_LINE_OFFSET, "out")
button = GPIO(BUTTON_CHIP, BUTTON_LINE_OFFSET, "in")

try:
    while True:
        led.write(button.read())
finally:
    led.write(True)
    led.close()
    button.close()

Code description:

  • Lines 5 to 9 define the chip and line numbers of LEDs and buttons

  • Lines 11~12 create the GPIO output and input objects of led and button respectively

  • Line 16, read the input value of the button pin to control the LED

The experimental operation is the same as the previous section. Use another terminal, use the gpioinfo command, you can see that two pins have been applied for use:

broken

1.5. Method 3: Using Adafruit Blinka

1.5.1. Installing Adafruit Blinka

Adafruit Blinka is similar to python-periphery in that it not only supports GPIO input and output control, but also supports I2C, SPI and other bus protocols. But Adafruit also provides richer application demos based on blinka, such as controlling the screen and so on.

Adafruit Blinka is installed as follows:

# Use the following command to install on the board
sudo apt -y install python3-libgpiod # Note: If it has been installed in method 1, ignore this step
sudo pip3 install Adafruit-Blinka

1.5.2. Read before use

The Lubancat RK series boards have been adapted to the Adafruit-Blinka library, but the available resources of the Adafruit-Blinka library on different boards are different. According to the Lubancat board in your hand, you can modify the resource name used in the corresponding sample program to complete the corresponding experiment.

It should be noted that some boards have limited resources, so the Adafruit-Blinka library function cannot support all boards. If you want to know whether your board supports some functions, you can query the board resource definition. The reference is as follows:

Make sure the Adafruit-Blinka library is installed and the board can be detected before querying.

  1. Enter python3 to enter the python3 terminal.

  2. Output from adafruit_platformdetect import Detector to add adafruit_platformdetect package;

  3. Enter detector = Detector() followed by print("Chip id: ", detector.chip.id) and print("Board id: ", detector.board.id) Detect board and chip id;

  4. In the python3 terminal, enter import board to import the board package.

  5. Enter board. and double-click the Tab key to display the completion information, which contains the resource content defined by the board.

lubancat-zero series:

broken

LubanCat 1 series:

broken

LubanCat 2 series:

broken

Note that the resources queried here are only the resources we added to adapt the Adafruit-Blinka library. Whether the specific resources can be used depends on the board situation, and you can also try it yourself.

提示

The added board resource is the 40pin lead out, and the setting rule is which pin corresponds to which GPIO. For example, GPIO3 corresponds to the third physical pin of 40pin. If the physical pin is grounded or there is no power supply, for example, there is no GPIO1.

The following formally enters the experimental part.

1.5.3. Adafruit-Blinka input and output

The sample code for using this Adafruit Blinka for input and output is as follows (Here, LubanCat 1 is used as an example, other series need to modify the pins by themselves, etc.):

Companion code ‘io/gpio/digital_io.py’ file content
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import board
import digitalio

# Modify the GPIO used according to the specific board
# Take LubanCat 1 board as an example, board.GPIO11 is the 11th physical pin of 40Ppin, board.GPIO11 = GPIO3_A5 = Pin 101
led = digitalio.DigitalInOut(board.GPIO11)
led.direction = digitalio.Direction.OUTPUT

try:
    while True:
        led.value=1
        time.sleep(0.5)
        led.value=0
        time.sleep(0.5)

finally:
    led.value = True
    led.deinit()

Code description:

  • Lines 1~2, board and digitalio are libraries provided by the Blinka package.

  • Lines 6~7 define the pin board.GPIO11 used and set it as the output direction.

  • Lines 9-14 make the pin output high and low levels.

The board.GPIO11 pin in the code is the LubanCat 1 pin defined in the Blinka library, use the command:

sudo python digital_io.py

If an LED light is connected to the corresponding pin, you can see the LED flashing.

When we apply for the corresponding board resource, it will detect the board model, and then load the corresponding resource definition according to the board information. So we can directly use the defined resource name, which is more intuitive to use than python-periphery.

More detailed pin definitions can be viewed directly in Source code for Adafruit Blinka :

1.6. References

In fact, there are more Python libraries that support peripheral hardware control. If you are interested, you can find them in github or pypi.