You are on page 1of 14

Access GPIO of AT91 in Linux Embedded System

GPIO of AT91 In Linux Embedded System I./ TRUY XUT GPIO T /SYS/CLASS/GPIO. Ch h tr Kernel-2.6.27 tr ln. + Kim tra kernel c check module gpio-sysfs hay cha bng lnh sau:
# cd linux-2.6.30 //v d thc hin trn kernel-2.6.30 # make ARCH=arm menuconfig trong mc Device Driver ...> chn [*]GPIO support ...> tip theo chn [*] /sys/class/gpio ...

ri build li kernel c h tr lp gpio-sysfs, sau update li kernel cho h thng. + Bootup li h thng ri g lnh trn mn hnh terminal kim tra kernel va mi build li

c support lp gpio-sysfs hay cha?


# ls /sys/class/gpio export gpiochip32 gpiochip96 gpiochip64 unexport # cat /sys/class/gpio/gpiochip32/label A # cat /sys/class/gpio/gpiochip64/label B # cat /sys/class/gpio/gpiochip96/label C

tng ng cho port A, B, C,

+ GPIO Numbers: L s tng ng chn ca Port, nn Port A l 32, Port B l 64 v Port C l 96, offset gia cc Port l 32. V d: PC8 th c s bng nn ca Port C cng 8, tc = 96+8 = 104 PB8 th c s bng nn ca Port B cng 8, tc = 64+8 = 72 + Getting access to a GPIO: Nu chng ta thy th mc gpioN trong /sys/class/gpio/ th N y chnh l GPIO Number nh m t trn. Ngc li cha c th cn phi to n trc khi s dng bng lnh sau:
# echo 72 > /sys/class/gpio/export //to chy PB8

Sau khi to xong, trong th muc gpio72 s c cc thuc tnh iu khin GPIO, xem bng lnh sau:
# ls /sys/class/gpio/gpio72 power uevent direction subsystem value

chng ta ch cn thuc tnh direction v value l c th iu khin c I/O. Nu khng iu khin th release gpioN bng lnh sau:
# echo 72 > /sys/class/gpio/unexport

+ Getting and Setting Direction: Ghi mt trong cc "in", "out", "high", "low" vo thuc tnh direction ca gpioN
1

Access GPIO of AT91 in Linux Embedded System


# echo "high" > /sys/class/gpio/gpio72/direction //set muc cao # cat /sys/class/gpio/gpio72/direction //xem chiu hin ti out

+ V d: iu khin PB8.
# echo 72 > /sys/class/gpio/export //Create gpio72 # echo "high" > /sys/class/gpio/gpio72/direction //Set high logic # cat /sys/class/gpio/gpio72/direction //Read direction out # cat /sys/class/gpio/gpio72/value //getting value 1 # echo 0 > /sys/class/gpio/gpio72/value //set low logic # cat /sys/class/gpio/gpio72/value 0 # echo "in" > /sys/class/gpio/gpio72/direction //Set in diraction # cat /sys/class/gpio/gpio72/value //Getting value from pin [some value]

Sample code
// // // // gpio-sysfs.c Created by Thinh Nguyen Tan, 25 August 2011 email: thinh.nttech@gmail.com Created in Eclipse SDK tool (version 3.5.2) running on Ubuntu 11.04 <string.h> <stdio.h> <stdlib.h> <unistd.h>

#include #include #include #include

