How to control the GPIO?

If you’re into C, I would check out TinyGPIO on the Pi… https://github.com/dasfoo/rpi-gpio/blob/master/gpio.c (there are newer versions on the net too) you can just change the hardware addresses and start hacking i guess. Even more low level (which should also work on the RockPi): https://elinux.org/RPi_GPIO_Code_Samples#Direct_register_access

RK3399 datasheet, Section 20.4 http://opensource.rock-chips.com/images/e/ee/Rockchip_RK3399TRM_V1.4_Part1-20170408.pdf

Rockchip GPIO has 5 banks, GPIO0~GPIO4, each bank has 32pins, naming as below:

GPIO0_A0 ~ A7 
GPIO0_B0 ~ B7
GPIO0_C0 ~ C7
GPIO0_D0 ~ D7

GPIO1_A0 ~ A7
....
GPIO1_D0 ~ D7

For Rockchip 4.4 kernel, the GPIO number can be calculated as below, take GPIO4_D5(PIN22 on 40PIN GPIO) as an example:

GPIO4_D5 = 32*4 + 8*3 + 5 = 157

To set GPIO4_D5 output

cd /sys/class/gpio
echo 157 > export
cd gpio157
echo out > direction
echo 1 > value     # output high
echo 0 > value     # output low
2 Likes

Tipp:

You can set the output value of an output and configuring the pin as a output in one command:

# Sets the pin as output and sets it to logical HIGH
echo "high" > /sys/class/gpio/gpio157/direction
# Sets the pin as output and sets it to logical LOW
echo "low" > /sys/class/gpio/gpio157/direction
3 Likes

GPIO pin number can be simplified by below table

3 Likes

Nice. i will add it to the wiki :slight_smile:

2 Likes

I implemented a Python wrapper for the GPIOs. One thing to observe is to make a call to seek(0), otherwiese the pins will not show the change in state.

GPIO class:

import os
from subprocess import run
from time import sleep

class GPIO:
    """ class to initialize and switch GPIO pins """
    def __init__(self, gpio_pin):
        """ :param gpio_pin: either a string of the form "GPIO3_D5" where 3 is the bank number  and D5 the address name, or, an integer """

        if type(gpio_pin) == str:
            if not self.parse_gpio_pin(gpio_pin):
                raise ValueError
        elif type(gpio_pin) == int:
            self.pin_number = str(gpio_pin)
        else:
            raise ValueError

        self.pin_dir = "gpio" + self.pin_number  # /sys/class/gpio pin directory name
        self.pin = None  # file descriptor for pin

    def parse_gpio_pin(self, gpio_pin):
         """ parses the input parameter """
        parts = gpio_pin.split('_')
        if len(parts) == 2 and len(parts[0]) == 5 and len(parts[1]) == 2:
            try:
                bank = int(parts[0][4])
            except ValueError:
                return False

            address1_coding = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
            try:
                address1 = address1_coding[parts[1][0]]
            except KeyError:
                return False

            try:
                address2 = int(parts[1][1])
            except ValueError:
                return False

            self.pin_number = str(bank * 32 + address1 * 8 + address2)
            return True

        else:
            return False

    def configure(self):
        """ configure pin for output """
        if not os.path.exists('/sys/class/gpio/' + self.pin_dir):
            subprocess.run('echo ' + self.pin_number + ' > ' + '/sys/class/gpio/export', shell=True)
        subprocess.run('echo out' + ' > ' + '/sys/class/gpio/' + self.pin_dir + '/direction', shell=True)

    def open(self):
        """ open pin directory for writing """
        self.pin = open('/sys/class/gpio/' + self.pin_dir + '/value', 'w')

    def switch(self, on):
        """ function to set pin high or low"""
        if on is True:
            self.pin.write('1')
        else:
            self.pin.write('0')
        # writing becomes effective only after a seek(0):
        self.pin.seek(0)

    def close(self):
        """ close pin directory """
        if self.pin is not None and not self.pin.closed:
            self.pin.close()

    def __del__(self):
        """ automatic closing on object deletion """
        self.close()

Usage:

# test with pin for red on-board LED
gpio = GPIO("GPIO3_D5")
gpio.configure()
gpio.open()

for i in range(10):
    gpio.switch(True)
    sleep(1)
    gpio.switch(False)
    sleep(1)
1 Like

