8

I've implemented this example to familiarize myself with basic GPIO programming in C. The code demonstrates how to write to GPIO pins but does not explicitly state how to read the state of pins. I suspect that WiringPi will ultimately be a better solution since I'll want to read the state of an output pin eventually, but meanwhile I'd like to complete my trek through Dom and Gert's code. How then, could I read the value of a pin?

  • Care to explain the downvote? – bobthechemist Nov 29 '13 at 16:41
  • 2
    The downvotes are ridiculous, perhaps you've upset someone(s) at some point. +1 from me just to compensate. – goldilocks Nov 29 '13 at 21:13
6

That example from elinux uses memory-mapped IO. The kernel also exports a user space interface via /sys/class/gpio,1 which is also documented on elinux. Working in C you would use low level read()/write() instead of echo, obviously. Don't use higher level stream based functions.

Some programmers become a bit upset when told to use a file interface for things that they believe should be done with system calls. This is purely a matter of style -- they amount to the exact same thing. There is no "additional I/O overhead", etc., accessing a file in this case because it's not a real file, it's a kernel interface. Exactly like any other system ABI you've ever used, only different. The use of /proc and /sys nodes has been long preferred by the kernel developers, but I still see people determined to use system calls where they can -- e.g., sysfs(), despite the fact that man 2 sysfs says clearly:

This System-V derived system call is obsolete; don't use it. On systems with /proc, the same information can be obtained via /proc/filesystems; use that interface instead.

That's a C library man page telling you to use the /proc interface. If that's not good enough to convince you, nothing is. /sys is the same kind of thing. Point being: just because you are using a file node instead of some C specific API doesn't mean you aren't doing real programming, or that performance will suffer, etc. etc. Some people might say it's actually a nice feature. It's also the method recommended by the people who wrote the OS kernel.

A quick introduction to the GPIO interface can be found in [kernel-src]/Documentation/ABI/testing/sysfs-gpio:

  GPIOs are only made available to userspace by an explicit
  "export" operation.  If a given GPIO is not claimed for use by
  kernel code, it may be exported by userspace (and unexported later).
  Kernel code may export it for complete or partial access.

  GPIOs are identified as they are inside the kernel, using integers in
  the range 0..INT_MAX.  See Documentation/gpio.txt for more information.

    /sys/class/gpio
        /export ... asks the kernel to export a GPIO to userspace
        /unexport ... to return a GPIO to the kernel
        /gpioN ... for each exported GPIO #N
            /value ... always readable, writes fail for input GPIOs
            /direction ... r/w as: in, out (default low); write: high, low
            /edge ... r/w as: none, falling, rising, both
        /gpiochipN ... for each gpiochip; #N is its first GPIO
            /base ... (r/o) same as N
            /label ... (r/o) descriptive, not necessarily unique
            /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)

There seem to various tutorials and such online in addition to the elinux one. I've only been using I2C, otherwise I'd give you a more direct answer.

If you are interested in writing kernel space code accessing GPIO, you can have a look here, although I think that is really only useful if you want to write a driver for a specific device and create your own user space API.


1. Since mem-mapped IO must also use read/write, I'm not sure if one method provides a significant advantage over the other here. Using the /sys interface will certainly be more portable, if you are looking for code that will run on things other than a raspberry pi.

  • Thanks. My go to language has been Mathematica, so when it was ported to the RPi I jumped. GPIO access via native Wolfram commands is a bit sluggish at the moment, so I'm trying to to learn enough c to keep me out of trouble. (so no kernel space code writing for me!) – bobthechemist Nov 29 '13 at 21:31
  • read()/write() and the associated file descriptor (as opposed to file stream) based functions are actually not Standard C, but they are POSIX and standard on linux. There's an introduction here: gnu.org/software/libc/manual/html_node/… Standard file streams may work, but in my experience they've also been problematic WRT to /sys and /proc; using the lower level descriptors is not anymore awkward or difficult anyway. Good luck! – goldilocks Nov 30 '13 at 15:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.