Difference between revisions of "GPIO Driver"

From ArmadeusWiki
Jump to: navigation, search
 
(38 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
{{Warning| This article describe the method to use gpio with armadeus '''version < 4.0'''. To use gpio on armadeus '''version 4.0''' or more see [[GPIOlib]]}}
 +
 +
 
On this page, you will find all the informations needed to use the Armadeus GPIO driver.
 
On this page, you will find all the informations needed to use the Armadeus GPIO driver.
  
 +
==Installation==
 
==Compilation==
 
==Compilation==
The first thing you have to do is to compile the driver. The only way to do that for the moment is to compile it as a module:
+
Since Armadeus-3.0 release, gpio driver is compiled and installed by default in rootfs. See [[Talk:GPIO_Driver]] to know how.
[host]$ cd armadeus/
+
[host]$ make linux-menuconfig
+
Then go in menu: '''Device Drivers  ---> Armadeus specific drivers''' and choose '''<M> Armadeus GPIO driver''' + '''<M> Armadeus Parallel Port driver''':<br>
+
[[Image:linux_config_gpio.png]]<br>
+
Exit and save your kernel configuration, then compile it:
+
[host]$ make linux
+
  
When compiled, you will obtain 2 modules in ''armadeus/target/linux/modules/gpio/'':
+
You have 2 modules:
* gpio.ko: this is the main driver. It should be loaded first and will allow you to easily control gpio pin from user space,
+
* gpio: this is the main driver. It should be loaded first and will allow you to easily control GPIO pins from user space,
* ppdev.ko: this is an extension driver to add PPDEV emulation to gpio.ko. This way you will be able to emulate a standard parallel port on one GPIO port (to connect a textual LCD, for example).
+
* ppdev: this is an extension driver to add PPDEV emulation to gpio.ko. This way you will be able to emulate a standard parallel port on one GPIO port (to connect a textual LCD, for example).
 +
{{Note|The parallel port driver (ppdev) will only work on [[APF9328]] based systems for now !}}
  
==Installation==
+
===Loading driver===
You have to:
+
<pre class="apf">
* reflash your rootfs or copy these modules on your target in ''/lib/modules/2.6.18.1/extra/gpio'' (don't forget modules.dep file),
+
# /usr/bin/loadgpio.sh
* copy loadgpio.sh script on your rootfs in /etc/
+
</pre>
After that you can launch:
+
# sh /etc/loadgpio.sh
+
 
or look inside this script if you want to manually enter the module parameters:
 
or look inside this script if you want to manually enter the module parameters:
 +
<pre class="apf">
 
  # modprobe gpio portB_init=0,0,0x00FFFF00,0,0,0,0,0,0x0FF00000,0,0,0,0,0,0,0x0FF00000
 
  # modprobe gpio portB_init=0,0,0x00FFFF00,0,0,0,0,0,0x0FF00000,0,0,0,0,0,0,0x0FF00000
 +
</pre>
 
gpio module parameters are values for PORTA, PORTB, PORTC, PORTD configuration registers in following order:
 
gpio module parameters are values for PORTA, PORTB, PORTC, PORTD configuration registers in following order:
DDIR, OCR1, OCR2, ICONFA1, ICONFA2, ICONFB1, ICONFB2, DR, GIUS, SSR, ICR1, ICR2, IMR, GPR, SWR, PUEN,
+
DDIR, OCR1, OCR2, ICONFA1, ICONFA2, ICONFB1, ICONFB2, DR, GIUS, SSR, ICR1, ICR2, IMR, GPR, SWR, PUEN,<br>
 +
{{Warning|If you don't know what these registers means, load the module without parameters !!}}
  
 
== Driver usage ==
 
== Driver usage ==
  
=== Directly with shell commands (through /proc filesystem) ===
+
=== As_devices ===
  
GPIO driver is usable through /proc interface:
+
GPIO can be use with library [[AsDevices]].
* use ''/proc/drivers/gpio/portXdir'' to read (with ''cat'') or set (with ''echo'') pin direction (where X is your port name: A, B, C or D)
+
 
* then use ''/proc/drivers/gpio/portX'' to read (with ''cat'') or write (with ''echo'') pin status
+
=== Directly with shell commands (through /proc & /dev filesystem) ===
 +
 
 +
GPIO driver is usable through its /proc interface:
 +
# use ''/proc/drivers/gpio/portXmode'' to configure a pin as a gpio (with ''echo'') and  where X is your port name: A, B, C or D (E,F for apf27)
 +
# use ''/proc/drivers/gpio/portXdir'' to read (with ''cat'') or set (with ''echo'') pin direction (where X is your port name)
 +
# then use ''/proc/drivers/gpio/portX'' to read (with ''cat'') or write (with ''echo'') pin status
 +
# ''/proc/drivers/gpio/portXirq'': to configure GPIO as an interrupt (blocking read); 0-> no interrupt, 1-> rising edge, 2-> falling edge, 3-> both edges
 +
# ''/proc/drivers/gpio/portXpullup'': (de)activate i.MX internal pull-up for that GPIO
 +
 
 +
====Examples====
 +
* Configure IO-Pin 31 of port A (LCD_OE_ACD on the APF27) as GPIO (not reversible):
 +
<pre class="apf">
 +
# echo -n 10000000000000000000000000000000 > /proc/driver/gpio/portAmode
 +
</pre>
  
====Examples:====
 
 
* See which IO-Pins of PortD are configured as inputs, and which one are outputs ('1' = output, '0' = input):
 
* See which IO-Pins of PortD are configured as inputs, and which one are outputs ('1' = output, '0' = input):
 +
<pre class="apf">
 
  # cat /proc/driver/gpio/portDdir
 
  # cat /proc/driver/gpio/portDdir
  01101100111100000110110011110000
+
  01101100111100000110110011110000       pins order: [31...0]
 
  #
 
  #
 +
</pre>
  
* Configure the IO-Pins 30, 28, 23, 22 and 21 of PortB as outputs, all others are inputs:
+
* Configure the IO-Pins 30, 28, 23, 22 and 21 of PortB as outputs ('1'), all others as inputs ('0'):
  # echo 01010000111000000000000000000000 > /proc/driver/gpio/portBdir
+
<pre class="apf">
 +
  # echo -n 01010000111000000000000000000000 > /proc/driver/gpio/portBdir
 +
</pre>
  
 
* Read the status/values of the IOs of PortB:
 
* Read the status/values of the IOs of PortB:
 +
<pre class="apf">
 
  # cat /proc/driver/gpio/portB
 
  # cat /proc/driver/gpio/portB
 
  00000000000011111111000000000000
 
  00000000000011111111000000000000
 
  #
 
  #
 +
</pre>
  
* Set bits 30, 28 and 23 of PortB to '1', all other outputs to '0':
+
* Set bits 30, 28 and 23 of PortB to '1', all other outputs to '0': '''<-- DEPRECATED, use /dev/gpio/ instead !'''
  # echo 01010000100000000000000000000000 > /proc/driver/gpio/portB
+
<pre class="apf">
 +
  # echo -n 01010000100000000000000000000000 > /proc/driver/gpio/portB
 +
</pre>
  
=== Directly with C program ( /proc filesystem) ===
+
* Blinks the LED on [[APF9328DevFull]] (pin 31 of portD):
 +
<pre class="apf">
 +
# cat /proc/driver/gpio/portDmode | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDmode
 +
# cat /proc/driver/gpio/portDdir | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDdir
 +
# echo -ne "\x00" > /dev/gpio/PD31
 +
# echo -ne "\x01" > /dev/gpio/PD31
 +
</pre>
 +
 
 +
* Blinks the LED on [[APF27Dev]] (pin 14 of portF):
 +
<pre class="apf">
 +
# cat /proc/driver/gpio/portFmode | sed "s/[0-1]\([0-1]\{14\}\)$/1\1/" > /proc/driver/gpio/portFmode
 +
# cat /proc/driver/gpio/portFdir | sed "s/[0-1]\([0-1]\{14\}\)$/1\1/" > /proc/driver/gpio/portFdir
 +
# echo -ne "\x01" > /dev/gpio/PF14
 +
# echo -ne "\x00" > /dev/gpio/PF14
 +
</pre>
 +
 
 +
* Sets only bit 5 of portADir to 1:
 +
<pre class="apf">
 +
# cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''1'''\1/" > /proc/driver/gpio/portAdir
 +
</pre>
 +
 
 +
* Sets only bit 5 of portADir to 0:
 +
<pre class="apf">
 +
# cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''0'''\1/" > /proc/driver/gpio/portAdir
 +
</pre>
 +
 
 +
* You can put it in a shell function:
 +
<pre class="apf">
 +
setbit()
 +
{
 +
    PORT=$1
 +
    NB=$2
 +
    VAL=$3
 +
    cat $PORT | sed "s/[0-1]\([0-1]\{$NB\}\)$/$VAL\1/" > $PORT
 +
}
 +
 
 +
# setbit /proc/driver/gpio/portAdir 5 0
 +
</pre>
 +
 
 +
* Blocking read on the PortD pin 0:
 +
<pre class="apf">
 +
# cat /dev/gpio/PD0 | less
 +
</pre>
 +
 
 +
* A test script is available in ''target/test/'' : [http://armadeus.git.sourceforge.net/git/gitweb.cgi?p=armadeus/armadeus;a=blob;f=target/test/test_gpio.sh;h=e2e54e855aeb25b0f0cbae5915930e9f904861dc;hb=HEAD test_gpio.sh]
 +
 
 +
=== Directly from a C program with IOCTLs ===
 +
 
 +
There is another way to drive GPIO module: with IOCTLs on the right device node (full port).<br>
 +
ioctl() function is using flags to say what must be done:
 +
* GPIORDDIRECTION for reading direction settings of the corresponding port
 +
* GPIOWRDIRECTION for writing direction settings
 +
* GPIORDDATA for reading data on the corresponding port
 +
* GPIOWRDATA for writing data
 +
* Etc...
 +
 
 +
There is a small C example in ''target/demos/gpio/'' that will give you more explanation: [http://armadeus.git.sourceforge.net/git/gitweb.cgi?p=armadeus/armadeus;a=blob_plain;f=target/demos/gpio/blink_led.c;hb=HEAD blink_led.c]
 +
 
 +
=== Directly with C program: /proc filesystem===
 +
{{Note|For performance please use IOCTL instead (see above)}}
  
 
After inserting the GPIO module, /proc entries are created in the
 
After inserting the GPIO module, /proc entries are created in the
Line 61: Line 140:
  
 
A little piece of code is the best way to understand quickly:
 
A little piece of code is the best way to understand quickly:
 
+
<source lang="C">
 
     int i;
 
     int i;
 
     unsigned char dummy;
 
     unsigned char dummy;
     FILE *GPIO,*GPIODIR;
+
     FILE *GPIO,*GPIODIR, *GPIOMODE;
 
     char buffer[32];
 
     char buffer[32];
     char * bufferDir="00000000011111111000000000000000";
+
    char * bufferMode="00000000011111111000000000000000";
     char * buffer1= "00000000000000011000000000000000";
+
     char * bufferDir= "00000000011111111000000000000000";
     char * buffer2=     "00000000000001100000000000000000";
+
     char * buffer1=   "00000000000000011000000000000000";
     char * buffer3=     "00000000000110000000000000000000";
+
     char * buffer2=   "00000000000001100000000000000000";
     char * buffer4=     "00000000011000000000000000000000";
+
     char * buffer3=   "00000000000110000000000000000000";
 +
     char * buffer4=   "00000000011000000000000000000000";
 
   
 
   
 +
    GPIOMODE = fopen("/proc/driver/gpio/portDmode","w");
 +
    setvbuf(GPIOMODE,buffer,_IONBF,32);
 +
    fwrite(bufferMode, sizeof(char), strlen(bufferMode), GPIOMODE);
 +
    fclose(GPIOMODE);
 
     GPIODIR = fopen("/proc/driver/gpio/portDdir","w");
 
     GPIODIR = fopen("/proc/driver/gpio/portDdir","w");
 
     setvbuf(GPIODIR,buffer,_IONBF,32);
 
     setvbuf(GPIODIR,buffer,_IONBF,32);
Line 90: Line 174:
 
     fclose(GPIO);
 
     fclose(GPIO);
 
     return (0);
 
     return (0);
 
+
</source>
=== Directly from a C program with IOCTLs ===
+
 
+
There is another way to drive GPIO module: with IOCTLs on the right device node.
+
ioctl() function is using flags to say what it must be done (read and
+
write):
+
* GPIORDDIRECTION for reading direction of the concerned port
+
* GPIOWRDIRECTION for writing direction of the concerned port
+
* GPIORDDATA for reading data of the concerned port
+
* GPIOWRDATA for writing data of the concerned port
+
 
+
An example of code will give more explanation:
+
 
+
  int fd;
+
  int i;
+
  int iomask,result;   
+
  unsigned char dev_buffer[BUF_SIZE+1];
+
+
  if ((fd = open("/dev/gpio/portD", O_RDWR))<0) {
+
    printf("Open error on /dev/gpio/portD\n");
+
    exit(0);
+
  }
+
  printf("Opened on /dev/gpio/portD\n");
+
  iomask=0xFFFFFF00;
+
  ioctl(fd,GPIOWRDIRECTION,&iomask);
+
  iomask=0x003F0000;
+
  for (i=0;i<2;i++) {
+
    printf("Led ON\n");       
+
    iomask=0x007F8000;
+
    ioctl(fd,GPIOWRDATA,&iomask);
+
    sleep(1);
+
    ioctl(fd,GPIORDDATA,&iomask);
+
    printf("read /dev/gpio/portD 0x%x\n",iomask);
+
    printf("Led OFF\n");
+
    iomask=0x00000000;
+
    ioctl(fd,GPIOWRDATA,&iomask);
+
    sleep(1);
+
  }
+
  close(fd);
+
  exit(0);
+
 
+
Of course you'll need to declare in the include part, the following:
+
* sys/ioctl.h
+
* linux/ppdev.h
+
 
+
and define pragmas such as:
+
* GPIORDDIRECTION _IOR(PP_IOCTL, 0xF0, int) 
+
* GPIOWRDIRECTION _IOW(PP_IOCTL, 0xF1, int)
+
* GPIORDDATA      _IOR(PP_IOCTL, 0xF2, int)
+
* GPIOWRDATA      _IOW(PP_IOCTL, 0xF3, int)
+
  
 
== Links ==
 
== Links ==
Line 145: Line 180:
 
* http://people.redhat.com/twaugh/parport/html/ppdev.html
 
* http://people.redhat.com/twaugh/parport/html/ppdev.html
 
* http://www.krugle.com/examples/p-yckfcEKjgfqvsNcB/drivertest.c
 
* http://www.krugle.com/examples/p-yckfcEKjgfqvsNcB/drivertest.c
 +
* [http://www.ipbx.ru/rm9200/gpio-RM9200.tar.gz AT91 way of doing it]
 +
* [http://www.avr32linux.org/twiki/bin/view/Main/GpioDevInterface AVR32 way of doing it]
 +
* [http://www.jibee.com/view.pl/OpenRobotik/GpioRoutingDriver JiBee's way of doing it]
  
 
[[Category:UserInput]]
 
[[Category:UserInput]]
 +
[[Category:Linux drivers]]

Latest revision as of 16:41, 12 December 2011

Warning Warning: This article describe the method to use gpio with armadeus version < 4.0. To use gpio on armadeus version 4.0 or more see GPIOlib


On this page, you will find all the informations needed to use the Armadeus GPIO driver.

Installation

Compilation

Since Armadeus-3.0 release, gpio driver is compiled and installed by default in rootfs. See Talk:GPIO_Driver to know how.

You have 2 modules:

  • gpio: this is the main driver. It should be loaded first and will allow you to easily control GPIO pins from user space,
  • ppdev: this is an extension driver to add PPDEV emulation to gpio.ko. This way you will be able to emulate a standard parallel port on one GPIO port (to connect a textual LCD, for example).
Note Note: The parallel port driver (ppdev) will only work on APF9328 based systems for now !


Loading driver

 # /usr/bin/loadgpio.sh

or look inside this script if you want to manually enter the module parameters:

 # modprobe gpio portB_init=0,0,0x00FFFF00,0,0,0,0,0,0x0FF00000,0,0,0,0,0,0,0x0FF00000

gpio module parameters are values for PORTA, PORTB, PORTC, PORTD configuration registers in following order: DDIR, OCR1, OCR2, ICONFA1, ICONFA2, ICONFB1, ICONFB2, DR, GIUS, SSR, ICR1, ICR2, IMR, GPR, SWR, PUEN,

Warning Warning: If you don't know what these registers means, load the module without parameters !!


Driver usage

As_devices

GPIO can be use with library AsDevices.

Directly with shell commands (through /proc & /dev filesystem)

GPIO driver is usable through its /proc interface:

  1. use /proc/drivers/gpio/portXmode to configure a pin as a gpio (with echo) and where X is your port name: A, B, C or D (E,F for apf27)
  2. use /proc/drivers/gpio/portXdir to read (with cat) or set (with echo) pin direction (where X is your port name)
  3. then use /proc/drivers/gpio/portX to read (with cat) or write (with echo) pin status
  4. /proc/drivers/gpio/portXirq: to configure GPIO as an interrupt (blocking read); 0-> no interrupt, 1-> rising edge, 2-> falling edge, 3-> both edges
  5. /proc/drivers/gpio/portXpullup: (de)activate i.MX internal pull-up for that GPIO

Examples

  • Configure IO-Pin 31 of port A (LCD_OE_ACD on the APF27) as GPIO (not reversible):
 # echo -n 10000000000000000000000000000000 > /proc/driver/gpio/portAmode
  • See which IO-Pins of PortD are configured as inputs, and which one are outputs ('1' = output, '0' = input):
 # cat /proc/driver/gpio/portDdir
 01101100111100000110110011110000       pins order: [31...0]
 #
  • Configure the IO-Pins 30, 28, 23, 22 and 21 of PortB as outputs ('1'), all others as inputs ('0'):
 # echo -n 01010000111000000000000000000000 > /proc/driver/gpio/portBdir
  • Read the status/values of the IOs of PortB:
 # cat /proc/driver/gpio/portB
 00000000000011111111000000000000
 #
  • Set bits 30, 28 and 23 of PortB to '1', all other outputs to '0': <-- DEPRECATED, use /dev/gpio/ instead !
 # echo -n 01010000100000000000000000000000 > /proc/driver/gpio/portB
 # cat /proc/driver/gpio/portDmode | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDmode
 # cat /proc/driver/gpio/portDdir | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDdir
 # echo -ne "\x00" > /dev/gpio/PD31
 # echo -ne "\x01" > /dev/gpio/PD31
  • Blinks the LED on APF27Dev (pin 14 of portF):
 # cat /proc/driver/gpio/portFmode | sed "s/[0-1]\([0-1]\{14\}\)$/1\1/" > /proc/driver/gpio/portFmode
 # cat /proc/driver/gpio/portFdir | sed "s/[0-1]\([0-1]\{14\}\)$/1\1/" > /proc/driver/gpio/portFdir
 # echo -ne "\x01" > /dev/gpio/PF14
 # echo -ne "\x00" > /dev/gpio/PF14
  • Sets only bit 5 of portADir to 1:
 # cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''1'''\1/" > /proc/driver/gpio/portAdir
  • Sets only bit 5 of portADir to 0:
 # cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''0'''\1/" > /proc/driver/gpio/portAdir
  • You can put it in a shell function:
 setbit()
 {
     PORT=$1
     NB=$2
     VAL=$3
     cat $PORT | sed "s/[0-1]\([0-1]\{$NB\}\)$/$VAL\1/" > $PORT
 }

 # setbit /proc/driver/gpio/portAdir 5 0
  • Blocking read on the PortD pin 0:
 # cat /dev/gpio/PD0 | less

Directly from a C program with IOCTLs

There is another way to drive GPIO module: with IOCTLs on the right device node (full port).
ioctl() function is using flags to say what must be done:

  • GPIORDDIRECTION for reading direction settings of the corresponding port
  • GPIOWRDIRECTION for writing direction settings
  • GPIORDDATA for reading data on the corresponding port
  • GPIOWRDATA for writing data
  • Etc...

There is a small C example in target/demos/gpio/ that will give you more explanation: blink_led.c

Directly with C program: /proc filesystem

Note Note: For performance please use IOCTL instead (see above)


After inserting the GPIO module, /proc entries are created in the filesystem, and so it's possible to directly use some Linux standard functions inside a C program, such as:

  • fopen
  • fwrite
  • fread
  • fclose

A little piece of code is the best way to understand quickly:

    int i;
    unsigned char dummy;
    FILE *GPIO,*GPIODIR, *GPIOMODE;
    char buffer[32];
    char * bufferMode="00000000011111111000000000000000";
    char * bufferDir= "00000000011111111000000000000000";
    char * buffer1=   "00000000000000011000000000000000";
    char * buffer2=   "00000000000001100000000000000000";
    char * buffer3=   "00000000000110000000000000000000";
    char * buffer4=   "00000000011000000000000000000000";
 
    GPIOMODE = fopen("/proc/driver/gpio/portDmode","w");
    setvbuf(GPIOMODE,buffer,_IONBF,32);
    fwrite(bufferMode, sizeof(char), strlen(bufferMode), GPIOMODE);
    fclose(GPIOMODE);
    GPIODIR = fopen("/proc/driver/gpio/portDdir","w");
    setvbuf(GPIODIR,buffer,_IONBF,32);
    fwrite(bufferDir, sizeof(char), strlen(bufferDir), GPIODIR);
    fclose(GPIODIR);
    GPIO = fopen("/proc/driver/gpio/portD","w");
    setvbuf(GPIO,buffer,_IONBF,32);
    while(1) {            
        fwrite(buffer1, sizeof(char), strlen(buffer1), GPIO);
        sleep(1);
        fwrite(buffer2, sizeof(char), strlen(buffer2), GPIO);
        sleep(1);
        fwrite(buffer3, sizeof(char), strlen(buffer3), GPIO);
        sleep(1);
        fwrite(buffer4, sizeof(char), strlen(buffer4), GPIO);
        sleep(1);
    }
    fclose(GPIO);
    return (0);

Links