Making GPIO pins available on the BeagleBoard XM

Hello,

i am trying to figure out how to make GPIO pins available on the
BeagleBoard XM. We are speaking regarding the 143 to 146 pins as a
good example. While 130-139 are available for input/output at once,
using an image for the SD card generated by narcissus is not enough to
make other pins work.

There is no run-time possibility to define the pins, as far as I
understand and there is no way to configure the kernel after it is put
on the SD card, right?

I have studied http://elinux.org/BeagleBoardPinMux, but I cannot
figure out the whole sequence for the final task:
1. To get an image of boot and system
2. Where boot should be altered to allow the extra GPIO pins for free
use inside my software
3. Other things are totally ok from the narcissus directly.

Is there an easy, but complete guide on that? Any help?

Thanks a lot in advance, SJ.

[/quote]
Yes, with kernel privileges, you CAN configure the pins from the user
Linux environment.

The following is a complete TCP server program in c that sets up a
group of GPIO pins
(avoiding some necessary pins in the same bank that will kill the
system if you
change their settings. Note I skip over pins 142 and 143.) It
compiles under a debian derived OS that has all the necessary
functions for GPIO access already built into it. I found this
necessary include stuff
was missing from angstrom, however.

Pretty much all the magic is done here by memory-mapped access
directly to the hardware
registers.

/*******server.c*********/
/*******Using select() for I/O multiplexing */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

                              /* port we're listening on */
#define PORT 2020
//following are bit masks for low 16 bit word of GPIO5
#define CS0 0x100 // chip select to first Mux
#define CS1 0x200 // chip select to second Mux
// following are bit masks for high 16-bit word of GPIO5
#define STROBE 0x1 // strobe mux latches
#define RESET 0x2 // Reset the Muxes

