CONTROL THE GPIO PINS ON THE DELL EMBEDDED BOX PC 3000 IN UBUNTU LINUX ABSTRACT The Dell Embedded Box PC 3000 provides General Purpose I/O (GPIO) pins for customization. Due to the unavailability of the corresponding kernel driver, users who run the Linux system on the Box PC face a problem in controlling the GPIO pins. This white paper describes how to control the GPIO pins from a user-space program through a device file.
TABLE OF CONTENTS GPIO ON EMBEDDED BOX PC 3000.......................................................................................3 USE THE I2C-I801 DRIVER ......................................................................................................4 OPEN THE INTERFACE OF I2C ADAPTER ............................................................................5 ACCESS THE GPIO CONTROLLER ........................................................................................
GPIO ON DELL EMBEDDED BOX PC 3000 The Dell Embedded Box PC 3000 provides twelve General Purpose I/O (GPIO) pins, where six of the pins are designed for output use and the other six are designed for input use. The GPIO pins are routed to the multi-function connector (standard DB44P male connector) on the back of the Embedded Box PC 3000. You can further extend the pins to the CN2 connector (standard DB25 female connector) with a multi-function cable. See Figure 1 for examples of the connectors .
The GPIO pins are implemented by the on-board GPIO expander controller chip, the TI TCA9555. It interfaces with the host processor through the two-line bidirectional I2C bus. This means it behaves as an I2C slave and has to be attached to the same bus with an I2C master. The I2C device (i.e. slave) is typically controlled by a kernel driver, but the TI TCA9555 does not have corresponding kernel drivers. If the Linux I2C subsystem supports the I2C adapter (i.e.
GRUB_HIDDEN_TIMEOUT=0 GRUB_HIDDEN_TIMEOUT_QUIET=true GRUB_TIMEOUT=10 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_enforce_resources=lax" GRUB_CMDLINE_LINUX="" # ... Figure 4 3. After the file is edited and saved, run the command “sudo update-grub” to update the GRUB configuration on the system. 4. Reboot to make the new kernel command effective. 5. After reboot, check that the error has been eliminated.
ACCESS THE GPIO CONTROLLER The TI TCA9555 provides 16 GPIO pins, with 12 connected to the Embedded PC 3000 Input and Output pins (DI0-5, DO0-5) as described in previous sections. The remaining 4 pins are unconnected. Each can be configured as an input or an output pin. The TI TCA9555 presents several couples of two 8-bit registers (i.e. 16 bits in each couple) with each couple dedicated to input, output and more.
The following source code example implements three functions to set the direction, set and read the level of a specific GPIO pin.
APPENDIX: FULL SOURCE CODE OF AN EXAMPLE PROGRAM #include #include #include #include #include #include #include #include #include
else if ( pin >= PIN_DI0 && pin <= PIN_DI5 ) chip_pin = pin - 14 + 8; return chip_pin; } // TI TCA9555: chip-specfic data #define TCA9555_REG_INPUT 0 #define TCA9555_REG_OUTPUT 2 #define TCA9555_REG_DIRECTION 6 #define GPIO_CAP_OUTPUT #define GPIO_CAP_INPUT #define GPIO_CAP_INOUT 1 2 (GPIO_CAP_OUTPUT|GPIO_CAP_INPUT) #define GPIO_MODE_UNKNOWN #define GPIO_MODE_OUTPUT #define GPIO_MODE_INPUT 0 1 2 typedef struct { int capability; int mode; } gpio_pin; typedef struct { int fd; gpio_pin pins[16]; } gpio_con
pin = map_to_chip_pin(i); gc->pins[pin].mode = GPIO_MODE_OUTPUT; // we do not allow user to change mode so restrict the pin cap to // be output only gc->pins[pin].capability = GPIO_CAP_OUTPUT; } // Pin 14~19 on connector are input pins for ( i = PIN_DI0 ; i <= PIN_DI5 ; i++ ) { pin = map_to_chip_pin(i); gc->pins[pin].mode = GPIO_MODE_INPUT; bmp_dir |= (1 << pin); // we do not allow user to change mode so restrict the pin cap to // be input only gc->pins[pin].
return rc; } if ( level ) bmp |= 1 << chip_pin; else bmp &= ~(1 << chip_pin); rc = _smbus_write_word(gc->fd, TCA9555_REG_OUTPUT, bmp); if ( rc ) { fprintf(stderr, "%s: failed to access controller\n", __FUNCTION__); return rc; } return 0; } int gpio_pin_get_level(gpio_controller *gc, int pin, int *level) { int rc, chip_pin; __u16 bmp; chip_pin = map_to_chip_pin(pin); if ( chip_pin < 0 ) { fprintf(stderr, "%s: pin number %d is invalid\n", __FUNCTION__, pin); return -EINVAL; } // We don't check the pin mode (i
int main(int argc, char** argv) { int rc, level; __u16 data; gpio_controller *epc3000_gc = gpio_initialize("Embedded PC 3000"); if ( !epc3000_gc ) { fprintf(stderr, "Failed to initialize Embedded PC 3000 GPIO controller\n"); return -1; } // Set the level of DO0 (pin 1 on connector) printf("Setting the level of DO0 to low...\n"); rc = gpio_pin_set_level(epc3000, 1, 0); if ( !rc ) printf("Successful\n"); printf("\n"); // Get the level of DI0 (pin 14 on connector) printf("Reading the level of DI0...\n"); rc =