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
-
3The 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
1 Answers
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.

- 58,859
- 17
- 112
- 227
-
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: http://www.gnu.org/software/libc/manual/html_node/Low_002dLevel-I_002fO.html 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