Contents

[hide]

 Interfaces explained

There are 2 main ways which can be used to talk to gpio pins on an AVR32 from userspace:

  • gpio-dev is an AVR32-specific interface, shipped only in .atmel kernels. You can change the state of a number of GPIOs at one time and you can receive pin change notifications by means of a blocking read. It can only deal with gpio inside the AVR32, not on an I/O expander.
  • gpio-sysfs is a user interface to the in kernel gpio framework. As such you have the same interface no matter what platform you're developing for. It deals with pins strictly one at a time. It is available in all mainline kernels from 2.6.27 onwards. At the time of writing it does not have support for pin change notification but patches to implement this exist, just message Squidgit and he'll get them to you. gpio-sysfs also doesn't care whether the gpios are built in to the AVR32 or whether they're on an external gpio expander, they're all interfaced the same way.

If you're inside the kernel then you've got one option:

  • gpio framework. This is the name of the framework through which gpios are accessed from within the kernel. gpio-sysfs is built on top of this for userspace access.

gpio-dev

NOTE: This method of I/O is depriciated and not suggested to use for new code. Use the gpio-sysfs instead.UPDATE: gpio-dev has been completely removed from Atmel kernels and Buildroot version 2.3.0 and newer. Use of sysfs is now mandatory for new systems.

Many others have shown how to use gpio-dev, I won't repeat their work here.

 gpio-sysfs

gpio-sysfs is the preferred method of gpio interfacing from userspace. Use this unless you absolutely need to update multiple gpios simultaniously or you must use a kernel version before 2.6.27. The full documentation is alongside the gpio-framework documentation, here.

File structure

The control files are all contained in

#: ls/sys/class/gpio
export       gpiochip0    gpiochip32   gpiochip96
gpiochip128  gpiochip64   unexport

Initially all that is in this folder are gpiochipN folders. There is one of these for each chip which provides gpio pins. On an AT32AP7000 for example, you have 4 gpiochipN folders corresponding to Ports A, B, C, D and E. Note that inside the kernel, Porta A through E and actually called pio0 through pio4 respectively. You can find out which gpiochip folder is which by examinging the "label" file in each one of those folders. For example gpiochip32 corresponds to pio1/PortB:

#: cat /sys/class/gpio/gpiochip32/label
pio1

For any gpios which have been exported for userspace access, you'll also see a gpioN folder where N is the number of the gpio. More on this shortly.

GPIO Numbers

To get access to a gpio, you must find the gpio number. This is done by finding the base number of the chip to which that gpio belongs then adding the number of the pin on that chip. For example, PC8 is the Port C base plus 8.

Each base can be found by looking in the "base" file of the corresponding gpiochipN folder. It's also the number at the end of the folder name. So in this example, we're looking for Port C, called pio2. This label is found in the gpiochip64 folder and as such the base number is 64. We want pin 8 so 8 + 64 is 72, this is our gpio number.

NOTE: This may sound complex but for chips which are always attached, like ones built in to the AVR32 chip, the numbers stay the same. You can find the gpio number once and use it for all time.

If you have any I/O expanders connected to, eg, the SPI bus, they'll have their own gpiochip folders here. The base numbers for these detachable expanders may change so you should find the base number and recalculate the gpio number each time the board starts up or the adapter is plugged in.

[edit] Getting access to a GPIO

Some times the kernel has already given you access to a gpio. If so you'll see gpioN folders in /sys/class/gpio where N is the gpio number. If you don't have this folder already, you need to create it. Once you've got the GPIO number, you request it from the kernel. Do this by writing the gpio number to the export file like

#: echo 72 > /sys/class/gpio/export

Once you've done this you'll see a folder, /sys/class/gpio/gpio72. In this folder you'll see the attributes needed to control the gpio.

#: ls /sys/class/gpio/gpio72
device         power          uevent
direction      subsystem      value

Out of all of these, you only need to pay attention to "value" and "direction".

If you don't need control of the gpio anymore, you can unexport it

#: echo 72 > /sys/class/gpio/unexport

Getting and Setting Direction

To set the direction, write one of "in", "out", "high" or "low" to your gpio's direction attribute. "low" and "out" have the same effect, to change the pin to an output which is initially low. "high" changes the pin to an output which is initially high. "in" changes the pin to an input.

This file will read as "in" or "out" so you can tell the direction.

#: echo "high" > /sys/class/gpio/gpio72/direction
#: cat /sys/class/gpio/gpio72/direction
out


Please note on a custom built 2.6.27 kernel using Buildroot, Dingo_aus found he needed to use

#: echo out > /sys/class/gpio/gpio72/direction
instead of 
#: echo "high" > /sys/class/gpio/gpio72/direction

Getting and Setting State

To set an output high or low, write a '1' or '0' to the value attribute. To read the value, just read this file.

 Putting it all together

