LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Embedded & Single-board computer (https://www.linuxquestions.org/questions/linux-embedded-and-single-board-computer-78/)
-   -   GPIO access from users pace? (https://www.linuxquestions.org/questions/linux-embedded-and-single-board-computer-78/gpio-access-from-users-pace-656817/)

ra2008 07-19-2008 06:46 AM

GPIO access from users pace?
 
Hi, is it possible to access ARM's GPIOs (EP93xx) runnning 2.6.21 Linux, from user space?
if yes how? what are the system call? any tutorials?
thanks

pinniped 07-19-2008 06:50 AM

You can always write a driver to be able to do it. The manufacturer of your board may already provide a reference driver.

raedbenz 07-19-2008 12:58 PM

Yes u can.
try to look for "Low level I/O API", like read(), write(), also mmap()..

estabroo 07-19-2008 10:49 PM

mmap is the answer you are looking for, if you look at the ep9301 user guide (or one more appropriate to the chip you are using) you can see where it maps pins to memory.

- snippet of code for ep9302 memory mapping of gpio pins -
Code:

#define GPIO_BASE 0x80840000
/* GPIO memory mapped registers */

volatile unsigned int *PBDR;  /* for unit select, lowest 3 bits */
volatile unsigned int *PBDDR;
volatile unsigned int *PEDR;
volatile unsigned int *PEDDR;

int memory_map_open(unsigned char **gpio) {
  int fd;

  fd = open("/dev/mem", O_RDWR);
  if (fd < 0) {
    perror("Failed to open /dev/mem");
    return fd;
  }
  *gpio = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);

  PBDR = (unsigned int *)(*gpio + 0x04);
  PBDDR = (unsigned int *)(*gpio + 0x14);
  PEDR = (unsigned int *)(*gpio + 0x20);
  PEDDR = (unsigned int *)(*gpio + 0x24);

  return fd;
}

Then where you want to use the data registers that control the pins just assign the appropriate value to them

*PBDDR = 0xff; /* data direction register, 0xff makes all the pins outputs iirc, been a while since I've read the user guide */
*PBDR = 0x01; /* drive the lowest pin that it controls high */

ra2008 07-20-2008 02:09 PM

Hi estabroo
thanks for the helpful reply,
i have tested the code (after rewriting it by adding main function,etc.. )and i get this error on Olimex CS-e9302 board
Code:

Segmentation fault
any hints?

jiml8 07-20-2008 03:08 PM

Segmentation fault means a wild pointer.

estabroo 07-20-2008 05:08 PM

Can you run it in a debugger and find out where the segfault occurred? If not you might have to put in fprintf to stderr messages to narrow it down, does it have a console (serial, vga, ...)? You should also check the value you get back from mmap to make sure it didn't fail. Can you post your code?

ra2008 07-21-2008 03:02 AM

Quote:

Originally Posted by estabroo (Post 3220937)
does it have a console (serial, vga, ...)?

Hi,
if u mean someting like hyperterminal, then yes i am using cutecom. here is the code:

Code:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define GPIO_BASE 0x80840000
/* GPIO memory mapped registers */
volatile unsigned int *PEDR;
volatile unsigned int *PEDDR;
       
int main (void)
        {       
          //long delay=128000, delay2=100;
          unsigned char **gpio;
          int fd;
          fd = open("/dev/mem", O_RDWR);
          if (fd < 0)
                  {
          perror("Failed to open /dev/mem");
          return fd;
                  }
          *gpio = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);

          PEDR = (unsigned int *)(*gpio + 0x20);
          PEDDR = (unsigned int *)(*gpio + 0x24);
       
        *PEDDR = 0xff;//set output
        *PEDR = 0x02;// turn ON Red LED (port E1)
               
          return 0;
        }


estabroo 07-21-2008 12:08 PM

Okay the problem is your declaration of gpio. It was ** in the function I posted because it was being passed in by reference, since you have it in the main program you should do this instead
Code:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define GPIO_BASE 0x80840000
/* GPIO memory mapped registers */
volatile unsigned int *PEDR;
volatile unsigned int *PEDDR;
       
int main (void)
        {       
          //long delay=128000, delay2=100;
          unsigned char *gpio;
          int fd;
          fd = open("/dev/mem", O_RDWR);
          if (fd < 0)
                  {
          perror("Failed to open /dev/mem");
          return fd;
                  }
          gpio = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);

          PEDR = (unsigned int *)(gpio + 0x20);
          PEDDR = (unsigned int *)(gpio + 0x24);
       
        *PEDDR = 0xff;//set output
        *PEDR = 0x02;// turn ON Red LED (port E1)
               
          return 0;
        }


ra2008 07-21-2008 01:31 PM

thanks very much,,it works now

maicho 08-01-2008 03:07 PM

interruption
 
Hi, Your code was very very usefull to me, but I would like know how I can set an interruption in GIOPORT, for example:

if the pin x from portA or B detect a low level (0) then execute a function (eg, increase a counter)

thanks

estabroo 08-01-2008 05:29 PM

I would imagine you'd need to write a kernel module that setup an irq handler function and requested interrupts generated by that gpio be sent to it. Take a look at the set_irq_type and request_irq functions in the kernel.

raedbenz 08-01-2008 09:37 PM

Hi,
dealing with interrupts can be done only in Kernel space not user space.
just use as estabroo said, "request_irq" to register ur irq number and device name, etc..
then write the handler (ISR).. at the exit of the module just free the irq.
http://www.xml.com/ldd/chapter/book/ch09.html
cheers

maicho 08-05-2008 08:48 AM

interruption
 
Thanks estabroo and raedbenz. I will tray write a module in kernel that let me manage an IO interruption. When I finish I will write here the code.


All times are GMT -5. The time now is 05:46 PM.