GPIO
Esta clase se encarga de GPIO (General-purpose input/output).
GPIO es un pon genérico en un circuito integrado cuyo comportamiento, incluyendo si es un pin de entrada o de saldida, puede ser controlado por el usuario en tiempo de ejecución.
Los pines GPIO no tienen ningún proposito general definido, y no se utilizan de forma predeterminada. La idea es que a veces el un sistema completo que utiliza un chip podría encontrar útil tener algunas lineas de control digital adicionales, y tenerlas a disposición del chip puede ahorrar la molestia de tener que diseñar un circuito adicional para proporcionarselo
Esta clase esta dividad en dos ficheros, cabecera (GPIO.h) and código fuente (GPIO.cpp).
GPIO.h
Enlace al código: GPIO.h
La clase Linux::LinuxGPIO define los métodos heradados de la clase abstracta AP_HAL::GPIO. La clase Linux::LinuxDigitalSourcetambién esta definida en este fichero y hereda deAP_HAL::DigitalSource`.
For more clarity in the code: The GPIO files define C preproccesor Hexadecimal addresses and BeagleBone Black GPIO mappings in linux.
#ifndef __AP_HAL_LINUX_GPIO_H__
#define __AP_HAL_LINUX_GPIO_H__
#include <AP_HAL_Linux.h>
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define GPIO0_BASE 0x44E07000
#define GPIO1_BASE 0x4804C000
#define GPIO2_BASE 0x481AC000
#define GPIO3_BASE 0x481AE000
#define GPIO_SIZE 0x00000FFF
// OE: 0 is output, 1 is input
#define GPIO_OE 0x14d
#define GPIO_IN 0x14e
#define GPIO_OUT 0x14f
#define LED_AMBER 117
#define LED_BLUE 48
#define LED_SAFETY 61
#define SAFETY_SWITCH 116
#define LOW 0
#define HIGH 1
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_PXF || CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_ERLE
#define LINUX_GPIO_NUM_BANKS 4
#else
// disable GPIO
#define LINUX_GPIO_NUM_BANKS 0
#endif
// BeagleBone Black GPIO mappings
#define BBB_USR0 53
#define BBB_USR1 54
#define BBB_USR2 55
#define BBB_USR3 56
#define BBB_P8_3 38
#define BBB_P8_4 39
#define BBB_P8_5 34
...
#define BBB_P9_42 7
...
A raíz de la declaración:
#define identifier replacement, cuando el preprocesador se encuentra con esta directiva, se sustituye cualquier ocurrencia deindetifieren el resto de código porreplacement. Esto es lo que se hace para los identificadores en el código de abajo.Tambien contiene una declaración con el din de activar o desactivar el GPIO, dependiendo de la tarjeta especificada
...
class Linux::LinuxGPIO : public AP_HAL::GPIO {
private:
struct GPIO {
volatile uint32_t *base;
volatile uint32_t *oe;
volatile uint32_t *in;
volatile uint32_t *out;
} gpio_bank[LINUX_GPIO_NUM_BANKS];
public:
LinuxGPIO();
void init();
void pinMode(uint8_t pin, uint8_t output);
int8_t analogPinToDigitalPin(uint8_t pin);
uint8_t read(uint8_t pin);
void write(uint8_t pin, uint8_t value);
void toggle(uint8_t pin);
/* Alternative interface: */
AP_HAL::DigitalSource* channel(uint16_t n);
/* Interrupt interface: */
bool attach_interrupt(uint8_t interrupt_num, AP_HAL::Proc p,
uint8_t mode);
/* return true if USB cable is connected */
bool usb_connected(void);
};
...
- La clase
LinuxGPIOhereda de AP_HAL::GPIO.
La palabra clave
volatilees utilizado para declarar que un objeto puede ser modificado en el programa por algo como el sistema operativo, el hardware, o un thread. Aquí se definen algunos indicadores volátiles.También se define una estructura GPIO llamada
gpio_bank[], como su nombre indica, se utiliza para agrupar los pins en bancos. Puede acceder al banco por el indice.En el ámbito público: hay definido un método
init(),read()andwrite(). (estas funciones están implementadas enGPIO.cpp).Los métodos definidos dentro de
GPIO.hen la claseLinux::LinuxGPIOcomoLinuxGPIO::pinMode(),LinuxGPIO::read(),LinuxGPIO::write()y así sucesivamente, son implementados para manejar los bancos de pines GPIO de la placa.
...
class Linux::LinuxDigitalSource : public AP_HAL::DigitalSource {
public:
LinuxDigitalSource(uint8_t v);
void mode(uint8_t output);
uint8_t read();
void write(uint8_t value);
void toggle();
private:
uint8_t _v;
};
#endif // __AP_HAL_LINUX_GPIO_H__
- Define el
LinuxDigitalSourceque hereda deDigitalSource, que es parte de AP_HAL::GPIO
Los métodos definidos dentro de
gpio.hen la claseLinux :: LinuxDigitalSource, se han aplicado aquí para administrar fuentes digitales.Algunos métodos se definen aquí, para posteriormente implementarlos en
GPIO.cpp.
GPIO.cpp
GPIO.cpp implementa los métodos definidos en GPIO.h.
El método más importante es init() que habilita todos los bancos GPIO, abra el directorio /sys/class/gpio/export, y mapeo los bancos GPIO en /dev/mem.
#include <AP_HAL.h>
#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
#include "GPIO.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/mman.h>
#include <sys/stat.h>
...
- En este fragmento de código
AP_HAL.hyGPIO.hestán incluidos y la placa esta definida.
Algunas funciones y librerias están incluidas:
Trata con las operaciones de entrada y salida: gestión de archivos, lectura, escritura... - (stdio.h)
Esta cabecera define varias funciones de propósito general, incluyendo la gestión dinámica de memoria, generación de numeros aleatorios, la comunicación con el entorno, aritmética de enteros, búsqueda, clasificación...- (stdlib.h)
El archico de cabeceras
string.hdefine varias funciones para manipular string de C y arrays. - (string.h)
- Cabecera de C que define la siguiente macro:
errno->Last error number (macro ); al menos 3 macros constantes adicionales: EDOM, ERANGE and EILSEQ. (see errno para más detalles). - (errno.h)
Esta cabecera denife constantes y tipos y declara funciones auxiliares. Es proporcionado por POSIX (Portable Operating System Interface-calls to the OS) - Sistemas compatibles.- (unistd.h)
La cabecera
fcntl.hdefine varias solicitudes y argumentos para el uso de las funcionesfcntl()andopen(). - (fcntl.h)La cabecera
poll.hdefine la estructurapollfdque incluye al menos los siguientes miembros: int fd(the following descriptor being polled), short int events (the input event flags) and short int revents ( the output event flags) - (poll.h)La cabecera
sys/mman.hdefine las opciones de protección cuando hay consultas, archivos asignados en memoria, o objetos en memoria compartida compatibles con opciones son soportados- (sys/mman.h)La cabecera
sys/stat.hdefine la esructura de los datos devueltos por las funcionesfstat(),lstat(), andstat(). - (sys/stat.h)
...
using namespace Linux;
static const AP_HAL::HAL& hal = AP_HAL_BOARD_DRIVER;
LinuxGPIO::LinuxGPIO()
{}
...
- Begins a namespace definition, takes the
AP_HAL::HAL& halvalue and callLinuxGPIO()funtion that manage pin banks.
...
void LinuxGPIO::init()
{
#if LINUX_GPIO_NUM_BANKS == 4
int mem_fd;
// Enable all GPIO banks
// Without this, access to deactivated banks (i.e. those with no clock source set up) will (logically) fail with SIGBUS
// Idea taken from https://groups.google.com/forum/#!msg/beagleboard/OYFp4EXawiI/Mq6s3sg14HoJ
uint8_t bank_enable[3] = { 5, 65, 105 };
int export_fd = open("/sys/class/gpio/export", O_WRONLY);
if (export_fd == -1) {
hal.scheduler->panic("unable to open /sys/class/gpio/export");
}
for (uint8_t i=0; i<3; i++) {
dprintf(export_fd, "%u\n", (unsigned)bank_enable[i]);
}
close(export_fd);
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
off_t offsets[LINUX_GPIO_NUM_BANKS] = { GPIO0_BASE, GPIO1_BASE, GPIO2_BASE, GPIO3_BASE };
for (uint8_t i=0; i<LINUX_GPIO_NUM_BANKS; i++) {
gpio_bank[i].base = (volatile unsigned *)mmap(0, GPIO_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, offsets[i]);
if ((char *)gpio_bank[i].base == MAP_FAILED) {
hal.scheduler->panic("unable to map GPIO bank");
}
gpio_bank[i].oe = gpio_bank[i].base + GPIO_OE;
gpio_bank[i].in = gpio_bank[i].base + GPIO_IN;
gpio_bank[i].out = gpio_bank[i].base + GPIO_OUT;
}
close(mem_fd);
#endif // LINUX_GPIO_NUM_BANKS
}
...
Habilitar todos bancos GPIO (creación de los bancos):
En primer lugar, intenta abrir el archivo
/sys/class/gpio/export: si falla imprimir un mensahe, si no imprime el contenido.Abre
/dev/mem.
off_tes un tipo usado para offset a varios funciones de archivos relacionados. Con esto activamos los bancos de GPIO, asignandolos en/dev/mem.
...
void LinuxGPIO::pinMode(uint8_t pin, uint8_t output)
{
uint8_t bank = pin/32;
uint8_t bankpin = pin & 0x1F;
if (bank >= LINUX_GPIO_NUM_BANKS) {
return;
}
if (output == HAL_GPIO_INPUT) {
*gpio_bank[bank].oe |= (1U<<bankpin);
} else {
*gpio_bank[bank].oe &= ~(1U<<bankpin);
}
}
int8_t LinuxGPIO::analogPinToDigitalPin(uint8_t pin)
{
return -1;
}
...
- Check the bank numbers and the output. Note the use of 1U for the left shift, to make it unsigned and the allocation using binary asigments.
- The return -1 is like a return boolean=False.
...
uint8_t LinuxGPIO::read(uint8_t pin) {
uint8_t bank = pin/32;
uint8_t bankpin = pin & 0x1F;
if (bank >= LINUX_GPIO_NUM_BANKS) {
return 0;
}
return *gpio_bank[bank].in & (1U<<bankpin) ? HIGH : LOW;
}
void LinuxGPIO::write(uint8_t pin, uint8_t value)
{
uint8_t bank = pin/32;
uint8_t bankpin = pin & 0x1F;
if (bank >= LINUX_GPIO_NUM_BANKS) {
return;
}
if (value == LOW) {
*gpio_bank[bank].out &= ~(1U<<bankpin);
} else {
*gpio_bank[bank].out |= 1U<<bankpin;
}
}
...
- Similarly to
pinmode()actsread()andwrite().
...
void LinuxGPIO::toggle(uint8_t pin)
{
write(pin, !read(pin));
}
/* Alternative interface: */
AP_HAL::DigitalSource* LinuxGPIO::channel(uint16_t n) {
return new LinuxDigitalSource(n);
}
/* Interrupt interface: */
bool LinuxGPIO::attach_interrupt(uint8_t interrupt_num, AP_HAL::Proc p, uint8_t mode)
{
return true;
}
bool LinuxGPIO::usb_connected(void)
{
return false;
}
LinuxDigitalSource::LinuxDigitalSource(uint8_t v) :
_v(v)
{
}
void LinuxDigitalSource::mode(uint8_t output)
{
hal.gpio->pinMode(_v, output);
}
uint8_t LinuxDigitalSource::read()
{
return hal.gpio->read(_v);
}
void LinuxDigitalSource::write(uint8_t value)
{
return hal.gpio->write(_v,value);
}
void LinuxDigitalSource::toggle()
{
write(!read());
}
#endif // CONFIG_HAL_BOARD
- Aquí las funciones que faltan se implementan.