Re: [beagleboard] GPIO - how to ?

4574 views
Skip to first unread message
Message has been deleted

Philip Balister

unread,
Sep 23, 2008, 9:08:53 AM9/23/08
to beagl...@googlegroups.com
On Tue, Sep 23, 2008 at 8:51 AM, Arno Steffen <arno.s...@web.de> wrote:
>
> How can I access GPIO pins from userspace, so read or write?
> Is there already a kernel driver for Omap35xx and how to work with that?
> Help is very much welcome!

Take a look at:

http://source.mvista.com/git/gitweb.cgi?p=linux-omap-2.6.git;a=blob;f=Documentation/gpio.txt;h=18022e249c53dc1ad991d74d160551fa32f32070;hb=HEAD

Philip

> ____________________________________________________________________
> Psssst! Schon vom neuen WEB.DE MultiMessenger gehört?
> Der kann`s mit allen: http://www.produkte.web.de/messenger/?did=3123
>
>
> >
>

John Beetem

unread,
Sep 23, 2008, 11:16:52 AM9/23/08
to Beagle Board
On the Ångström demo I've been able to use mmap() and /dev/mem to map
OMAP peripheral memory into my user space application. This way I can
access OMAP registers directly instead of having to go through device
drivers. So far I've
only accessed the GPIO registers so I could play with the user LEDs.

The C code looks something like this:

int fd = open("/dev/mem", O_RDWR); volatile ulong *A;
if (fd < 0) {printf("Could not open file\n"); return;}
A = (ulong*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0x49050000);
if (A == MAP_FAILED) {printf("Mapping failed\n"); close(fd);
return;}
A[0x603C / 4] |= 0x600000; // Turn on LEDs

Bill Gatliff

unread,
Sep 23, 2008, 11:22:14 AM9/23/08
to beagl...@googlegroups.com
John Beetem wrote:
> On the Ångström demo I've been able to use mmap() and /dev/mem to map
> OMAP peripheral memory into my user space application. This way I can
> access OMAP registers directly instead of having to go through device
> drivers. So far I've
> only accessed the GPIO registers so I could play with the user LEDs.

Be careful of that if something kernel-side is using those same registers--- you
might interrupt each other, and end up with incoherent values in the registers.

The sysfs interface to gpiolib (see gpio.txt) is pretty lightweight, avoids
having to interact with GPIO peripheral control registers directly from
userspace, and thereby avoids the risk of clobbering register values due to
contention with kernel context. But that interface only works for
machines/platforms that use gpiolib (which I think includes Beagleboard).

Where nothing kernel-side is touching the area being mmap'ed, then your code
works fine--- for any peripheral, not just gpio.


b.g.
--
Bill Gatliff
bg...@billgatliff.com

Arno Steffen

unread,
Sep 24, 2008, 3:35:23 AM9/24/08
to beagl...@googlegroups.com
In my kernel sources the gpio.txt differs a bit.
Dirk gave me the hint, that calling this functions is ony allowed in kernel-space.
The result was:

But if I do in gpio_test.c
---------------------------------------------
#include <stdio.h>
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int
#include <asm/arch/gpio.h>
main()
{ ..
gpio_direction_input(3);
.. }
---------------------------------------------
I get

uilding file: ../gpio_test.c
Invoking: Sourcery G++ C Compiler
arm-none-linux-gnueabi-gcc -I/opt/src/2.6_kernel/include -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"gpio_test.d" -MT"gpio_test.d" -o"gpio_test.o" "../gpio_test.c"
In file included from /opt/src/2.6_kernel/include/asm/arch/gpio.h:142,
from ../gpio_test.c:13:
/opt/src/2.6_kernel/include/asm-generic/gpio.h: In function 'gpio_get_value_cansleep':
/opt/src/2.6_kernel/include/asm-generic/gpio.h:15: warning: implicit declaration of function 'might_sleep'
../gpio_test.c: At top level:
../gpio_test.c:40: warning: return type defaults to 'int'
../gpio_test.c: In function 'main':
../gpio_test.c:98: warning: control reaches end of non-void function
Finished building: ../gpio_test.c

Building target: gpio
Invoking: Sourcery G++ C Linker
arm-none-linux-gnueabi-gcc -o"gpio" ./gpio_test.o
./gpio_test.o: In function `__gpio_set_direction':
/opt/src/2.6_kernel/include/asm/arch/gpio.h:117: undefined reference to `omap_set_gpio_direction'
collect2: ld returned 1 exit status
make: *** [gpio] Fehler 1
..

My kernel config has:
CONFIG_GENERIC_GPIO=y
CONFIG_OMAP_GPIO_SWITCH=y

> -----Ursprüngliche Nachricht-----
> Von: "Philip Balister" <philip....@gmail.com>
> Gesendet: 23.09.08 15:09:24
> An: beagl...@googlegroups.com
> Betreff: [beagleboard] Re: GPIO - how to ?


>
> On Tue, Sep 23, 2008 at 8:51 AM, Arno Steffen <arno.s...@web.de> wrote:
> >
> > How can I access GPIO pins from userspace, so read or write?
> > Is there already a kernel driver for Omap35xx and how to work with that?
> > Help is very much welcome!
>
> Take a look at:
>
> http://source.mvista.com/git/gitweb.cgi?p=linux-omap-2.6.git;a=blob;f=Documentation/gpio.txt;h=18022e249c53dc1ad991d74d160551fa32f32070;hb=HEAD
>
> Philip

________________________________________________________________________
"50 erste Dates" mit Adam Sandler u. Drew Barrymore kostenlos anschauen!
Exklusiv für alle WEB.DE Nutzer. http://www.blockbuster.web.de

Arno Steffen

unread,
Sep 24, 2008, 3:43:03 AM9/24/08
to beagl...@googlegroups.com
> -----Ursprüngliche Nachricht-----
> Von: "Bill Gatliff" <bg...@billgatliff.com>
> Gesendet: 23.09.08 17:22:44

> An: beagl...@googlegroups.com
> Betreff: [beagleboard] Re: GPIO - how to ?


>

Can you explain handling that more in detail?
What exactly is the gpiolib? In my kernel source I found
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/gpio-switch.c
arch/arm/plat-omap/gpio-switch.o
but for some reasons I can't work with that - or don't know how.

In my Kernel config I did:
CONFIG_GENERIC_GPIO=y
CONFIG_OMAP_GPIO_SWITCH=y

But loading the kernel gives me neither a sys/class/gpio nor a /dev/gpio or something to work with from userspace.

_________________________________________________________________________
In 5 Schritten zur eigenen Homepage. Jetzt Domain sichern und gestalten!
Nur 3,99 EUR/Monat! http://www.maildomain.web.de/?mc=021114

Arno Steffen

unread,
Sep 24, 2008, 10:21:43 AM9/24/08
to beagl...@googlegroups.com
Did test this way. But couldn't change the GPIOs.

I write a 0x2 to GPIO.SYSCONFIG and read back 0, which seems to be ok.
But in GPIO.OE I read a 0xfffffff (all Input), and can't change that value.

I also tried to mmap the area where the MUX bits are. But get a message:
"Mapped failed".

Mpfhhhh.

> -----Ursprüngliche Nachricht-----
> Von: "John Beetem" <johnb...@yahoo.com>
> Gesendet: 23.09.08 17:17:16
> An: Beagle Board <beagl...@googlegroups.com>


> Betreff: [beagleboard] Re: GPIO - how to ?

> On the Ångström demo I've been able to use mmap() and /dev/mem to map
> OMAP peripheral memory into my user space application. This way I can
> access OMAP registers directly instead of having to go through device
> drivers. So far I've
> only accessed the GPIO registers so I could play with the user LEDs.
>

> The C code looks something like this:
>
> int fd = open("/dev/mem", O_RDWR); volatile ulong *A;
> if (fd < 0) {printf("Could not open file\n"); return;}
> A = (ulong*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE,
> MAP_SHARED, fd, 0x49050000);
> if (A == MAP_FAILED) {printf("Mapping failed\n"); close(fd);
> return;}
> A[0x603C / 4] |= 0x600000; // Turn on LEDs
>

_______________________________________________________________________
Jetzt neu! Schützen Sie Ihren PC mit McAfee und WEB.DE. 30 Tage
kostenlos testen. http://www.pc-sicherheit.web.de/startseite/?mc=022220

John Beetem

unread,
Sep 24, 2008, 12:42:20 PM9/24/08
to Beagle Board
I was able to mmap the System Control Module's PADCONFS area by
mapping the entire SCM register space at 0x48002000 with a size of
0x1000 (4KB).
mmap() restricts the size and alignment of memory blocks in an
implementation-specific way.
Trying to mmap just the PADCONFS area at 0x48002030 failed for me
since it wasn't aligned to a 4KB boundary.

Hope this helps.

Bill Gatliff

unread,
Sep 24, 2008, 12:54:14 PM9/24/08
to beagl...@googlegroups.com
John Beetem wrote:
> I was able to mmap the System Control Module's PADCONFS area by
> mapping the entire SCM register space at 0x48002000 with a size of
> 0x1000 (4KB).
> mmap() restricts the size and alignment of memory blocks in an
> implementation-specific way.
> Trying to mmap just the PADCONFS area at 0x48002030 failed for me
> since it wasn't aligned to a 4KB boundary.

Indeed. Your addresses and sizes must be 4K-aligned on ARM.

arno.s...@web.de

unread,
Sep 30, 2008, 6:37:34 AM9/30/08
to Beagle Board
Yes that works fine, thanks
Although there is sometime strong delays and artefacts accessing
GPIOs.
My program does via the mmap somewhat like

set padconfig = 0x00040004 //GPIO mode
set outputenable = 0
set dataout or set_bits or clear_bits ...

But it really works only the second time I call it. Somehow
strange ...
Any idea about that?


On 24 Sep., 18:42, John Beetem <johnbee...@yahoo.com> wrote:
> I was able to mmap the System Control Module's PADCONFS area by
> mapping the entire SCM register space at 0x48002000 with a size of
> 0x1000 (4KB).
> mmap() restricts the size and alignment of memory blocks in an
> implementation-specific way.
> Trying to mmap just the PADCONFS area at 0x48002030 failed for me
> since it wasn't aligned to a 4KB boundary.
>
> Hope this helps.
>
> On Sep 24, 7:21 am,ArnoSteffen <arno.stef...@web.de> wrote:
>
>
>
> > Did test this way. But couldn't change the GPIOs.
>
> > I write a 0x2 to GPIO.SYSCONFIG and read back 0, which seems to be ok.
> > But in GPIO.OE I read a 0xfffffff (all Input), and can't change that value.
>
> > I also tried to mmap the area where the MUX bits are. But get a message:
> > "Mapped failed".
>
> > Mpfhhhh.- Zitierten Text ausblenden -

John Beetem

unread,
Sep 30, 2008, 11:57:00 AM9/30/08
to Beagle Board
Sorry, I don't know why it wouldn't work the first time. My only
direct experience is playing with the user LEDs. Even then, when I
turn on the user LEDs one of them only stays on until Ångström blinks
it. Fortunately, that seems to be the only artifact.

As Bill mentioned above, you do have to consider that other processes
may be accessing these same registers. That creates all sorts of
nasty situations. For example, if process A updates a peripheral
register by doing a read-modify-write, there is a tiny chance that
process B may interrupt A's read-modify-write and do its own read-
modify-write. Then when control returns to process A it completes its
read-modify-write overwriting the effect of process B. This sort of
bug occurs very infrequenty and is extremely hard to reproduce. The
solution is to suspend interrupts during the read-modify-write --
perhaps ARM has an instruction that does this atomically.

I totally doubt that's causing your problem, since it is a very low
probablility of occurrence.

Another common issue with device registers is making sure they're in
an uncacheable memory. I would hope that mmap() would take care of
this automatically. The kernel should know what can be cached and
what cannot, i.e., normal program instructions and data can be cached,
but the peripheral register area cannot be. This is actually
consistent with your symptoms, since the first writes may only update
data cache and the OMAP registers only get updated when the cache
flushes. I would be surprised if this is what's happening since the
kernel should set up the memory map properly, but it might be worth
checking the memory management tables if it's not too hard just to
rule it out definitively.

Using a well-written device driver should avoid these problems. In
general, if you're writing an application that will run under an OS
with other applications that you didn't write, you're best off using a
device driver so the OS can manage shared resources. If you're
writing what is essentially a stand-alone application and using Linux
as a temporary development tool, direct access to OMAP registers makes
the most sense

Another common consideration is the use of "volatile" in C programs.
Declaring a variable "volatile" tells the compiler that each use of
the variable in the program must result in an actual load or store
instruction, and that those loads and stores must use the exact
declared size of the variable. Otherwise the compiler is free to
optimize access to the variable, e.g., put it in a register and avoid
what the compiler considers to be unnecessary loads and stores.
"volatile" tells the compiler that the variable could change value at
any time and that all stores are signficant. Variables shared between
processes should usually be declared "volatile".

Sometimes the compiler will do the right thing even if you don't use
"volatile". But then when you change the compiler's optimization
options or update to a new compiler release, suddenly code that you
haven't looked at in years stops working. What fun!

John

Bill Gatliff

unread,
Sep 30, 2008, 12:13:45 PM9/30/08
to beagl...@googlegroups.com
John Beetem wrote:

> Another common issue with device registers is making sure they're in
> an uncacheable memory. I would hope that mmap() would take care of
> this automatically.

Funny you should mention that. AT91 has had problems with that in the past, I
wonder if OMAP does too?

arno.s...@web.de

unread,
Oct 1, 2008, 4:38:49 AM10/1/08
to Beagle Board
Thanks for your details. I am working on a driver now.
Than I can use the
gpio_request(), gpio_direction_output(), gpio_set_value()
functions.
Unfortunatly the gpio_request doesn't set the padmux to mode4 (GPIO)
as I expected.
Even there seems to be no support in the recent kernel (mux.h) for
Omap35xx.
So my beginner question is:
what is the best way to address (read/write) registers of Omap (like
padconf) from kernel-space? I've seen that the max frequency of
toggling a GPIO pin via gpio_set_value() isn't quite exciting fast. So
guess I have to implent parts not via this kernel function but via
direct register access, maybe even in Assembler.

Syed Mohammed, Khasim

unread,
Oct 1, 2008, 4:47:24 AM10/1/08
to beagl...@googlegroups.com
For now the best way is to use the kernel APIs to configure the PAD
config registers, I don't think we support dynamic configuration of
these pins, but you could do this in board file, the current Latest
GIT kernel does support these APIs, as you mentioned you have to
update the mux.h accordingly.

But, I think we should also support dynamic configuring of PAD registers

Regards,
Khasim

arno.s...@web.de

unread,
Oct 1, 2008, 9:20:33 AM10/1/08
to Beagle Board
For me as a beginner "git" is a too big issue.
You are writing : use the kernel API to set - but that's exactly the
question - how does it works?
A very simple example would be fine.
For me even a static setting is fine. In board.h I couldn't find
somewhat like a default Padconf mapping,
at least I can't find that.
But nevertheless the question - how to access Padconf and other
registers
as simple a simple memory access from a driver - so from inside the
kernel space. A simple
memcopy(0x48xxxxxx,) does not work.


On 1 Okt., 10:47, "Syed Mohammed, Khasim " <sm.kha...@gmail.com>
wrote:
> For now the best way is to use the kernel APIs to configure the PAD
> config registers, I don't think we support dynamic configuration of
> these pins, but you could do this in board file, the current Latest
> GIT kernel does support these APIs, as you mentioned you have to
> update the mux.h accordingly.
>
> But, I think we should also support dynamic configuring of PAD registers
>
> Regards,
> Khasim-

arno.s...@web.de

unread,
Oct 1, 2008, 10:13:35 AM10/1/08
to Beagle Board
The same as for

unsigned char *padconfaddr99 = 0x48002114;
padconf_gpio = (IO_PAD_MUXMODE4 << IO_PAD_HIGH_SHIFT) +
IO_PAD_MUXMODE4;
*padconfaddr99 = padconf_gpio;

Unable to handle kernel paging request at virtual address 48002114

same with
writel(padconf_gpio, padconfaddr99);

I don't want to write to a virtual address, want to have the real
address.
Reply all
Reply to author
Forward
0 new messages