Somehow it doesn’t work in my build (Debian ARM64 + DTB from armhf).

The red LED is on in Debian ARM64 and off in armhf by default, after I copied the DTB from armhf to ARM64. I got the audio but the LED turns off. The intfc:dtoverlay=two-color-led setting in /boot/hw_intfc.conf doesn’t seem affect this on neither side. I guess there are some conflicts going on.

1 Like

The example with the red LED was more to demonstrate the general usage of the GPIO Python class. It can be used to switch any GPIO pin. On my RockPi Armbian system the red LED works.

GPIO_3_D5 = 3 * 32 + 3 * 8 + 5  # = 125
gpio = GPIO(GPIO_3_D5)

If you could parse the name string to convert to number, that would help some people to calculate the numbers.

For newer kernel, the LED is configured as heart beat device. You can not control it. You can control it with led trigger.

cat /sys/class/leds/user-led2/trigger
none rc-feedback kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 mmc1 timer oneshot [heartbeat] backlight gpio cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 default-on rfkill0 mmc2 rfkill1 rfkill2

For example, you can set it to emmc read/write status with following:

echo mmc1 >  /sys/class/leds/user-led2/trigger
1 Like

Good idea, already updated.

HI Jack,
I have problem to activate the GPIO pins on Ubuntu mate desktop with the latest kernel. Could you please have a look at my problem?
https://forum.radxa.com/t/mraa-gpio-list-no-pins/1467

Thanks,
Rolly

Hi friends,

I have a silly question, but I’m not finding the answer.

I’m reading the documentation of the mraa to see if I can learn how to control my gpios. On Raspberry we have to define if we are either going to use the GPIO address or the BOARD address.

Can I do or need to do the same with mraa? What about the gpio.cleanup command ?

Thanks in advance!

Simple C function to get gpio number from string such as GPIO1_D3. Can be ehanced to support lower case such as gpio1_d3. Hope this helps someone.

int get_gpio_number(char *gpio_str)
{
int gpio_no, bank = 0, pin_mul = 0, pin = 0;

if(!gpio_str)
    return -1;

if(strlen(gpio_str) != 8)
    return -1;

bank = gpio_str[4] - '0';
pin_mul = gpio_str[6] - 'A';
pin = gpio_str[7] - '0';

gpio_no = bank*32 + pin_mul*8 + pin;

return gpio_no;
}
2 Likes

The problem with porting libmraa to the ROCK Pi 4 is that there is a TON of software written for many HAT devices that depend on WiringPi. This kind of comparability is critical if you want folks to adopt ROCK Pi 4 over the Raspberry Pi 4. Perhaps you might reconsider your decision and also port WiringPi?

1 Like

I agree with @few. There already exists a WiringNP, which is WiringPi for Nano PI from friedlyelec.
It shouldn’t be a big problem to fork the repo and include also RockPi 4.

The board is detected using CPU information in boardtype_friendlyelec.c. I don’t have any of the boards yet, but I do think that if you compile the repo the board will be detected as Nano Pi M4, which uses RK3399. In the wiringPi.c there are various schemas related to detected board. You should patch the GPIO schema of NanoPi M4 according to RockPi 4. An experienced programmer would need some hour to fork, patch and make the WiringPI for RockPi.

I do agree, that Radxa team should spend this hour of labour work to clone almost done work.

However, not all apps would work, even if you would have WiringPi implemented. Only the apps, referencing with header pin number shall work. For others you would still need to change the GPIO numbers in source.

In my opinion It is no-sense to develop a board which want to be as much as possible compatible with Pi3 and on the other side not supporting the ecosystem of Pi3 world, and in particular the porting of one of the most well working libraries for Gpio

One doesn’t need to support all the childish hacks that are built for pi. Just because a lot of noobs use something stupid does not make it correct or reasonable.

1 Like

I agree with @luke1962. Those noobs are actually buying your boards, don’t forget it.

Dear Radxa,

I would like to have WiringPi and RPI.GPIO library for interfacing ready made examples for Raspberry Pi. I have noticed that FriendlyElec already ported those libraries to their Nano Pi M4. Unfortunately they violate the license agreement and their library are not open source, so no possible port to Rock Pi 4. You could inform them about their violation, they had copied opens source and made it like their own source??? We (buyers of Rock Pi) would expect also from Radxa, to port those widely used libraries made for Rpi.

Thank you.

1 Like