cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
gsanson
Participant
Participant
11,096 Views
Registered: ‎04-13-2015

Why can't i read the /sys/class/gpio/gpio150/value from in a C app

Jump to solution

Hi,

 

I've gone to the User space under PetaLinux to try and read the PB Switches since I was unable to get the <gpio.h> based code to compile.

 

I can perform the following from the shell

# cat /sys/clas/gpio/gpio150/value

and i get a 1 when the button is pressed and a 0 when released. When I perform a read from the value I always get a 0.

Why is that? How can I read from the value within a C app?

 

Here is the code:

 

int main(int argc, char *argv[ ])
{
    int valuefd_in, valuefd_out, exportfd, directionfd;
    char buf[8];
 
    printf("GPIO test running...\n");
 
    // The GPIO has to be exported to be able to see it
    // in sysfs
 
    exportfd = open("/sys/class/gpio/export", O_WRONLY);
    if (exportfd < 0)
    {
        printf("Cannot open GPIO to export it\n");
        exit(1);
    }
 
    write(exportfd, PBSW14_GPIO, 3);
    write(exportfd, PBSW14_GPIO, 3);
    write(exportfd, DS23_GPIO, 3);
    close(exportfd);
 
    printf("GPIO exported successfully\n");
 
    // Update the direction of the GPIO to be an output
 
    directionfd = open("/sys/class/gpio/gpio148/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "out", 4);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

 
    printf("GPIO direction set as output successfully\n");
 
    // Get the GPIO value ready to be toggled
     valuefd_in = open("/sys/class/gpio/gpio150/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
    // Get the GPIO value ready to be toggled
     valuefd_out = open("/sys/class/gpio/gpio148/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
 
    printf("GPIO value opened, now toggling...\n");
     while (1)
    {
        read(valuefd_in, buf, 5);
        printf("value = %s\n", buf);
        if(buf[0] == '1'){
            write(valuefd_out,"1", 2);
        }else{
            write(valuefd_out,"0", 2);
        }
    }    
}

0 Kudos
1 Solution

Accepted Solutions
gsanson
Participant
Participant
18,350 Views
Registered: ‎04-13-2015

 

Thanks for all the suggestions

 

The double export  PBSW14_GPIO was a typo.

 

I've figured the issue out.

The major isse was the variable I was writing the read into - I used a pointer to an char.

The code that works is below:

 

-------------------------------------------------------------------------------------------------------------------

int main(int argc, char *argv[ ])
{
    int valuefd_in, valuefd_out, exportfd, directionfd;
    char value;
 
    printf("GPIO test running...\n");

     // The GPIO has to be exported to be able to see it
    // in sysfs
 
    exportfd = open("/sys/class/gpio/export", O_WRONLY);
    if (exportfd < 0)
    {
        printf("Cannot open GPIO to export it\n");
        exit(1);
    }
 
    write(exportfd, PBSW13_GPIO, 3);
    write(exportfd, PBSW14_GPIO, 3);
    write(exportfd, DS23_GPIO, 3);
    close(exportfd);
 
    printf("GPIO exported successfully\n");
 
    // Update the direction of the GPIO to be an output
 
    directionfd = open("/sys/class/gpio/gpio148/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "out", 4);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

 
    printf("GPIO direction set as output successfully\n");
 
    // Get the GPIO value ready to be toggled
     valuefd_in = open("/sys/class/gpio/gpio150/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
    // Get the GPIO value ready to be toggled
     valuefd_out = open("/sys/class/gpio/gpio148/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
 
    printf("GPIO value opened, now toggling...\n");
     // toggle the GPIO as fast a possible forever, a control c is needed
    // to stop it
 
    while (1)
    {
        lseek(valuefd_in, 0, SEEK_SET);  // Move to beginning o file
        read(valuefd_in, &value, 1);
        if(value == '1'){
            write(valuefd_out,"1", 2);
        }else{
            write(valuefd_out,"0", 2);
        }
    }    
}

-------------------------------------------------------------------------------------------------------------------

BTW - testing showed that this loop responds between 4 and 10 microseconds

I'm sure an interrupt-drven one would be much more responsive. Does anyone know how to get an interrupt from /sys/class/gpio ?

I really am trying to stay out of changing the device tree (ran into issues following a tutorial - not very clear) or writing a kernel module.

 

 

 

View solution in original post

0 Kudos
6 Replies
sorenb
Xilinx Employee
Xilinx Employee
11,083 Views
Registered: ‎03-13-2012
0 Kudos
norman_wong
Scholar
Scholar
11,080 Views
Registered: ‎05-28-2012

Try rewinding (via lseek()) before each read.

 

 while (1)
    {
        lseek(valuefd_in, 0, SEEK_SET);  // Move to beginning o file
        read(valuefd_in, buf, 5);

 

The GPIO value can only be read "once" and then the fd at EOF.

 

0 Kudos
gsanson
Participant
Participant
11,062 Views
Registered: ‎04-13-2015
Hi,

Tried that and still get a '0' when the button is pressed.
Any other suggestions?
I'm still trying to get the gpio library working, in that gettign the include path correct if possible.
0 Kudos
norman_wong
Scholar
Scholar
11,047 Views
Registered: ‎05-28-2012

That should work. A few comments about your code fragment.
...
    write(exportfd, PBSW14_GPIO, 3); // This should be 4 if PBSW14_GPIO="148" or "150"
    write(exportfd, PBSW14_GPIO, 3); // Why twice?
    write(exportfd, DS23_GPIO, 3);   // This should be 4 if PBSW14_GPIO="148" or "150"
...
// This code is repeated twice.
    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

     valuefd_out = open("/sys/class/gpio/gpio148/value", O_RDWR);
    if (valuefd_in < 0) // Test valuefd_out?
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
...
        read(valuefd_in, buf, 5); // Should only need to read 2.

Perhaps test the return codes from lseek() and read().

0 Kudos
gsanson
Participant
Participant
18,351 Views
Registered: ‎04-13-2015

 

Thanks for all the suggestions

 

The double export  PBSW14_GPIO was a typo.

 

I've figured the issue out.

The major isse was the variable I was writing the read into - I used a pointer to an char.

The code that works is below:

 

-------------------------------------------------------------------------------------------------------------------

int main(int argc, char *argv[ ])
{
    int valuefd_in, valuefd_out, exportfd, directionfd;
    char value;
 
    printf("GPIO test running...\n");

     // The GPIO has to be exported to be able to see it
    // in sysfs
 
    exportfd = open("/sys/class/gpio/export", O_WRONLY);
    if (exportfd < 0)
    {
        printf("Cannot open GPIO to export it\n");
        exit(1);
    }
 
    write(exportfd, PBSW13_GPIO, 3);
    write(exportfd, PBSW14_GPIO, 3);
    write(exportfd, DS23_GPIO, 3);
    close(exportfd);
 
    printf("GPIO exported successfully\n");
 
    // Update the direction of the GPIO to be an output
 
    directionfd = open("/sys/class/gpio/gpio148/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "out", 4);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

    directionfd = open("/sys/class/gpio/gpio150/direction", O_RDWR);
    if (directionfd < 0)
    {
        printf("Cannot open GPIO direction it\n");
        exit(1);
    }
 
    write(directionfd, "in", 3);
    close(directionfd);

 
    printf("GPIO direction set as output successfully\n");
 
    // Get the GPIO value ready to be toggled
     valuefd_in = open("/sys/class/gpio/gpio150/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
    // Get the GPIO value ready to be toggled
     valuefd_out = open("/sys/class/gpio/gpio148/value", O_RDWR);
    if (valuefd_in < 0)
    {
        printf("Cannot open GPIO value\n");
        exit(1);
    }
 
    printf("GPIO value opened, now toggling...\n");
     // toggle the GPIO as fast a possible forever, a control c is needed
    // to stop it
 
    while (1)
    {
        lseek(valuefd_in, 0, SEEK_SET);  // Move to beginning o file
        read(valuefd_in, &value, 1);
        if(value == '1'){
            write(valuefd_out,"1", 2);
        }else{
            write(valuefd_out,"0", 2);
        }
    }    
}

-------------------------------------------------------------------------------------------------------------------

BTW - testing showed that this loop responds between 4 and 10 microseconds

I'm sure an interrupt-drven one would be much more responsive. Does anyone know how to get an interrupt from /sys/class/gpio ?

I really am trying to stay out of changing the device tree (ran into issues following a tutorial - not very clear) or writing a kernel module.

 

 

 

View solution in original post

0 Kudos
norman_wong
Scholar
Scholar
11,034 Views
Registered: ‎05-28-2012

I have doubts about using an integer variable to hold a character. This code
  char value;
  read(valuefd_in, &value, 1);
works only on little endian platforms and if value has zeroes in the upper 3 bytes. If you init value to some value like -1, the comparision to '0' or '1' should fail. As it is, you are depending on the compiler to initialize value to 0. With compiler optimization enabled, this might not happen.

The original code
  char buf[2];
  read(valuefd_in, buf, 2);
should work and more type safe. Your working code, not longer has
  printf("value = %s\n", buf);
Perhaps, the delay due to printing caused you to miss a button press.

GPIO interrupts require use of poll() and the sysfs "edge" attributes. A while back, the Xilinx GPIO driver did not support the interrupt model. It might work now.

 

0 Kudos