GPIO code execution speed increase

Hi -

I’m trying to send data bytes from a GPIO pin at a rate of 10 k bits/sec. I’ve tried writing code in Python and in C. After I set or clear the pin, I call a sleep function to adjust the length of the bit to be 100 uS. Although any call to the usleep function produces a delay of more than 100 uS, even using usleep(1) to usleep(50).

Is there a way to get the code to execute faster or is it the nature of what’s running in the background like the GUI etc taking up processing power?? Or is there a better way of timing the delay precisely?

Here are the loop tests I created.

Python:

import time
import sys

receive_pin = 18  # BCM pin number. physical pin 12
transmit_pin = 4  # BCM pin number. physical pin 7

def __init__(self,receive_pin, transmit_pin):
  self.rx_pin = receive_pin
  self.tx_pin = transmit_pin
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(self.tx_pin, GPIO.OUT)

while True:
     GPIO.output(self.tx_pin,0)
     time.sleep(1/100000)
     GPIO.output(self.tx_pin,1)
     time.sleep(1/100000)

C example:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{

    int fd = open("/sys/class/gpio/gpio79/direction", O_WRONLY);
    if (fd == -1) {
        perror("Unable to open /sys/class/gpio/gpio79/direction");
        exit(1);
    }

    if (write(fd, "out", 3) != 3) {
        perror("Error writing to /sys/class/gpio/gpio79/direction");
        exit(1);
    }

    close(fd);

    fd = open("/sys/class/gpio/gpio79/value", O_WRONLY);
    if (fd == -1) {
        perror("Unable to open /sys/class/gpio/gpio79/value");
        exit(1);
    }

   // Endless loop to test write speed
    for (;;) {
        write(fd, "1", 1);
        usleep(1);              // Delay for 1 u Sec
        write(fd, "0", 1);
        usleep(1);              // Delay for 1 u Sec
    }

    close(fd);
    return 0;
}

In both of these examples when the sleep function is called, the delay is too long.

Any help will be very appreciated!

Thanks
Jamie

https://raw.githubusercontent.com/jwatte/jetson-gpio-example/master/gpiomem.cpp

Try this way, use mmap is more faster , I can reach 1.8M hz.

Thank you @pointech for your help. I’ve looked through this example on github and I don’t quite understand because I’m new to C programming. It looks like the hrtimer functions in this example are installed as a module. So how do I implement the hrtimer into my code? Do I have to load the module first?

This is what I have so far and when I try to compile an executable using gcc I get an error that it can’t find linux/hrtimer.h : No such file or directory

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <linux/hrtimer.h>


struct hrtimer my_timer;
ktime_t delay = ktime_set(2, 0);

enum hrtimer_restart my_callback(struct hrtimer *timer)
{
    printk("Timer test\n");
    return HRTIMER_NORESTART;
}


int main()
{

    hrtimer_init(&my_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);

    my_timer.function = my_callback;
    hrtimer_start(&my_timer, delay, CLOCK_MONOTONIC); 

    return 0;
}

Any further help would be great

Thanks
Jamie

1 Like

Hi Jamie Basil, linux/hrtimer.h is kernel library header, in Linux opera system , programs are divided into user space and kernel space. . operating system - What is the difference between the kernel space and the user space? - Stack Overflow
user space and kernel space program are use different libraries, kernel space program , we always called as module.
Tutorials/driver.c at master · Embetronicx/Tutorials · GitHub is a module code.

Thank you @pointech
I’m now trying to toggle a gpio pin with the function gpiod_set_value but I’m having troubles. If you have any suggestions that would be great.

When running dmesg I get the error

gpiod_set_value: invalid GPIO (errorpointer)

Here’s my call function


struct device *dev;
struct gpio_desc *data_rx, *data_tx;

data_tx = gpiod_get_index(dev, "data", 1, GPIOD_OUT_HIGH);

gpiod_set_value(data_tx, 1);

Any ideas on what might be happening?

hello JamieBasil,