int create_PIO_pin(char *num_pin); int set_direction_pin(char *gpio_num, char *direction); int set_value_pin(char *gpio_num, char *value); int main(int argc, char** argv) { printf("\n**********************************\n" "* Welcome to PIN Blink program *\n" "* blinking pin 20,21 on port B *\n" "* ....rate of 1 Hz............ *\n" "**********************************\n"); //Integer to keep track of whether we want on or off int toggle = 0; //Using sysfs we need to write "84" to /sys/class/gpio/export //This will create the folder /sys/class/gpio/gpio84 <PB20> if (create_PIO_pin("84") == -1) { printf("Cannot open export file.\n"); exit(1); } //This will create the folder /sys/class/gpio/gpio85 <PB21> if (create_PIO_pin("85") == -1) { printf("Cannot open export file.\n"); exit(1); } printf("...export file accessed, new pin now accessible\n"); //SET DIRECTION if (set_direction_pin("gpio84", "out") == -1)

Access GPIO of AT91 in Linux Embedded System


{ printf("Cannot open direction file.\n"); exit(1); } if (set_direction_pin("gpio85", "out") == -1) { printf("Cannot open direction file.\n"); exit(1); } printf("...direction set to output\n"); //Run an infinite loop - will require Ctrl-C to exit this program while(1) { toggle = !toggle; if(toggle) { //Set "1" to file set_value_pin("gpio84", "1"); set_value_pin("gpio85", "1"); printf("...value set to 1...\n"); } else { set_value_pin("gpio84", "0"); set_value_pin("gpio85", "0"); printf("...value set to 0...\n"); } //Pause for one second sleep(1); } return 0; }

/* * to create the folder /sys/class/gpio/gpionum_pin * ex: PB20 -> num_pin = "84" * Input: none * Output: none * Return: -1 * 0 */
int create_PIO_pin(char *num_pin) { FILE *fp=NULL; //create a variable char set_value[4]; //Using sysfs we need to write num_pin to /sys/class/gpio/export //This will create the folder /sys/class/gpio/gpionum_pin if ((fp = fopen("/sys/class/gpio/export", "ab")) == NULL) { printf("Cannot open export file.\n"); return -1; } //Set pointer to begining of the file rewind(fp); //Write our value of num_pin to the file

Access GPIO of AT91 in Linux Embedded System


strcpy(set_value, num_pin); fwrite(&set_value, sizeof(char), strlen(set_value), fp); fclose(fp); return 0; } /* * Set direction pin * Input: *gpio_num, *direction ex: "gpio84", "in"/"out" * Output: none * Return: -1 * 0 */ int set_direction_pin(char *gpio_num, char *direction) { const char *fd = "/sys/class/gpio/"; char fileName[40]; char set_value[4]; FILE *fp=NULL; memset strcat strcat strcat (fileName, (fileName, (fileName, (fileName, 0x0, 40); fd); gpio_num); "/direction");

//SET DIRECTION //Open the LED's sysfs file in binary for reading and writing { printf("Cannot open direction file: %s.\n", fileName); return -1; } //Set pointer to begining of the file rewind(fp); //Write our value of "out" to the file strcpy(set_value, direction); fwrite(&set_value, sizeof(char), strlen(set_value), fp); fclose(fp); return 0; } /* * Set value in pin * Input: *gpio_num, *value ex: "gpio84", "0"/"1" * Output: none * Return: -1 * 0 */ int set_value_pin(char *gpio_num, char *value) { const char *fd = "/sys/class/gpio/"; char fileName[40], set_value[4]; FILE *fp=NULL; memset strcat strcat strcat (fileName, (fileName, (fileName, (fileName, 0x0, 40); fd); gpio_num); "/value");

//SET DIRECTION //Open the LED's sysfs file in binary for reading and writing

Access GPIO of AT91 in Linux Embedded System


{ printf("Cannot open value file %s.\n", fileName); return -1; } //Set pointer to begining of the file rewind(fp); //Write our value of "0"/1 to the file strcpy(set_value, value); fwrite(&set_value, sizeof(char), 1, fp); fclose(fp); return 0; }

/* * Read value of a pin * Input: *gpio_num, *value ex: "gpio84" * Output: none * Return: -1 * 0 high * 1 low */ int read_value_pin(char *gpio_num) { int ret; const char *fd = "/sys/class/gpio/"; char fileName[40], set_value[4]; FILE *fp=NULL; memset strcat strcat strcat (fileName, (fileName, (fileName, (fileName, 0x0, 40); fd); gpio_num); "/value");

//SET DIRECTION //Open the sysfs file in binary for reading and writing if ((fp = fopen(fileName, "rb+")) == NULL) { printf("Cannot open value file %s.\n", fileName); return EOPENFILE; } //Set pointer to begining of the file rewind(fp); //Read our value of the file memset(set_value, 0x00, 4); fread (&set_value, sizeof(char), 1, fp); fclose(fp); if (set_value[0] = '0') ret = 0; else ret = 1; return ret; }

Access GPIO of AT91 in Linux Embedded System

Makefile:
# TODO: # makefile
ifndef ERASE_FCT ERASE_FCT=rm -rf endif ifndef CROSS_COMPILE CROSS_COMPILE=/home/arm/project/compiler/arm-2011.03/bin/arm-none-linux-gnueabiendif CC=$(CROSS_COMPILE)gcc STRIP=$(CROSS_COMPILE)strip all: main main: main.o @echo 'Building target: $@' @echo 'Invoking: arm-2011.03-41-arm-none-linux-gnueabi-' $(CC) -o main *.o -lpthread $(STRIP) main @echo 'finised building target :$@' main.o: gpio-sysfs.c $(CC) -c gpio-sysfs.c clean: $(ERASE_FCT) main *.o

Bin dch chng trnh: Copy source code v makefile vo th mc ng dng, ch ng dn ca trnh bin dch phi ging vi ng dn ch trong makefile. V d: to th mc /home/arm/project/application/gpio-sysfs copy gpio-sysfs.c v makefile vo th mc gpio-sysfs vi ng dn nh trn.
# cd /home/arm/project/application/gpio-sysfs //vo th mc sourcecode # cat clean # make //lnh xa tt c cc file output //build ng dng, sau khi thnh cng s sinh ra file // thc thi, main

Access GPIO of AT91 in Linux Embedded System

II./ TRUY XUT GPIO T KERNEL MODULE . Kernel module l mt dng driver c vit di dng module trong h thng nhng, n gip cho developer pht trin chng trnh iu khin trong h thng ebedded system mt cch linh ng. Cc lnh shell thc hin add, remove v list kernel module vo h thng bao gm "insmod, rmmod, lsmod ...". Driver ca Linux c th tch hp vo h thng theo hai kiu bao gm driver build sn (tch hp vo file nh ca kernel l uImage hoc zImage) hc theo kiu module. phin bn Linux 2.6.xx ui file ca module khi bin dch ra c tn l ".ko". Internal module: Internal module c source c tch hp vo trong kernel source (linux-2.6.xx), bin dch module ny, chng ta cn phi config li kernel v check ch [M] vo mc chn trong kernel menuconfig. bin dch internal module ta dng lnh sau: $ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- modules Ch : lnh ny ch c thc hin khi ta ang th mc gc ca kernel source, v d nh th mc "linux-2.6.30" v attach trong makefile ca th mc linux-2.6.xx. External module: External module l c source code xy dng nm ngoi kernel source, khi ngi dng cn phi to ra Makefile cho ph hp c th bin dch. Cu trc ca Makefile cho external module nh sau: + Bin dch dng native gcc: (cn phi c source kernel trong h thng rootfs, thch hp cho h thng Linux chy trn PC), ta c Makefile nh sau:
obj-m += module.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Trong , source module c tn l module.c. Sau khi compile xong ta c c module.ko + Bin dch dng cross-compiler: (dng my tnh Linux bin dch cho h thng nhng SAM9260-EK, ) cu trc Makefile c dng nh sau:
export ARCH=arm export CROSS_COMPILE=arm-none-linux-gnueabiobj-m += module.o all: make -C /home/arm/project/kernel/linux-2.6.30 M=$(PWD) modules clean: make -C /home/AT91SAM9260/KERNEL/linux-2.6.30 M=$(PWD) clean 7

Access GPIO of AT91 in Linux Embedded System

Ta cn phi export hai bin ARCH v CROSS_COMPILE, tham s -C ca lnh make bao gm ng dn n source kernel cho h thng nhng. Dng lnh sau dch module: $ make clean all 2.1/ Xy dng gpio module Driver, cc pin gpio_number ca AT91SAM9260 c khai bo trong header file: "arch/arm/mach-at91/include/mach/gpio.h"
AT91_PIN_PA0, AT91_PIN_PB0, AT91_PIN_PC0, ...

V d :
#defineAT91_PIN_PA0 (PIN_BASE + 0x00 + 0) #defineAT91_PIN_PB0 (PIN_BASE + 0x20 + 0) #defineAT91_PIN_PC0 (PIN_BASE + 0x40 + 0) #defineAT91_PIN_PD0 (PIN_BASE + 0x60 + 0)

... V PIN_BASE c nh ngha trong header file "irqs.h" v c gi tr l 32. Nh vy ta c th quy i ra gpio_number theo cng thc nh sau: 1. Pin name c dng P<letter><number> 2. gpio_number = 32*letter + number : A = 1, B = 2, C = 3 ... 3. V d : PC6 => gpio_number = 32*3+6 = 102 Sau y l v d cho kernel module c tn gi l gpio_dev, driver cho php chng trnh ng dng truy xut gpio pin trn MPU, bao gm cc IO control set chiu input, ouput, set bit, clear bit. Chng trnh ng dng s dng driver ny thng qua device file c tn l "/dev/gpio". Sau y l v d cho kernel module vi source file c tn l "gpio_dev.c".
#include #include #include #include #include #include #include #include #include #include <linux/module.h> <linux/errno.h> <linux/init.h> <asm/uaccess.h> <asm/io.h> <asm/gpio.h> <asm/atomic.h> <linux/init.h> <linux/genhd.h> <linux/miscdevice.h> "gpiodev" "gpio" //driver name //device name

#define DRVNAME #define DEVNAME

#define IOC_GPIODEV_MAGIC 'B' #define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10) #define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)

Access GPIO of AT91 in Linux Embedded System


#define GPIO_CLEAR #define GPIO_DIR_IN #define GPIO_DIR_OUT static int dev_major; /* Counter is 1, if the device is not opened and zero (or less) if opened. */ static atomic_t gpio_open_cnt = ATOMIC_INIT(1); static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int retval = 0; switch (cmd) { case GPIO_GET: retval = gpio_get_value(arg); break; case GPIO_SET: printk("gpio set\n"); gpio_set_value(arg, 1); break; case GPIO_CLEAR: printk("gpio clear\n"); gpio_set_value(arg, 0); break; case GPIO_DIR_IN: gpio_direction_input(arg); break; case GPIO_DIR_OUT: gpio_direction_output(arg, 0); break; default: retval = -EINVAL; break; } return retval; } static int gpio_open(struct inode *inode, struct file *file) { int result = 0; unsigned int dev_minor = MINOR(inode->i_rdev); /* FIXME: We should really allow multiple applications to open the device * at the same time, as long as the apps access different IO pins. * The generic gpio-registration functions can be used for that. * Two new IOCTLs have to be introduced for that. Need to check userspace * compatibility first. --mb */ if (!atomic_dec_and_test(&gpio_open_cnt)) { _IO(IOC_GPIODEV_MAGIC, 12) _IO(IOC_GPIODEV_MAGIC, 13) _IO(IOC_GPIODEV_MAGIC, 14)

Access GPIO of AT91 in Linux Embedded System


atomic_inc(&gpio_open_cnt); printk(KERN_ERR DRVNAME ": dev_minor); result = -EBUSY; goto out; } out: return result; } static int gpio_close(struct inode * inode, struct file * file) { smp_mb__before_atomic_inc(); atomic_inc(&gpio_open_cnt); return 0; } struct file_operations gpio_fops = { .ioctl = gpio_ioctl, .open = gpio_open, .release = gpio_close, }; static struct miscdevice gpio_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVNAME, .fops = &gpio_fops, }; static int __init gpio_mod_init(void) { return misc_register(&gpio_dev); } static void __exit gpio_mod_exit(void) { misc_deregister(&gpio_dev); } module_init (gpio_mod_init); module_exit (gpio_mod_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Crispin / OpenWrt"); MODULE_DESCRIPTION("Character device for for generic gpio api"); Device with minor ID %d already in use\n",

Makefile ca module ny c th xy dng nh sau:


export ARCH=arm export CROSS_COMPILE=/home/arm/project/compiler/arm-2011.03/bin/arm-none-linux-gnueabiobj-m += gpio_dev.o all: make -C /home/arm/project/linux-kernel/linux-2.6.30 M=$(PWD) modules clean: make -C /home/arm/project/linux-kernel/linux-2.6.30 M=$(PWD) clean

10

Access GPIO of AT91 in Linux Embedded System

y:/home/arm/project/compiler/arm-2011.03/bin/ l ng dn ca GNU ARM toolchain cha trnh bin dch. /home/arm/project/linux-kernel/linux-2.6.30 l ng dn ca kernel linux-2.6.30 Build module: Chp gpio_dev.c v Makefile vo th mc /home/arm/project/mydrivermodule/gpio_dev . Trn mn hnh console di chuyn con tr ti th mc ny v thc hin bin dch module va mi to.
$ cd /home/arm/project/mydrivermodule/ $ make clean all //xa cc file output v build module

Sau khi build thnh cng kernel module (trn my PC Linux), ta c file gpio_dev.ko. chy c module, ta chp gpio_dev.ko vo th mc root ca SAM9260EK v thc hin cc lnh insert module vo h thng, trn mn hnh Tera pro (terminal) g lnh sau:
root@at91sam:~$ insmod gpio_dev.ko root@at91sam:~$ lsmod Module gpio_dev //insert module into kernel //list module Size Used by 2144 0

Kim tra vic insert gpio_dev.ko s dng lnh sau:


root@at91sam:~$ ls /dev/

Nu trong danh sch lit k c gpio l thnh cng.

2.2/ Vit application iu khin I/O. Vit mt chng trnh iu khin led sng 1 s v tt 1 s c source vi tn l gpioctl.c c ni dung nh sau:

11

Access GPIO of AT91 in Linux Embedded System


#include #include #include #include #include #include #include #include <string.h> <stdio.h> <stdlib.h> <unistd.h> <sys/types.h> <sys/stat.h> <fcntl.h> <linux/ioctl.h>

#include <mach/gpio.h> #define #define #define #define #define #define IOC_GPIODEV_MAGIC 'B' GPIO_GET _IO(IOC_GPIODEV_MAGIC, GPIO_SET _IO(IOC_GPIODEV_MAGIC, GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 10) 11) 12) 13) 14)

int main (int argc, char **argv) { int fd; if ((fd = open("/dev/gpio", O_RDWR)) < 0) { printf("Error whilst opening /dev/gpio\n"); return -1; } printf("Open module driver well \n"); //Setting Direction is output ioctl(fd, GPIO_DIR_OUT, AT91_PIN_PA6); ioctl(fd, GPIO_DIR_OUT, AT91_PIN_PB20); ioctl(fd, GPIO_DIR_OUT, AT91_PIN_PB21); ioctl(fd, GPIO_DIR_OUT, AT91_PIN_PB22); ioctl(fd, GPIO_DIR_OUT, AT91_PIN_PB23); //loop forever while (1) { ioctl(fd, GPIO_SET, AT91_PIN_PA6); ioctl(fd, GPIO_SET, AT91_PIN_PB20); ioctl(fd, GPIO_SET, AT91_PIN_PB21); ioctl(fd, GPIO_SET, AT91_PIN_PB22); ioctl(fd, GPIO_SET, AT91_PIN_PB23); sleep(1); //sleep 1 second ioctl(fd, GPIO_CLEAR, AT91_PIN_PA6); ioctl(fd, GPIO_CLEAR, AT91_PIN_PB20); ioctl(fd, GPIO_CLEAR, AT91_PIN_PB21); ioctl(fd, GPIO_CLEAR, AT91_PIN_PB22); ioctl(fd, GPIO_CLEAR, AT91_PIN_PB23); sleep(1); } //Close device file close(fd); return 0; }

y: <mach/gpio> l th vin ca AT91 trong th mc: /home/arm/project/mach-at91-header/include/ 12

Access GPIO of AT91 in Linux Embedded System

Makefile c ni dung nh sau:


#makefile TODO PATH_FILE=/home/arm/project/ #for C header file C_INCLUDE_PATH=$(PATH_FILE)linux-kernel/linux-2.6.30/include export C_INCLUDE_PATH=$C_INCLUDE_PATH:$(PATH_FILE)mach-at91-header/include/ #for C++ header file #CPLUS_INCLUDE_PATH=/... #export CPLUS_INCLUDE_PATH #ARM-Linux compiler ifndef CROSS_COMPILE CROSS_COMPILE=$(PATH_FILE)compiler/arm-2011.03/bin/arm-none-linux-gnueabiendif CC=$(CROSS_COMPILE)gcc STRIP=$(CROSS_COMPILE)strip gpioctl: gpioctl.o @echo 'Building target: $@' @echo 'Invoking: arm-2011.03-41-arm-none-linux-gnueabi-' $(CC) -o gpioctl *.o -lpthread $(STRIP) gpioctl @echo 'Finished building target: $@' gpioctl.o: gpioctl.c $(CC) -c gpioctl.c all: gpioctl clean: rm -rf gpioctl *.o

Build ng dng Chp 2 tp tin gpioctl.c v Makefile vo th mc /home/arm/project/application/gpioctl/ s dng lnh sau build: $ make clean all Sau khi bin dch thnh cng s sinh ra tp tin thc thi c tn l gpioctl Ch : phi c th vin nh ngha ca AT91 mach-at91-header mi build c ng dng ny. 2.3/ Thc thi ng dng: Chp gpioctl vo board SAM9260EK ri g lnh thc thi chng trnh.
root@at91sam:~$ chmod 777 gpioctl root@at91sam:~$ ./gpioctl //change permission for executing //execute

13

Access GPIO of AT91 in Linux Embedded System

III. / TRUY XUT GPIO T new DRIVER. y l mt internal driver do developer xy dng v c tch hp vo linux-2.6.xx

14

You might also like