linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* Still struggling with Xilinx GPIO...
@ 2008-05-26 15:43 Guillaume Dargaud
  2008-05-27 16:42 ` John Bonesio
  0 siblings, 1 reply; 4+ messages in thread
From: Guillaume Dargaud @ 2008-05-26 15:43 UTC (permalink / raw)
  To: linuxppc-dev

I still haven't managed to figure out how to use the Xilinx GPIO from 
usermode.

The program gpio_test found at 
http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/archive/2004/05/msg00004.html 
and slightly modified as this:

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#include <linux/types.h>
#include <sys/ioctl.h>

#include <xgpio_ioctl.h>

#define GPIO_DEV "/dev/xgpio"

void usage(int argc, char *argv[])
{
        fprintf(stderr,"usage: %s hexval\n\n", argv[0]);
        fprintf(stderr,"\n");
        fprintf(stderr,"Puts the input hexval onto the LEDs, and\n");
        fprintf(stderr,"displays the current value on the DIP switches\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"try  gpio_test FC\n\n");

}

void dump_dipsw(int val)
{
        int i;
        val = (val & 0x000000FF);

        printf("DIP SW: ");
        for(i=0;i<8;i++)
        {
                printf("%i",val & 0x01);
                val >>= 1;
        }
        printf("\n");
}

/* Turn 4 LSB of X into 8 bit LED segment code */
unsigned char nyb_hex2led(int x)
{
        unsigned char led_tab[] = {
                0xFC, 0x60, 0xDA, 0xF2,
                0x66, 0xB6, 0xBE, 0xE0,
                0xFE, 0xF6, 0xEE, 0x3E,
                0x9C, 0x7A, 0x9E, 0x8E};

        return led_tab[x & 0xF];
}

/* Turn 8 LSB of x into 2 times 8 bit LED segment codes */
unsigned short hex2led(int x)
{
        return (nyb_hex2led(x & 0xF) << 8) | (nyb_hex2led((x >> 4) & 0xF));
}

int main(int argc, char *argv[])
{
        /* Open the device */
        int fd = open(GPIO_DEV, O_RDWR);

        struct xgpio_ioctl_data gpio_ioctl;
        // struct ibm_gpio_ioctl_data gpio_ioctl;
//      int     result;
//      int command;

        if(fd==-1) {
                fprintf(stderr,"Unable to open %s\n", GPIO_DEV);
                return -1;
        }

/*
        if(argc!=2)
        {
                usage();
                exit(1);
        }
*/
        gpio_ioctl.chan=0;

        /* Set the tristates */
        gpio_ioctl.mask=0x000000FF;
        ioctl(fd, XGPIO_TRISTATE,(void *)&gpio_ioctl);

        /* Get output data from command line if provided */

        if(argc==2)
                sscanf(argv[1],"%x",&(gpio_ioctl.data));
        else
                gpio_ioctl.data=time(NULL);

        /* Convert binary (16 LSB) into LED segment codes and shift into
           position on gpio */
        gpio_ioctl.data=hex2led(gpio_ioctl.data & 0xFF)<<8;

        ioctl(fd, XGPIO_OUT,(void *)&gpio_ioctl);

        /* Read some data */
        ioctl(fd, XGPIO_IN,(void *)&gpio_ioctl);

        dump_dipsw(gpio_ioctl.data);

        return 0;
}


...crashes in flames when run:

# gpio_test FC
[ 1366.864955] Oops: kernel access of bad area, sig: 11 [#5]
[ 1366.867560] NIP: c0108d50 LR: c00e68c4 CTR: 00000000
[ 1366.867560] REGS: c752fde0 TRAP: 0300   Tainted: G      D   (2.6.25-rc9)
[ 1366.867560] MSR: 00029030 <EE,ME,IR,DR>  CR: 93000033  XER: e000007f
[ 1366.867560] DEAR: c8fffffc, ESR: 00000000
[ 1366.867560] TASK = c7c37030[202] 'gpio_test' THREAD: c752e000
[ 1366.867560] GPR00: 00000000 c752fe90 c7c37030 c8fffffc 00000056 0000000c 
c752feb0 00000000
[ 1366.867560] GPR08: 00000000 11111111 ffffffe7 c7c5866c 00000000 10018dec 
ffff8432 ffdf1d0f
[ 1366.867560] GPR16: ffffffff ffffffff ffffffff ffffffff ffffffff 00000000 
100af244 10000858
[ 1366.867560] GPR24: 10000c00 00000002 10000478 800c5a03 c7c58000 c7c5866c 
800c5a03 c0200000
[ 1366.867560] NIP [c0108d50] XIo_In32+0x4/0xc
[ 1366.867560] LR [c00e68c4] XGpio_GetDataDirection+0x84/0xac
[ 1366.867560] Call Trace:
[ 1366.867560] [c752fe90] [c00e66a8] xgpio_getinst+0x48/0xb0 (unreliable)
[ 1366.867560] [c752fea0] [c00e6a8c] xgpio_ioctl+0x1a0/0x1fc
[ 1366.867560] [c752fed0] [c006740c] vfs_ioctl+0x6c/0x84
[ 1366.867560] [c752fee0] [c006778c] do_vfs_ioctl+0x368/0x39c
[ 1366.867560] [c752ff10] [c0067800] sys_ioctl+0x40/0x70
[ 1366.867560] [c752ff40] [c0002770] ret_from_syscall+0x0/0x3c
[ 1366.867560] Instruction dump:
[ 1366.867560] 7c634b78 7c031b78 4e800020 7c0006ac 88630000 5463063e 
4e800020 7c0006ac
[ 1366.867560] a0630000 5463043e 4e800020 7c0006ac <80630000> 4e800020 
7c0006ac 7c601e2c
Segmentation fault


# dmesg | grep gpio
[    0.120666] Registering device xilinx_gpio:0
[    0.121672] Registering device xilinx_gpio:1
[    0.122682] Registering device xilinx_gpio:2
[    0.292352] xgpio0 #0 at 0x81400000 mapped to 0xC9000000 device: 10,185 
using IRQ#7
[    0.293805] xgpio1 #1 at 0x81420000 mapped to 0xC9020000 device: 10,186 
using IRQ#6
[    0.295062] xgpio2 #2 at 0x81440000 mapped to 0xC9040000 device: 10,187 
using IRQ#5
[ 1366.867560] TASK = c7c37030[202] 'gpio_test' THREAD: c752e000
[ 1366.867560] [c752fe90] [c00e66a8] xgpio_getinst+0x48/0xb0 (unreliable)
[ 1366.867560] [c752fea0] [c00e6a8c] xgpio_ioctl+0x1a0/0x1fc



Another program using a different strategy also fails:

#include <fcntl.h>
#include <stdio.h>

int main (int argc, char *argv[]) {
 if (argc==2 || argc==3) {

  int fd = open(argv[1], O_RDWR | O_NDELAY );
  if (fd < 0) {
     fprintf(stderr, "GPIO OPEN FAIL\n");
     return -1;
  }

  unsigned long buff = 0;
  if (argc==2) {
   if (read(fd, &buff, 4) != 4)
      fprintf(stderr, "GPIO READ ERROR\n");
   else printf( "%x\n", buff);
  } else {
   buff=atoi(argv[2]);
   if (write(fd, &buff, 4) != 4)
      fprintf(stderr, "GPIO WRITE ERROR value %x\n", buff);
   else printf( "Written %x successfully\n", buff);
  }

  close(fd);
 } else {
  fprintf(stderr, "Usage: %s device [value] to read or write data to gpio 
device\n", argv[0]);
  return 1;
 }

 return 0;
}


# GpioReadWrite /dev/xgpio
GPIO READ ERROR
# GpioReadWrite /dev/xgpio 7
GPIO WRITE ERROR value 0

I wanted to avoid writing a kernel module, but apparently I've ran out of 
options...
-- 
Guillaume Dargaud
http://www.gdargaud.net/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Still struggling with Xilinx GPIO...
  2008-05-26 15:43 Still struggling with Xilinx GPIO Guillaume Dargaud
@ 2008-05-27 16:42 ` John Bonesio
  2008-05-28  9:51   ` Guillaume Dargaud
  0 siblings, 1 reply; 4+ messages in thread
From: John Bonesio @ 2008-05-27 16:42 UTC (permalink / raw)
  To: Guillaume Dargaud; +Cc: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 6898 bytes --]

Hi Guillaume,

Try using channel 1. It may be set up where the first channel is 1 and
not 0.

- John

On Mon, 2008-05-26 at 17:43 +0200, Guillaume Dargaud wrote:

> I still haven't managed to figure out how to use the Xilinx GPIO from 
> usermode.
> 
> The program gpio_test found at 
> http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/archive/2004/05/msg00004.html 
> and slightly modified as this:
> 
> #include <stdio.h>
> #include <fcntl.h>
> #include <errno.h>
> #include <string.h>
> 
> #include <linux/types.h>
> #include <sys/ioctl.h>
> 
> #include <xgpio_ioctl.h>
> 
> #define GPIO_DEV "/dev/xgpio"
> 
> void usage(int argc, char *argv[])
> {
>         fprintf(stderr,"usage: %s hexval\n\n", argv[0]);
>         fprintf(stderr,"\n");
>         fprintf(stderr,"Puts the input hexval onto the LEDs, and\n");
>         fprintf(stderr,"displays the current value on the DIP switches\n");
>         fprintf(stderr,"\n");
>         fprintf(stderr,"try  gpio_test FC\n\n");
> 
> }
> 
> void dump_dipsw(int val)
> {
>         int i;
>         val = (val & 0x000000FF);
> 
>         printf("DIP SW: ");
>         for(i=0;i<8;i++)
>         {
>                 printf("%i",val & 0x01);
>                 val >>= 1;
>         }
>         printf("\n");
> }
> 
> /* Turn 4 LSB of X into 8 bit LED segment code */
> unsigned char nyb_hex2led(int x)
> {
>         unsigned char led_tab[] = {
>                 0xFC, 0x60, 0xDA, 0xF2,
>                 0x66, 0xB6, 0xBE, 0xE0,
>                 0xFE, 0xF6, 0xEE, 0x3E,
>                 0x9C, 0x7A, 0x9E, 0x8E};
> 
>         return led_tab[x & 0xF];
> }
> 
> /* Turn 8 LSB of x into 2 times 8 bit LED segment codes */
> unsigned short hex2led(int x)
> {
>         return (nyb_hex2led(x & 0xF) << 8) | (nyb_hex2led((x >> 4) & 0xF));
> }
> 
> int main(int argc, char *argv[])
> {
>         /* Open the device */
>         int fd = open(GPIO_DEV, O_RDWR);
> 
>         struct xgpio_ioctl_data gpio_ioctl;
>         // struct ibm_gpio_ioctl_data gpio_ioctl;
> //      int     result;
> //      int command;
> 
>         if(fd==-1) {
>                 fprintf(stderr,"Unable to open %s\n", GPIO_DEV);
>                 return -1;
>         }
> 
> /*
>         if(argc!=2)
>         {
>                 usage();
>                 exit(1);
>         }
> */
>         gpio_ioctl.chan=0;
> 
>         /* Set the tristates */
>         gpio_ioctl.mask=0x000000FF;
>         ioctl(fd, XGPIO_TRISTATE,(void *)&gpio_ioctl);
> 
>         /* Get output data from command line if provided */
> 
>         if(argc==2)
>                 sscanf(argv[1],"%x",&(gpio_ioctl.data));
>         else
>                 gpio_ioctl.data=time(NULL);
> 
>         /* Convert binary (16 LSB) into LED segment codes and shift into
>            position on gpio */
>         gpio_ioctl.data=hex2led(gpio_ioctl.data & 0xFF)<<8;
> 
>         ioctl(fd, XGPIO_OUT,(void *)&gpio_ioctl);
> 
>         /* Read some data */
>         ioctl(fd, XGPIO_IN,(void *)&gpio_ioctl);
> 
>         dump_dipsw(gpio_ioctl.data);
> 
>         return 0;
> }
> 
> 
> ...crashes in flames when run:
> 
> # gpio_test FC
> [ 1366.864955] Oops: kernel access of bad area, sig: 11 [#5]
> [ 1366.867560] NIP: c0108d50 LR: c00e68c4 CTR: 00000000
> [ 1366.867560] REGS: c752fde0 TRAP: 0300   Tainted: G      D   (2.6.25-rc9)
> [ 1366.867560] MSR: 00029030 <EE,ME,IR,DR>  CR: 93000033  XER: e000007f
> [ 1366.867560] DEAR: c8fffffc, ESR: 00000000
> [ 1366.867560] TASK = c7c37030[202] 'gpio_test' THREAD: c752e000
> [ 1366.867560] GPR00: 00000000 c752fe90 c7c37030 c8fffffc 00000056 0000000c 
> c752feb0 00000000
> [ 1366.867560] GPR08: 00000000 11111111 ffffffe7 c7c5866c 00000000 10018dec 
> ffff8432 ffdf1d0f
> [ 1366.867560] GPR16: ffffffff ffffffff ffffffff ffffffff ffffffff 00000000 
> 100af244 10000858
> [ 1366.867560] GPR24: 10000c00 00000002 10000478 800c5a03 c7c58000 c7c5866c 
> 800c5a03 c0200000
> [ 1366.867560] NIP [c0108d50] XIo_In32+0x4/0xc
> [ 1366.867560] LR [c00e68c4] XGpio_GetDataDirection+0x84/0xac
> [ 1366.867560] Call Trace:
> [ 1366.867560] [c752fe90] [c00e66a8] xgpio_getinst+0x48/0xb0 (unreliable)
> [ 1366.867560] [c752fea0] [c00e6a8c] xgpio_ioctl+0x1a0/0x1fc
> [ 1366.867560] [c752fed0] [c006740c] vfs_ioctl+0x6c/0x84
> [ 1366.867560] [c752fee0] [c006778c] do_vfs_ioctl+0x368/0x39c
> [ 1366.867560] [c752ff10] [c0067800] sys_ioctl+0x40/0x70
> [ 1366.867560] [c752ff40] [c0002770] ret_from_syscall+0x0/0x3c
> [ 1366.867560] Instruction dump:
> [ 1366.867560] 7c634b78 7c031b78 4e800020 7c0006ac 88630000 5463063e 
> 4e800020 7c0006ac
> [ 1366.867560] a0630000 5463043e 4e800020 7c0006ac <80630000> 4e800020 
> 7c0006ac 7c601e2c
> Segmentation fault
> 
> 
> # dmesg | grep gpio
> [    0.120666] Registering device xilinx_gpio:0
> [    0.121672] Registering device xilinx_gpio:1
> [    0.122682] Registering device xilinx_gpio:2
> [    0.292352] xgpio0 #0 at 0x81400000 mapped to 0xC9000000 device: 10,185 
> using IRQ#7
> [    0.293805] xgpio1 #1 at 0x81420000 mapped to 0xC9020000 device: 10,186 
> using IRQ#6
> [    0.295062] xgpio2 #2 at 0x81440000 mapped to 0xC9040000 device: 10,187 
> using IRQ#5
> [ 1366.867560] TASK = c7c37030[202] 'gpio_test' THREAD: c752e000
> [ 1366.867560] [c752fe90] [c00e66a8] xgpio_getinst+0x48/0xb0 (unreliable)
> [ 1366.867560] [c752fea0] [c00e6a8c] xgpio_ioctl+0x1a0/0x1fc
> 
> 
> 
> Another program using a different strategy also fails:
> 
> #include <fcntl.h>
> #include <stdio.h>
> 
> int main (int argc, char *argv[]) {
>  if (argc==2 || argc==3) {
> 
>   int fd = open(argv[1], O_RDWR | O_NDELAY );
>   if (fd < 0) {
>      fprintf(stderr, "GPIO OPEN FAIL\n");
>      return -1;
>   }
> 
>   unsigned long buff = 0;
>   if (argc==2) {
>    if (read(fd, &buff, 4) != 4)
>       fprintf(stderr, "GPIO READ ERROR\n");
>    else printf( "%x\n", buff);
>   } else {
>    buff=atoi(argv[2]);
>    if (write(fd, &buff, 4) != 4)
>       fprintf(stderr, "GPIO WRITE ERROR value %x\n", buff);
>    else printf( "Written %x successfully\n", buff);
>   }
> 
>   close(fd);
>  } else {
>   fprintf(stderr, "Usage: %s device [value] to read or write data to gpio 
> device\n", argv[0]);
>   return 1;
>  }
> 
>  return 0;
> }
> 
> 
> # GpioReadWrite /dev/xgpio
> GPIO READ ERROR
> # GpioReadWrite /dev/xgpio 7
> GPIO WRITE ERROR value 0
> 
> I wanted to avoid writing a kernel module, but apparently I've ran out of 
> options...


________________________________________________________________________

John Bonesio
Commercial Linux Solutions
john.bonesio@xilinx.com
(408) 879-5569


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.


[-- Attachment #2: Type: text/html, Size: 12054 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Still struggling with Xilinx GPIO...
  2008-05-27 16:42 ` John Bonesio