you should examine whether you’re retrieve GPIO correctly.
for example,

    data_tx = gpiod_get_index(dev, "data", 1, GPIOD_OUT_HIGH);
    if ( IS_ERR(data_tx) ) {
        pr_err("Error when retrieve GPIO\n");
        ...

Thank you JerryChang

Yes when I add the pr_err code you suggested I get the message:

[  570.694891] Error when retrieve GPIO

Could it be a problem with my device tree node ?

data {
        compatible = "gpio-data";
        status = "okay";
        data-gpios = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_HIGH>, /* rx, gpio216, pin 7 */	
                     <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>; /* tx, gpio79, pin 12 */
	};

Hi Jamie,
Are you including header file to use definition of TEGRA_GPIO?

Hi @shgarg

I’m not sure if I’m adding the header file. What specifically is that?

Here’s the entire C source:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>

struct device *dev;
struct gpio_desc *data_rx, *data_tx;

static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);

static const struct of_device_id data_dt_ids[] = {
    { .compatible = "gpio-data", },
    { /* sentinel */ }
};

MODULE_DEVICE_TABLE(of, data_dt_ids);

/*
** Module Init function
*/ 
static int __init etx_driver_init(void)
{

    pr_info("Module init.\n");
 
    data_rx = gpiod_get(dev,"data_rx",GPIOD_IN);
    if ( IS_ERR(data_rx) ) {
        pr_err("Error retrieving GPIO\n");
    } 
    data_tx = gpiod_get(dev,"data_tx",GPIOD_OUT_HIGH);
    if ( IS_ERR(data_tx) ) {
        pr_err("Error retrieving GPIO\n");
    }

    gpiod_set_value(data_tx, 1);
    gpiod_set_value(data_tx, 0);

    return 0;
}

/*
** Module exit function
*/ 
static void __exit etx_driver_exit(void)
{
    pr_info("Module exit.\n");
}
 
module_init(etx_driver_init);
module_exit(etx_driver_exit);

MODULE_LICENSE("GPL");

I’ve changed to code to try and get a simpler example to work but still doesn’t.

Also here is the device tree I’ve been working on. Not sure where my errors are:

	data {
		compatible = "gpio-data";
		status = "okay";
        data_rx-gpios = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; /* rx, gpio216, pin 7 */
		data_tx-gpios = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>; /* tx, gpio79, pin 12 */
	};

Any ideas on how to fix?

Thanks for your help!
Jamie

In your device tree, check if this is there.
#include <dt-bindings/gpio/tegra-gpio.h>

Yes. I have it in tegra210-p3448-0000-p3449-0000-b00.dts. I’m using the latest Jetson Nano 4GB.

Here’s my entire device tree file:

#include "tegra210-porg-p3448-common.dtsi"
#include "porg-platforms/tegra210-porg-pinmux-p3448-0000-b00.dtsi"
#include "porg-platforms/tegra210-porg-gpio-p3448-0000-b00.dtsi"
#include "tegra210-tc358743.dtsi"
#include <dt-bindings/gpio/tegra-gpio.h>

/ {
	model = "NVIDIA Jetson Nano Developer Kit";
	compatible = "nvidia,p3449-0000-b00+p3448-0000-b00", "nvidia,jetson-nano", "nvidia,tegra210";
	nvidia,dtsfilename = __FILE__;

	spi@70410000 {
		status = "okay";
		spiflash@0 {
			controller-data {
				nvidia,x1-len-limit = <16>;
				nvidia,x4-bus-speed = <104000000>;
				nvidia,x4-dymmy-cycle = <8>;
			};
		};
	};

	gpio@6000d000 {
		/* gpio-name for 40-pin header, gpio-name given as COL(10) x ROW(20) */
		gpio-line-names = "",   "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "SPI1_MOSI",    "SPI1_MISO",    "SPI1_SCK",     "SPI1_CS0",     "SPI0_MOSI",    "SPI0_MISO",    "SPI0_SCK",     "SPI0_CS0",
		"SPI0_CS1",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "GPIO13",      "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"UART1_RTS",    "UART1_CTS",    "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "I2S0_FS",    "I2S0_DIN",    "I2S0_DOUT",   "I2S0_SCLK",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "GPIO01",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "GPIO07",   "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "GPIO12",       "",     "",     "",     "",     "",
		"GPIO11",      "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "GPIO09",     "",     "",     "",
		"",     "",     "",     "",     "",     "",     "",     "",     "",     "",
		"",     "",     "SPI1_CS1",     "",     "",     "",     "",     "",     "",     "";
	};


	data {
		compatible = "gpio-data";
		status = "okay";
        data_rx-gpios = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; /* rx, gpio216, pin 7 */
		data_tx-gpios = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>; /* tx, gpio79, pin 12 */
	};


};

