GPIO Driver
On this page, you will find all the informations needed to use the Armadeus GPIO driver.
Contents
Compilation
Done by default starting from Armadeus-3.0 release. See Talk:GPIO_Driver to know how.
Installation
When compiled, you will have 2 modules:
- gpio: this is the main driver. It should be loaded first and will allow you to easily control GPIO pins from user space,
- ppdev: this is an extension driver to add PPDEV emulation to gpio.ko. This way you will be able to emulate a standard parallel port on one GPIO port (to connect a textual LCD, for example).
Note: The parallel port driver (ppdev) will only work on APF9328 based systems ! |
Loading driver
# /usr/bin/loadgpio.sh
or look inside this script if you want to manually enter the module parameters:
# modprobe gpio portB_init=0,0,0x00FFFF00,0,0,0,0,0,0x0FF00000,0,0,0,0,0,0,0x0FF00000
gpio module parameters are values for PORTA, PORTB, PORTC, PORTD configuration registers in following order:
DDIR, OCR1, OCR2, ICONFA1, ICONFA2, ICONFB1, ICONFB2, DR, GIUS, SSR, ICR1, ICR2, IMR, GPR, SWR, PUEN,
Driver usage
Directly with shell commands (through /proc & /dev filesystem)
GPIO driver is configurable through /proc interface:
- use /proc/drivers/gpio/portXmode to configure a pin as a gpio (with echo) and where X is your port name: A, B, C or D (E,F for apf27)
- use /proc/drivers/gpio/portXdir to read (with cat) or set (with echo) pin direction (where X is your port name)
- then use /proc/drivers/gpio/portX to read (with cat) or write (with echo) pin status
- /proc/drivers/gpio/portXirq: configure if GPIO should be used as an interruptible one (ie blocking read)
- /proc/drivers/gpio/portXpullup: (de)activate i.MXL internal pull-up for that GPIO
Examples:
- Configure IO-Pin 31 of port A (LCD_OE_ACD on the APF27) as gpio
# echo -n 10000000000000000000000000000000 > /proc/driver/gpio/portAmode
- See which IO-Pins of PortD are configured as inputs, and which one are outputs ('1' = output, '0' = input):
# cat /proc/driver/gpio/portDdir 01101100111100000110110011110000 pins order: [31...0] #
- Configure the IO-Pins 30, 28, 23, 22 and 21 of PortB as outputs ('1'), all others as inputs ('0'):
# echo -n 01010000111000000000000000000000 > /proc/driver/gpio/portBdir
- Read the status/values of the IOs of PortB:
# cat /proc/driver/gpio/portB 00000000000011111111000000000000 #
- Set bits 30, 28 and 23 of PortB to '1', all other outputs to '0': <-- DEPRECATED, use /dev/gpio/ instead !
# echo -n 01010000100000000000000000000000 > /proc/driver/gpio/portB
- Blinks the LED on DevFull (pin 31 of portD):
# cat /proc/driver/gpio/portDdir | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDmode # cat /proc/driver/gpio/portDdir | sed "s/[0-1]\([0-1]\{31\}\)$/1\1/" > /proc/driver/gpio/portDdir # echo -ne "\x00" > /dev/gpio/PD31 # echo -ne "\x01" > /dev/gpio/PD31
- Sets only bit 5 of portADir to 1:
# cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''1'''\1/" > /proc/driver/gpio/portAdir
- Sets only bit 5 of portADir to 0:
# cat /proc/driver/gpio/portAdir | sed "s/[0-1]\([0-1]\{'''5'''\}\)$/'''0'''\1/" > /proc/driver/gpio/portAdir
- You can put it in a shell function:
setbit() { PORT=$1 NB=$2 VAL=$3 cat $PORT | sed "s/[0-1]\([0-1]\{$NB\}\)$/$VAL\1/" > $PORT } # setbit /proc/driver/gpio/portAdir 5 0
- Blocking read on the PortD pin 0:
# cat /dev/gpio/PD0
Directly with C program ( /proc filesystem)
After inserting the GPIO module, /proc entries are created in the filesystem, and so it's possible to directly use some Linux standard functions inside a C program, such as:
- fopen
- fwrite
- fread
- fclose
A little piece of code is the best way to understand quickly:
int i;
unsigned char dummy;
FILE *GPIO,*GPIODIR, *GPIOMODE;
char buffer[32];
char * bufferMode="00000000011111111000000000000000";
char * bufferDir= "00000000011111111000000000000000";
char * buffer1= "00000000000000011000000000000000";
char * buffer2= "00000000000001100000000000000000";
char * buffer3= "00000000000110000000000000000000";
char * buffer4= "00000000011000000000000000000000";
GPIOMODE = fopen("/proc/driver/gpio/portDmode","w");
setvbuf(GPIOMODE,buffer,_IONBF,32);
fwrite(bufferMode, sizeof(char), strlen(bufferMode), GPIOMODE);
fclose(GPIOMODE);
GPIODIR = fopen("/proc/driver/gpio/portDdir","w");
setvbuf(GPIODIR,buffer,_IONBF,32);
fwrite(bufferDir, sizeof(char), strlen(bufferDir), GPIODIR);
fclose(GPIODIR);
GPIO = fopen("/proc/driver/gpio/portD","w");
setvbuf(GPIO,buffer,_IONBF,32);
while(1) {
fwrite(buffer1, sizeof(char), strlen(buffer1), GPIO);
sleep(1);
fwrite(buffer2, sizeof(char), strlen(buffer2), GPIO);
sleep(1);
fwrite(buffer3, sizeof(char), strlen(buffer3), GPIO);
sleep(1);
fwrite(buffer4, sizeof(char), strlen(buffer4), GPIO);
sleep(1);
}
fclose(GPIO);
return (0);
Directly from a C program with IOCTLs
There is another way to drive GPIO module: with IOCTLs on the right device node. ioctl() function is using flags to say what it must be done (read and write):
- GPIORDDIRECTION for reading direction of the concerned port
- GPIOWRDIRECTION for writing direction of the concerned port
- GPIORDDATA for reading data of the concerned port
- GPIOWRDATA for writing data of the concerned port
An example of code will give more explanation:
int fd;
int i;
int iomask,result;
unsigned char dev_buffer[BUF_SIZE+1];
if ((fd = open("/dev/gpio/portD", O_RDWR))<0) {
printf("Open error on /dev/gpio/portD\n");
exit(0);
}
printf("Opened on /dev/gpio/portD\n");
iomask=0xFFFFFF00;
ioctl(fd,GPIOWRDIRECTION,&iomask);
iomask=0x003F0000;
for (i=0;i<2;i++) {
printf("Led ON\n");
iomask=0x007F8000;
ioctl(fd,GPIOWRDATA,&iomask);
sleep(1);
ioctl(fd,GPIORDDATA,&iomask);
printf("read /dev/gpio/portD 0x%x\n",iomask);
printf("Led OFF\n");
iomask=0x00000000;
ioctl(fd,GPIOWRDATA,&iomask);
sleep(1);
}
close(fd);
exit(0);
Of course you'll need to declare in the include part, the following:
- sys/ioctl.h
- linux/ppdev.h
and define pragmas such as:
- GPIORDDIRECTION _IOR(PP_IOCTL, 0xF0, int)
- GPIOWRDIRECTION _IOW(PP_IOCTL, 0xF1, int)
- GPIORDDATA _IOR(PP_IOCTL, 0xF2, int)
- GPIOWRDATA _IOW(PP_IOCTL, 0xF3, int)