Difference between revisions of "Using the EMAC GPIO Class"

From wiki.emacinc.com
Jump to: navigation, search
m (Approved for Final Draft)
Line 1: Line 1:
{{todo|List related hardware eventually; (12.17.13-18:20->KY+);(12.18.13-19:00->MD+)|Klint Youngmeyer|project=oe 4, oe 5,mw,ky,FinalDraft,md}}
+
{{todo|List related hardware eventually; (12.17.13-18:20->KY+);(12.18.13-19:00->MD+);(12.19.13-11:21->MW+)|Klint Youngmeyer|project=oe 4, oe 5,mw,ky,Complete,md}}
  
 
The EMAC GPIO Class is a generic programming interface for General Purpose Input Output (GPIO) devices in the Linux Kernel. The GPIO class driver has two main interfaces under standard Linux: Linux sysfs and character device. The GPIO class is extremely flexible and uses a set of function pointers at the kernel level to allow for specialized read/write functions for each device. EMAC utilizes the GPIO class to create devices that use the same simple interface, such as GPIO registers, simple configuration variables, hardware registers, and Analog-to-Digital converter drivers where the user needs to retrieve a single value from the device.
 
The EMAC GPIO Class is a generic programming interface for General Purpose Input Output (GPIO) devices in the Linux Kernel. The GPIO class driver has two main interfaces under standard Linux: Linux sysfs and character device. The GPIO class is extremely flexible and uses a set of function pointers at the kernel level to allow for specialized read/write functions for each device. EMAC utilizes the GPIO class to create devices that use the same simple interface, such as GPIO registers, simple configuration variables, hardware registers, and Analog-to-Digital converter drivers where the user needs to retrieve a single value from the device.

Revision as of 11:22, 19 December 2013

TODO: {{#todo:List related hardware eventually; (12.17.13-18:20->KY+);(12.18.13-19:00->MD+);(12.19.13-11:21->MW+)|Klint Youngmeyer|oe 4, oe 5,mw,ky,Complete,md}}

The EMAC GPIO Class is a generic programming interface for General Purpose Input Output (GPIO) devices in the Linux Kernel. The GPIO class driver has two main interfaces under standard Linux: Linux sysfs and character device. The GPIO class is extremely flexible and uses a set of function pointers at the kernel level to allow for specialized read/write functions for each device. EMAC utilizes the GPIO class to create devices that use the same simple interface, such as GPIO registers, simple configuration variables, hardware registers, and Analog-to-Digital converter drivers where the user needs to retrieve a single value from the device.

Supported Devices

Most of EMAC's ARM based SOM-Carrier combinations and some of EMAC's x86 boards support the EMAC GPIO Class. For a list of GPIOs on each device, please see the EMAC website at emacinc.com/products/system_on_module.


Components

An EMAC GPIO Class Device has three main components. A clear understanding of these components is important for proper use and implementation.

Data

The data member of a GPIO device is the primary component. In the most simple devices, this is the only component accessible from userspace. The data member is read and/or written to access or set the current value of the GPIO device. The actual function of the data member is implementation specific. For a GPIO device in its purest form, such as the GPIO ports present in many of EMAC's CPLD designs, the data member is a register value with each of the 8 least significant bits representing the digital state of a single line in the GPIO port. In contrast, A/D devices implemented with the EMAC GPIO Class will typically provide the analog value of the currently selected channel in the data member.

The data member is allocated as a 32-bit unsigned integer regardless of implementation. Many devices use only the least significant byte or the least significant bit.

Data Code Example:

#include "gpio_char.h"

int fd_out, fd_in;
int data;
int output = 42;

//Open device "/dev/portc" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_out = open("/dev/portc", O_RDWR)) <= 0){
    printf("couldn't open /dev/portc\n");return -1;
}
//This will write the contents of the variable 'output' to /dev/portc
if (ioctl(fd_out, DATAWRITE, &output)<0){
    return -1;
}

//Open device "/dev/portb" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_out = open("/dev/portb", O_RDWR)) <= 0){
    printf("couldn't open /dev/portb\n");return -1;
}
//This will read the digital value of /dev/portb to the the variable 'data' 
if (ioctl(fd_out, DATAREAD, &data)<0)
{
    return -1;
}