Right, lets put it all together and get access to PB2, set it to an initially high output, check that it has worked, set the output low then change it to an input and read the state.

#: cat /sys/class/gpio/gpiochip0/label
pio0
#: cat /sys/class/gpio/gpiochip32/label
pio1
#: cat /sys/class/gpio/gpiochip32/base
32
So we've found that Port B (pio1) is gpiochip32, the base is 32. We want pin 2 of this so our gpio number is 34
#: echo 34 > /sys/class/gpio/export
#: echo "high" > /sys/class/gpio/gpio34/direction
#: cat /sys/class/gpio/gpio34/direction
out
#: cat /sys/class/gpio/gpio34/value
1
#: echo 0 > /sys/class/gpio/gpio34/value
#: cat /sys/class/gpio/gpio34/value
0
#: echo "in" > /sys/class/gpio/gpio34/direction
#: cat /sys/class/gpio/gpio34/value
[some value]

Done!

 Example of GPIO access from within a C program

The following a sample C program to blink PB3 at 1Hz on the AP7000.

// Blink pin 3 on port B at 1 Hz
// Just add an LED and see the light! ;)
//
//Created by Dingo_aus, 7 January 2009
//email: dingo_aus [at] internode <dot> on /dot/ net
//
//Created in AVR32 Studio (version 2.0.2) running on Ubuntu 8.04

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

FILE *fp; 

int main(int argc, char** argv)
{

	printf("\n**********************************\n"
			"*  Welcome to PIN Blink program  *\n"
			"*  ....blinking pin 3 on port B  *\n"
			"*  ....rate of 1 Hz............  *\n"
			"**********************************\n");
	
	//create a variable to store whether we are sending a '1' or a '0'
	char set_value[4]; 
	//Integer to keep track of whether we want on or off
	int toggle = 0;
	
	//Using sysfs we need to write "37" to /sys/class/gpio/export
	//This will create the folder /sys/class/gpio/gpio37
	if ((fp = fopen("/sys/class/gpio/export", "ab")) == NULL)
		{
			printf("Cannot open export file.\n");
			exit(1);
		}
	//Set pointer to begining of the file
		rewind(fp);
		//Write our value of "37" to the file
		strcpy(set_value,"37");
		fwrite(&set_value, sizeof(char), 2, fp);
		fclose(fp);
	
	printf("...export file accessed, new pin now accessible\n");
	
	//SET DIRECTION
	//Open the LED's sysfs file in binary for reading and writing, store file pointer in fp
	if ((fp = fopen("/sys/class/gpio/gpio37/direction", "rb+")) == NULL)
	{
		printf("Cannot open direction file.\n");
		exit(1);
	}
	//Set pointer to begining of the file
	rewind(fp);
	//Write our value of "out" to the file
	strcpy(set_value,"out");
	fwrite(&set_value, sizeof(char), 3, fp);
	fclose(fp);
	printf("...direction set to output\n");
	
	//SET VALUE
	//Open the LED's sysfs file in binary for reading and writing, store file pointer in fp
	if ((fp = fopen("/sys/class/gpio/gpio37/value", "rb+")) == NULL)
		{
			printf("Cannot open value file.\n");
			exit(1);
		}
	//Set pointer to begining of the file
	rewind(fp);
	//Write our value of "1" to the file 
	strcpy(set_value,"1");
	fwrite(&set_value, sizeof(char), 1, fp);
	fclose(fp);
	printf("...value set to 1...\n");
			
	//Run an infinite loop - will require Ctrl-C to exit this program
	while(1)
	{
		//Set it so we know the starting value in case something above doesn't leave it as 1
		strcpy(set_value,"1");
		
		if ((fp = fopen("/sys/class/gpio/gpio37/value", "rb+")) == NULL)
		{
			printf("Cannot open value file.\n");
			exit(1);
		}	
		toggle = !toggle;
		if(toggle)
		{
			//Set pointer to begining of the file
			rewind(fp);
			//Write our value of "1" to the file 
			strcpy(set_value,"1");
			fwrite(&set_value, sizeof(char), 1, fp);
			fclose(fp);
			printf("...value set to 1...\n");
		}
		else
		{
			//Set pointer to begining of the file
			rewind(fp);
			//Write our value of "0" to the file 
			strcpy(set_value,"0");
			fwrite(&set_value, sizeof(char), 1, fp);
			fclose(fp);
			printf("...value set to 0...\n");
		}
		//Pause for one second
		sleep(1);
	}
	return 0;
}

When executed on your board the expected output will be similar to the following:

/home/dingo # ./first_pin_blink.elf 

**********************************
*  Welcome to PIN Blink program  *
*  ....blinking pin 3 on port B  *
*  ....rate of 1 Hz............  *
**********************************
...export file accessed, new pin now accessible
...direction set to output
...value set to 1...
...value set to 1...
...value set to 0...
...value set to 1...
^C
/home/dingo # 

Logo

更多推荐