GPIO: switching between ALT functions


13 posts
by TimG » Mon Apr 01, 2013 3:05 pm
Dear Group,
I'm looking for a command-line utility to switch GPIO pins between their alternative functions. Does such a thing exist?

So far I've only found C code, mostly variations on this from Gert & Dom:
http://elinux.org/RPi_Low-level_peripherals#C_2

I don't mind wrapping this up into something which can be called from a Bash script, but I thought I'd ask if somebody has done it already.
User avatar
Posts: 217
Joined: Tue Apr 03, 2012 12:15 am
Location: Switzerland
by joan » Mon Apr 01, 2013 3:17 pm
Not that I'm aware of. WiringPi gpio command line lets you set input or output or pwm. I know of nothing which allows the setting of a gpio to any of its 8 modes from the command line.
User avatar
Posts: 12528
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by TimG » Mon Apr 01, 2013 3:47 pm
OK. Well I put the code from http://elinux.org/RPi_Low-level_peripherals#C_2 in a simple wrapper and it seems to work ok. I've copied it below for comments & suggestions.

-Tim

Compile as follows:
Code: Select all
gcc -o gpio_alt gpio_alt.c
sudo chown root:root gpio_alt
sudo chmod u+s gpio_alt
sudo mv gpio_alt /usr/local/bin/


gpio_alt.c:
Code: Select all
/*
Utility to switch Raspberry-Pi GPIO pin functions
Tim Giles 01/04/2013

Usage:
$ gpio_alt -p PIN_NUMBER -f ALT_NUMBER

Based on RPi code from Dom and Gert, 15-Feb-2013, <http://elinux.org/RPi_Low-level_peripherals#C_2>
and Gnu getopt() example <http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html#Example-of-Getopt>
*/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;
volatile unsigned *gpio;
void setup_io();

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0



int main (int argc, char **argv) {
  int opt, flag, n_pin, n_alt;
  flag=0;

  while ((opt = getopt (argc, argv, "hp:f:")) != -1) {
    switch (opt) {
    case 'h':
      break;
    case 'p':
      n_pin = atoi(optarg); flag |= 0b0001; break;
    case 'f':
      n_alt = atoi(optarg); flag |= 0b0010; break;
    case '?':
      // getopt() prints error messages, so don't need to repeat them here
      return 1;
    default:
      abort ();
    }
  }
 
  if (flag != 0b0011) {
    fprintf (stderr, "Usage:\n$ gpio_alt -p PIN_NUM -f FUNC_NUM\n");
    return 1;
  }
 
  setup_io(); // Set up gpi pointer for direct register access
  INP_GPIO(n_pin);  // Always use INP_GPIO(x) before using SET_GPIO_ALT(x,y)
  SET_GPIO_ALT(n_pin, n_alt);
 
  printf("Set pin %i to alternative-function %i\n", n_pin, n_alt);
 
  return 0;
}



void setup_io() {
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned *)gpio_map;
}
User avatar
Posts: 217
Joined: Tue Apr 03, 2012 12:15 am
Location: Switzerland
by walt » Tue Sep 30, 2014 6:18 am
Great. I follow your steps, and PWM0, 1 on GPIO12 / 13 are worked as alt0 function.
Thank you .

But I have a little question, how to roll back to GPIO function. From datasheet, alt0 --alt5 is other functions, so what value of ALT_NUMBER should be for GPIO?

gpio_alt -p PIN_NUMBER -f ALT_NUMBER
Posts: 16
Joined: Wed Apr 02, 2014 3:32 am
Location: boston
by joan » Tue Sep 30, 2014 7:11 am
They are all gpio functions. Use input/output to set the two gpio functions not covered by alt0-alt5.
User avatar
Posts: 12528
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by vvn2023 » Mon Feb 23, 2015 5:21 am
Hi,

Is there any API to set the alt function in the kernel code ie in machine driver?

Thanks,
vvn
Posts: 33
Joined: Fri Dec 19, 2014 6:42 am
by msperl » Mon Feb 23, 2015 6:09 am
This kind of things would best get handled via device tree overlays - it then sets things up correctly on boot...

Martin
Posts: 325
Joined: Thu Sep 20, 2012 3:40 pm
by DougieLawson » Mon Feb 23, 2015 12:38 pm
msperl wrote:This kind of things would best get handled via device tree overlays - it then sets things up correctly on boot...

Martin


https://github.com/fivdi/onoff/wiki/Ena ... spberry-Pi
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

Since 2012: 1B*5, 2B*2, B+, A+, Zero*2, 3B*3

Please post ALL technical questions on the forum. Do not send private messages.
User avatar
Posts: 27538
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
by malevil » Mon Jun 06, 2016 7:40 pm
Thanks for the GPIO ALT switching code! It's been working for me nice on my RPi 2.

Unfortunately on my RPi 3 I wanted to reproduce the same ALT switching, but doesn't work :(
Neither found a proper GPIO map for RPi 3 with all the ALT functions, so I cannot validate if it's changed.

I'm wanted to use the GPIO 18 / ALT5 PWM function. Does anyone else has experience about this on RPi 3?
Should I use different code for switching or the GPIO mapping changed?

" pi@raspberrypi:~ $ gpio_alt -p 18 -f 5 "

Thanks!
Posts: 3
Joined: Mon Jun 06, 2016 7:34 pm
by joan » Mon Jun 06, 2016 8:09 pm
malevil wrote:Thanks for the GPIO ALT switching code! It's been working for me nice on my RPi 2.

Unfortunately on my RPi 3 I wanted to reproduce the same ALT switching, but doesn't work :(
Neither found a proper GPIO map for RPi 3 with all the ALT functions, so I cannot validate if it's changed.

I'm wanted to use the GPIO 18 / ALT5 PWM function. Does anyone else has experience about this on RPi 3?
Should I use different code for switching or the GPIO mapping changed?

" pi@raspberrypi:~ $ gpio_alt -p 18 -f 5 "

Thanks!

There must be dozens of ways of doing this now.

From the command line you can use my pigs to start hardware PWM on the relevant GPIO.
User avatar
Posts: 12528
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by malevil » Mon Jun 06, 2016 8:24 pm
Actually I'm routing the systems audio PWM signal there. It's works on RPi 2 as I described but not on RPi 3 for some reason...
Posts: 3
Joined: Mon Jun 06, 2016 7:34 pm
by joan » Mon Jun 06, 2016 8:32 pm
malevil wrote:Actually I'm routing the systems audio PWM signal there. It's works on RPi 2 as I described but not on RPi 3 for some reason...

pigs m 18 5 # set GPIO18 to mode ALT5
User avatar
Posts: 12528
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by malevil » Mon Jun 06, 2016 9:12 pm
joan wrote:
malevil wrote:Actually I'm routing the systems audio PWM signal there. It's works on RPi 2 as I described but not on RPi 3 for some reason...

pigs m 18 5 # set GPIO18 to mode ALT5


Thank you!
That works! :)
Posts: 3
Joined: Mon Jun 06, 2016 7:34 pm