@ 2008-05-28  9:51   ` Guillaume Dargaud
  2008-05-28 16:09     ` John Bonesio
  0 siblings, 1 reply; 4+ messages in thread
From: Guillaume Dargaud @ 2008-05-28  9:51 UTC (permalink / raw)
  To: John Bonesio; +Cc: linuxppc-dev

Hi John,

> Try using channel 1. It may be set up where the first channel is 1 and not 
> 0.

Not sure what you mean...

I'm actually not clear how many devices I should have:

$ grep "GPIO.*BASEADDR" 
arch/ppc/platforms/4xx/xparameters/xparameters_ml405.h
#define XPAR_GPIO_0_BASEADDR XPAR_LEDS_4BIT_BASEADDR
#define XPAR_GPIO_1_BASEADDR XPAR_LEDS_POSITIONS_BASEADDR
#define XPAR_GPIO_2_BASEADDR XPAR_PUSH_BUTTONS_POSITION_BASEADDR

But depending on the examples I look at, they define either:

crw-rw-rw-    1 root     root      10, 185 May 26 13:49 xgpio
or:
crw-rw-rw-    1 root     root      10, 185 May 26 13:18 xgpio0
crw-rw-rw-    1 root     root      10, 186 May 26 13:18 xgpio1
crw-rw-rw-    1 root     root      10, 187 May 26 13:18 xgpio2