int main(int argc, char *argv[])
{
  /* master file descriptor list */
  fd_set master; /* temp file descriptor list for select() */
  fd_set read_fds; /* server address */
  struct sockaddr_in serveraddr; /* client address */
  struct sockaddr_in clientaddr; /* maximum file descriptor number */
  int fdmax; /* listening socket descriptor */
  int listener; /* newly accept()ed socket
descriptor */
  int newfd; /* buffer for client data */
  char buf[1024];
  int nbytes; /* for setsockopt() SO_REUSEADDR, below
*/
  int yes = 1;
  int addrlen, bufoffset;
  int i, j, k, l, m, n, x, gpio_addr, gpio_addrH_set,
gpio_addrH_clr;
  // int addrmap[16] = {0,1,2,3,4,5,8,9,10,
  // 11,12,13,6, 7, 14, 15};
  int addrmap[16] = {0,1,2,3,4,5,12, 13, 6,
                     7, 8, 9, 10, 11, 14, 15};
  /* clear the master and temp sets */
  FD_ZERO(&master);
  FD_ZERO(&read_fds);

  /* first, set up mapping and configure GPIO pads */
  int fd = open("/dev/mem", O_RDWR | O_SYNC);

  if (fd < 0) {
    printf("Could not open memory\n");
    return 0;
  }

  // Pad configuration
  volatile ulong *pinconf;
  pinconf = (ulong*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0x48000000);
  if (pinconf == MAP_FAILED) {
    printf("Pinconf Mapping failed\n");
    close(fd);
    return 0;
  }

  // Configure Expansion header pins as I/O (GPIO 154..144) gap (GPIO
139 .. 130)

   pinconf[0x2158/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 130,131
   pinconf[0x215C/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 132,133
   pinconf[0x2160/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 134,135
   pinconf[0x2164/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 136,137
   pinconf[0x2168/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 138,139
   pinconf[0x216C/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 140,141
   pinconf[0x2174/4] = 0x011C011C; // set pulltype, bi-dir and
mux mode 4, GPIO 144,145
   close(fd);

   printf("Pinconf completed.\n");

   fd = open("/dev/mem", O_RDWR | O_SYNC);

  // GPIO Configuration: configure are input
   volatile ulong *gpio;
   gpio = (ulong*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0x49050000);
   if (gpio == MAP_FAILED) {
     printf("Gpio Mapping failed\n");
     close(fd);
   }

   printf("GPIO mmap complete\n");
  // Configure GPIO 5 bits 17,16 and 11..2 as output.
  x = gpio[6034/4];
  printf("gpio[6034/4] = %x\n",x);
  // x = x & 0xfffcf003; // change bits 17, 16 and 11..2 to
zero
  x = x & 0xfffc0003; // change bits 17, 16 and 11..2 to zero
  gpio[0x6034/4] = x;
  printf("config pads GPIO_139..130 to output\n");

   fd = open("/dev/mem", O_RDWR | O_SYNC);

  // GPIO Configuration: configure are input
   volatile ushort *gpios;
   gpios = (ushort*) mmap(NULL, 0x10000, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0x49050000);
   if (gpios == MAP_FAILED) {
     printf("Gpios Mapping failed\n");
     close(fd);
   }

  // parallel byte I/O on GPIO_137 .. GPIO_130
  /* pin map is as follows :
   Bit GPIO pad Expansion Header Pin #
   Reset GPIO_145 10
   Strobe GPIO_144 4
   CS1 GPIO_139 3
   CS0 GPIO_138 5
   MSB GPIO_137 7
     6 GPIO_136 9
     5 GPIO_135 11
     4 GPIO_134 13
     3 GPIO_133 15
     2 GPIO_132 17
     1 GPIO_131 19
   LSB GPIO_130 21
  */
  int c=0;
  gpio_addr = 0x603c/2; // addr of gpio data out reg
  gpio_addrH_set = 0x6096/2; // addr of high 16-bit word of GPIO5
  gpio_addrH_clr = 0x6092/2; // addr of high 16-bit word of GPIO5

  /* now set up the server */
  /* get the listener */
  if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
      perror("Server-socket() error lol!");
      /*just exit lol!*/
      exit(1);
    }
  printf("Server-socket() is OK...\n");
  /*"address already in use" error message */
  if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
== -1)
    {
      perror("Server-setsockopt() error lol!");
      exit(1);
    }
  printf("Server-setsockopt() is OK...\n");

  /* bind */
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_addr.s_addr = INADDR_ANY;
  serveraddr.sin_port = htons(PORT);
  memset(&(serveraddr.sin_zero), '\0', 8);
  if(bind(listener, (struct sockaddr *)&serveraddr,
sizeof(serveraddr)) == -1)
    {
      perror("Server-bind() error lol!");
      exit(1);
    }
  printf("Server-bind() is OK...\n");

  /* listen */
  if(listen(listener, 10) == -1)
    {
      perror("Server-listen() error lol!");
      exit(1);
    }
  printf("Server-listen() is OK...\n");

  /* add the listener to the master set */
  FD_SET(listener, &master);
  /* keep track of the biggest file descriptor */
  fdmax = listener; /* so far, it's this one*/

  /* loop */
  for(;:wink:
    {
      /* copy it */
      read_fds = master;

      if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
        {
          perror("Server-select() error lol!");
          exit(1);
        }
      printf("Server-select() is OK...\n");

      /*run through the existing connections looking for data to be
read*/
      for(i = 0; i <= fdmax; i++)
        {
          if(FD_ISSET(i, &read_fds))
            { /* we got one... */
              if(i == listener)
                {
                  /* handle new connections */
                  addrlen = sizeof(clientaddr);
                  if((newfd = accept(listener, (struct sockaddr
*)&clientaddr, &addrlen)) == -1)
                    {
                      perror("Server-accept() error lol!");
                    }
                  else
                    {
                      printf("Server-accept() is OK...\n");

                      FD_SET(newfd, &master); /* add to master set */
                      if(newfd > fdmax)
                        { /* keep track of the maximum */
                          fdmax = newfd;
                        }
                      printf("%s: New connection from %s on socket %d
\n", argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
                    }
                }
              else
                {
                  /* handle data from a client */
                  if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
                    {
                      /* got error or connection closed by client */
                      if(nbytes == 0)
                        /* connection closed */
                        printf("%s: socket %d hung up\n", argv[0], i);
                      else
                        perror("recv() error lol!");
                      /* close it... */
                      close(i);
                      /* remove from master set */
                      FD_CLR(i, &master);
                    }
                  else
                    {
                      gpios[ gpio_addrH_set] = RESET;
                      gpios[ gpio_addrH_clr] = RESET;
                      /* we got some data from a client*/
                      if (nbytes >= 10) {
                        for (j=0; j < 16; j++) printf("%x ",buf[j]);
                        printf("\n");
                        bufoffset = 0;
                        for (j=0; j < 10; j++) {
                          if ((buf[j] == 0xff) && (buf[j+1] == 0xff))
bufoffset = j+2;
                        }
                        printf("offset to first data is %d
\n",bufoffset);
                        printf("message is %x, Length is %d
\n",i,nbytes);
                        for (j=0;j< 8;j++) {
                          printf("byte %x is %x\n",j,buf[j
+bufoffset]);
                          m = CS0; // clear control bits
                          printf("data = ");
                          for (k=0; k<16; k++) { // loop through
first 16 switches
                            if ((buf[j+bufoffset]) == addrmap[k]) {l =
0x80;}
                            else {l = 0;}
                            n = ((k & 0x0f) | ((j << 4) & 0x70) | l |
m) & 0x3ff;
                            printf("%x ",n);
                            gpios[gpio_addr] = (n & 0x3ff) << 2;
                            gpios[ gpio_addrH_set] = STROBE;
                            gpios[ gpio_addrH_clr] = STROBE;
                            // need to clear CS0 bit
                            n = n & (!CS0);
                            gpios[gpio_addr] = (n & 0x3ff ) << 2;
                          }
                          printf("\n");
                          m = CS1; // clear control bits
                          for (k=0; k<16; k++) { // loop through
second 16 switches
                            if ((buf[j+bufoffset]) == (addrmap[k]+16))
{l = 0x80;}
                            else {l = 0;}
                            n = ((k & 0x0f) | ((j << 4) & 0x70) | l |
m) & 0x3ff;
                            gpios[gpio_addr] = (n & 0x3ff) << 2;
                            gpios[ gpio_addrH_set] = STROBE;
                            gpios[ gpio_addrH_clr] = STROBE;
                            n = n & (!CS1);
                            gpios[gpio_addr] = (n & 0x3ff ) << 2;
                          }
                        }
                      }
                    }
                }
            }
        }
    }
  return 0;
}

Dear jmelson, this was extremely helpful, thanks a lot!

Hope it will be useful. There is the setup part at the beginning,
and then the last page near the end is where the server code actually
performs I/O to the GPIO pins after a command comes in. The middle
is all the TCP server code that is not related to the GPIO stuff.

I built this with a LOT of helpful hints from this forum, and it is
used to view signals in a remotely-located experimental area.

Jon

Jon, perhaps it will overlay some of the previous topics, but:

  1. Where can I find the mapping of GPIO5 bits to any of the following: [EXP, Processor Pins or GPIO_XXX]?

  2. How to properly set up pins as inputs or outputs using memory access, because you write you set up for output (0, probably?) 11…2 and 16,17 bits, but in your configuration you set up 15 and 14 as well, have a look at this, please:
    FFFC0003
    1111 1111 1111 1100 0000 0000 0000 0011

  3. How to properly set or clear any of these bits - high or low (when configured as inputs) and to read the discrete value (when configured as outputs)?

This will for sure be useful to others beginning as well. Thanks!

Jon, perhaps it will overlay some of the previous topics, but:

1. Where can I find the mapping of GPIO5 bits to any of the following: [EXP,
Processor Pins or GPIO_XXX]?

The mapping to the Beagle Board header pinout is in the Beagle Board
manual.
The mapping of all the GPIO to OMAP pads is in the technical reference
manual from TI. It is not as well organized as one might like, you
need
to read THREE different sections to pull it all together. Yes, I
KNOW, it
is 1700 PAGES, but the info is in there.

But, basically, GPIO numbering starts at zero, so GPIO 0-31 are in
GPIO bank
1, 32-63 is bank 2, 64-95 is bank 3, 96 - 127 is bank 4, 128 - 159 is
bank 5
and 160 - 192 is bank 6.

2. How to properly set up pins as inputs or outputs using memory access,
because you write you set up for output (0, probably?) 11..2 and 16,17 bits,
but in your configuration you set up 15 and 14 as well, have a look at this,
please:
FFFC0003
1111 1111 1111 1100 0000 0000 0000 0011

Yes, sorry, the comments may have gotten a little out of sync with the
actual
working code.

3. How to properly set or clear any of these bits - high or low (when
configured as inputs) and to read the discrete value (when configured as
outputs)?

You can always read an output bit, the setting for output just turns
on the
output drivers for that pin.

There is a write register that can be written as byte, 16-bit word or
32-bit longword. I don't use these as you can't write to several bits
in the middle of the GPIO5 bank or it will kill the system. So, I use
the masked set and clear registers instead, and make sure I only
affect the
desired bits. You can't set or clear an input bit, that is a function
of the external
hardware. You can only read what the external device is sending.

Your terminology is confusing. An OUTPUT from the OMAP chip drives a
signal
onto the pin. An INPUT senses the state of the pin, presumably driven
by
something off-board.

Jon

Dear Jon,

to stay on the polite side, I would like to inform that I successfully
finished reading inputs with the fast direct memory reading approach
(before that, I had problems with fopen-ing gpio files to read an
input already at about 0.8kHz) implementing what was posted in this
forum and adding necessary changes from my side.

SJ.