These are the error messages I’m getting:

[  868.684671] Module init.
[  868.684676] Error retrieving GPIO
[  868.684688] gpiod_set_value: invalid GPIO (errorpointer)
[  868.684694] gpiod_set_value: invalid GPIO (errorpointer)

Anything else I should check?

Thanks again for your help,
Jamie

Hi Jamie,
These GPIOs are already in use by audio.
Can you try accessing some other gpio? or remove from super-module dtsi.

Hi @shgarg

I just tried both of your suggestions, accessing other gpio and removing super-module dtsi and I still get the errors.

First I commented out the super module include in tegra210-porg-p3448-common.dtsi and that didn’t work.

/* #include "porg-platforms/tegra210-porg-super-module-e2614.dtsi" */

Then I changed the gpio pins to (Z, 0) and (Z, 2):


	data {
		compatible = "gpio-data";
		status = "okay";
        data_rx-gpios = <&gpio TEGRA_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
		data_tx-gpios = <&gpio TEGRA_GPIO(Z, 2) GPIO_ACTIVE_HIGH>; 
	};

This also didn’t work and I’m still getting the same error messages. Did I make these changes correctly?

Thanks
J

Hi Jamie,
Can you try once using data_rx = gpiod_get(dev,“data_rx-gpios”,GPIOD_IN);

HI Jamie,
In your driver, use this API “devm_gpiod_get_optional” instead of “gpiod_get”. It should work. No need to change anything else.

Hi @shgarg

Regarding…

Can you try once using data_rx = gpiod_get(dev,“ data_rx-gpios ”,GPIOD_IN);

when I change it to data_rx-gpios I get this error message when I init:

[  249.636153] driver_gpio_test: loading out-of-tree module taints kernel.

.
When I do the below:

“devm_gpiod_get_optional” instead of “gpiod_get”.

this eliminated the errors I was seeing but I still don’t see the GPIO pin changing yet. I even tried a different pin (E, 6) which I think helps.

	data {
		compatible = "gpio-data";
		status = "okay";
        data_rx-gpios = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; /* rx, gpio216, pin 7 BB 0 */
		data_tx-gpios = <&gpio TEGRA_GPIO(E, 6) GPIO_ACTIVE_HIGH>; /* tx, gpio38, pin 33  E 6*/
	};

This is the source code with the setting pins function. Does this still look correct?

    pr_info("Module init.\n");
 
    data_rx = devm_gpiod_get_optional(dev,"data_rx",GPIOD_IN);
    if ( IS_ERR(data_rx) ) {
        pr_err("Error retrieving GPIO\n");
    } 
    data_tx = devm_gpiod_get_optional(dev,"data_tx",GPIOD_OUT_HIGH);
    if ( IS_ERR(data_tx) ) {
        pr_err("Error retrieving GPIO\n");
    }

    gpiod_set_value(data_tx, 1);
    gpiod_set_value(data_tx, 0);

Thanks again for all your help
J

Hi Jamie,
If you want GPIO to read, you need to use platform_device structure in driver.
Refer some existing driver who is using gpio from device tree. For example: drivers/video/backlight/pwm_bl.c. Go to our kernel source code and check.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.