If that is the former, I see the code uses:
 gpio_ioctl.chan=0;
And I guess that's what you are refering to, right ?

Putting 1 gives me a working program, but no LED lights up and the buttons 
are always shown at 0.
Putting 0 gives a nice core dump as in my previous msg.
Putting 2 locks up the system.

And... I don't see how the code manages to read/wite all 3 GPIOs with only 
two IOCTL calls. Shouldn't they be 3 different calls using different 
addresses ?!? Argh, this complete lack of documentation in maddening. Not 
everything can be understood from reading the source.

Thanks.
-- 
Guillaume Dargaud
http://www.gdargaud.net/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Still struggling with Xilinx GPIO...
  2008-05-28  9:51   ` Guillaume Dargaud
@ 2008-05-28 16:09     ` John Bonesio
  0 siblings, 0 replies; 4+ messages in thread
From: John Bonesio @ 2008-05-28 16:09 UTC (permalink / raw)
  To: Guillaume Dargaud; +Cc: linuxppc-dev

Hi Guillaume,

gpio_ioctl.chan = x;

That's what determines which gpio device gets used. Since using 1 at
least doesn't give you a core dump, I would guess that 1 is the correct
value to use there.

So the next thing to check is to make sure that the ioctl command codes
being used are right.

The only way I know how to do this is to look in the linux kernel source
for the gpio device. Try looking here:
    linux/drivers/char/xilinx_gpio