DDR

The ddr or Data Direction Register is a member of the EMAC GPIO Class that is used primarily for direction-configurable GPIO devices. Many devices do not register this aspect of the interface. The ddr member is used to determine if a particular device should act as an input or output. Depending on the implementation, many devices are bit-configurable GPIO devices, meaning that each bit/line in the GPIO device can be configured as an input or output by its respective value in the ddr. Typically, a '1' value in the ddr configures the device as an output and a '0' value in the ddr configures the device as an input. Bidirectional GPIO devices are generally configured as inputs by default until explicitly configured as an output to prevent hardware contention.

For example, an EMAC GPIO Class device porta is a one-byte bit-configurable bidirectional GPIO device. Each bit in the data register corresponds to the digital status of the corresponding line porta[0-7]. On reset, the ddr member is read at 0x00, indicating that the device is configured with all lines as inputs. If the ddr member is set to 0xAA (binary 1010 1010) bits 0, 2, 4, and 6 will remain configured as inputs while the rest of the bits will be configured as outputs. Reading and setting the value in the data member will react according to the configuration set in the ddr. The ddr is allocated as a 32-bit unsigned integer regardless of implementation.

DDR Code Example:

#include "gpio_char.h"

int fd_out, fd_in;
int input = 0x00;
int output = 0xff;

//Open device "/dev/portc" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_out = open("/dev/portc", O_RDWR)) <= 0){
    printf("couldn't open /dev/portc\n");return -1;
}
//This will set the data direction of /dev/portc to all outputs as denoted by output=0xff
if (ioctl(fd_out, DDRWRITE, &output)<0)
{
    return -1;
}

//Open device "/dev/portb" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_in = open("/dev/portb", O_RDWR)) <= 0){
    printf("couldn't open /dev/portb\n");return -1;
}
//This will set the data direction of /dev/portb to all inputs as denoted by input=0x00
if (ioctl(fd_out, DDRWRITE, &input)<0)
{
    return -1;
}

Index

Many EMAC GPIO Class devices are implemented as indexed GPIO Devices. These devices utilize a member named index which impacts the device according to the implementation. The index member is typically used to specify a memory offset from some base for the data member or some type of channel setting or controller selection. Many devices ignore the index value or do not register this member at all.

An example of an indexed GPIO Class device is the indexed_atod device (and other A/D devices) found on many EMAC boards. In this case, the index member is used to set the current channel of the A/D to read from the data member. When the index is set to 0, channel 0 will be accessed. When the index is set to 3, the data register will reflect the current value on channel 3 of the device. Another example would be two identical counter registers in a device where setting the index would control which counter was accessed when reading the data register. This would be an alternative to registering a separate device for each counter.

Indexed GPIO devices should check the applicable range for the index when the user attempts to set the device. For example, an 8-channel A/D device implemented as an EMAC GPIO Class device would have a valid range for the index member of 0-7. Attempting to set the index to anything greater than 7 would cause the index to be set to the maximum allowed value of 7.

Index Code Example:

#include "gpio_char.h"

int fd_out, fd_in;
int index_c = 1;
int index_b;

//Open device "/dev/portc" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_out = open("/dev/portc", O_RDWR)) <= 0){
    printf("couldn't open  /dev/portc\n");return -1;
}
//This will set the AtoD index for /dev/portc
if (ioctl(fd_out, INDEXWRITE, &index_c)<0)
{
    fprintf(stderr,"error setting index: %s\n", strerror(errno));
    return -1;
}

//Open device "/dev/portb" for reading and writing
//Note that this operation uses the 'open()' Linux system call rather than 'fopen()'
if ((fd_out = open("/dev/portb", O_RDWR)) <= 0){
    printf("couldn't open /dev/portb\n");return -1;
}
//This will read the AtoD index for /dev/portb into index_b
if (ioctl(fd_out, INDEXREAD, &index_b)<0)
{
    fprintf(stderr,"error reading index: %s\n", strerror(errno));
    return -1;
}