Then you find the routine that is handling the ioctl commands. It'll
probably be called xgpio_ioctl. In this routine you'll see something
like:
    switch(cmd) {
    case XGPIO_IN:
        ...

The value for XGPIO_IN is defined in a header file (probably). The
header file might be called xgpio_ioctl.h.

So here's the key:
    Make sure the value for XGPIO_IN used in the user application is the
same as the one used in the kernel.

At one point I had see a case where the values in the kernel had
changed, but the user application was still trying to use the old
values.

Hope this helps,

- John



On Wed, 2008-05-28 at 11:51 +0200, Guillaume Dargaud wrote:
> Hi John,
> 
> > Try using channel 1. It may be set up where the first channel is 1 and not 
> > 0.
> 
> Not sure what you mean...
> 
> I'm actually not clear how many devices I should have:
> 
> $ grep "GPIO.*BASEADDR" 
> arch/ppc/platforms/4xx/xparameters/xparameters_ml405.h
> #define XPAR_GPIO_0_BASEADDR XPAR_LEDS_4BIT_BASEADDR
> #define XPAR_GPIO_1_BASEADDR XPAR_LEDS_POSITIONS_BASEADDR
> #define XPAR_GPIO_2_BASEADDR XPAR_PUSH_BUTTONS_POSITION_BASEADDR
> 
> But depending on the examples I look at, they define either:
> 
> crw-rw-rw-    1 root     root      10, 185 May 26 13:49 xgpio
> or:
> crw-rw-rw-    1 root     root      10, 185 May 26 13:18 xgpio0
> crw-rw-rw-    1 root     root      10, 186 May 26 13:18 xgpio1
> crw-rw-rw-    1 root     root      10, 187 May 26 13:18 xgpio2
> 
> If that is the former, I see the code uses:
>  gpio_ioctl.chan=0;
> And I guess that's what you are refering to, right ?
> 
> Putting 1 gives me a working program, but no LED lights up and the buttons 
> are always shown at 0.
> Putting 0 gives a nice core dump as in my previous msg.
> Putting 2 locks up the system.
> 
> And... I don't see how the code manages to read/wite all 3 GPIOs with only 
> two IOCTL calls. Shouldn't they be 3 different calls using different 
> addresses ?!? Argh, this complete lack of documentation in maddening. Not 
> everything can be understood from reading the source.
> 
> Thanks.

________________________________________________________________________

John Bonesio
Commercial Linux Solutions
john.bonesio@xilinx.com
(408) 879-5569

This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-05-28 16:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-26 15:43 Still struggling with Xilinx GPIO Guillaume Dargaud
2008-05-27 16:42 ` John Bonesio
2008-05-28  9:51   ` Guillaume Dargaud
2008-05-28 16:09     ` John Bonesio

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).