Controle de GPIO da Raspberry Pi utilizando a linguagem C

Confira todos os pontos em uma configuração dos pinos de GPIO da Raspberry Pi e como o Sistema Operacional se porta perante estas configurações.
GPIO da Raspberry Pi

Então pessoal, quando comecei a desenvolver soluções envolvendo sistemas embarcados, enfrentei muitas dificuldades para utilizar os recursos que a Raspberry Pi possui, trabalhando com códigos de baixo nível que permitem um maior controle sobre suas funcionalidades computacionais,  como por exemplo a linguagem C.

Dessa forma, pensei em utilizar este aspecto como motivação para produzir este artigo, detalhando todos os pontos em uma configuração dos pinos de GPIO da Raspberry Pi, como o Sistema Operacional se porta perante estas configurações, para que seu desenvolvimento tenha um salto de qualidade e que essas dificuldades impostas ao se trabalhar com um sistema embarcado utilizando linguagens de baixo nível sejam solucionadas.

Relato também que este tema já foi abordado nos artigos Raspberry PI – GPIO input com Python e Raspberry PI – GPIO output com Python, mas a linguagem utilizada em ambos foi Python. Portanto, a construção de um material contendo este assunto é muito importante, visto que podemos efetuar um comparativo entre os benefícios que o desenvolvimento de aplicações envolvendo Python ou C podem proporcionar respeitando as características de projeto, mas este assunto fica para um próximo artigo.

Antes de começarmos a desenvolver os códigos, primeiramente precisamos instalar a imagem do S.O operacional desejado. Para executar este procedimento, disponibilizamos em nosso banco de artigos o material Como instalar o Raspbian na Raspberry? que pode ser utilizado como consulta visto que o S.O presente neste projeto foi o Raspbian.

(Nota: Encaminhamos também para consulta o material postado nesta página que ilustra o procedimento de como o cartão deverá ser gravado).

Caso não conheça a Raspberry Pi, recomendamos ler o artigo Raspberry Pi. Se já possui um conhecimento desta plataforma mas não é muito familiarizado com Linux, o artigo Raspberry Pi e o Linux irá proporcionar uma excelente base sobre os dois assuntos.

Configurações do ambiente

  • Board: Raspberry Pi 3 model B
  • Distribuição: Raspbian GNU/Linux – Jessie (2016-09-23)
  • Kernel 4.4.26-v7+
  • gcc (Raspbian 4.9.2-10) 4.9.2

GPIO

GPIO (General Purpose Input/Output) é o termo utilizado para o controle de todo pino que possui as funcionalidades gerais de entrada e saída e não possui atribuições dedicadas, ou seja, todo pino que possibilita a configuração como entrada ou saída pode ser classificado como pino de GPIO desde que não possua características funcionais dedicadas.

Estes pinos podem ser configurados como saída (estado lógico alto – 1 ou baixo – 0) ou como entrada utilizado na leitura de push buttons por exemplo.

Controlando os pinos de GPIO

Primeiramente, para controlar os pinos de GPIO de qualquer microcontrolador, precisamos necessariamente saber qual é o seu impacto quando tentamos controlar o mesmo na presença de um Sistema Operacional portado no processador do dispositivo.

Em processadores de alto desempenho, que possuem um sistema operacional, esta ação de controle é submetida ao kernel, ou seja, o kernel que se comunica diretamente com o hardware e os softwares do espaço de usuário possuem apenas um subconjunto de instruções de máquina. Dessa forma, para que um programa que está no espaço de usuário poder ter acesso ao hardware, é necessário que o kernel permita essas operações.

Quando estamos tratando das configurações dos pinos de GPIO da Raspberry Pi, onde o programa do espaço de usuário necessita da permissão de controle dos pinos de GPIO, existem várias bibliotecas que permitem esse controle. Neste documento iremos utilizar a sysfs, que proporciona um controle maior relacionado à manipulação dos arquivos presentes na estrutura de diretórios do S.O.

SYSFS

O Sysfs possui a capacidade de permitir ao código do kernel a exportação das informações necessárias para o controle dos periféricos do espaço de núcleo ao espaço do usuário em um sistema de arquivos em memória, que nos possibilita a manipulação do hardware no espaço do usuário mesmo com a presença do sistema operacional. Esta ação simplesmente nos proporciona uma interatividade entre nossa aplicação e o hardware, trabalhando apenas com arquivos, links simbólicos e diretórios.

Dessa forma, este recurso torna o processo de controle amigável ao desenvolvedor, visto que para o controle dos periféricos é necessário trabalhar apenas com arquivos e suas derivações em conjunto com uma linguagem que possua essas propriedades de manipulação de arquivos.

Estrutura de diretórios do SYSFS

Sysfs é uma simples coleção de diretórios, arquivos e links simbólicos, que permitem a navegação e manipulação utilizando simples comandos shell.

A Figura 1 ilustra a estrutura dos subdiretórios presentes no sysfs:  

Estrutura de diretórios sysfs
Figura 1 – Estrutura de diretórios sysfs

Adicionalmente, encaminhamos abaixo, a critério introdutório, os diretórios em conjunto com suas especificações técnicas. Como nosso foco está direcionado apenas com as funcionalidades ligadas ao diretório /sys/class/gpio, qualquer dúvida a respeito deverá ser consultada nesta página.

  • block: Este diretório possui subdiretórios para cada dispositivo do sistema. Em cada diretório, são descritos os atributos que descrevem as características dos dispositivos.
  • bus: Possui um layout com os vários tipos de barramento do kernel presentes no processador. Cada subdiretório que representa a forma de barramento utilizada, possui dois subdiretórios:
    • devices
      • Conjunto de links simbólicos para cada device encontrado no sistema.  
    • drivers
      • Possui os drivers para cada dispositivo presente no barramento utilizado.
  • class: Diretório que contém as representações de cada dispositivo conhecidas pelo kernel.
  • devices: Contém um sistema de arquivos que representa uma árvore de dispositivos.
  • firmware: Possui as interfaces de visualização e manipulação de atributos e objetos específicos do firmware.
  • module: É o diretório que contém os subdiretórios para cada módulo do kernel.

Diretório /sys/class/gpio/

Este diretório possui três tipos de entrada:

  • Interfaces de controle usadas para permitir ao espaço de usuário o controle do pino de GPIO;
  • GPIOs;
  • Instâncias de Controle do GPIO.

Visando ilustrar como é disposta a estrutura de diretório após a exportação do controle do GPIO para o espaço de usuário, considere a Figura 2.

Estrutura do diretório /sys/class/gpio/
Figura 2 – Estrutura do diretório /sys/class/gpio/

Inicialmente, para que possamos controlar um pino de GPIO, necessariamente precisamos fazer com que este controle feito no espaço de núcleo seja exportado para o espaço de usuário. Esta interface de controle irá permitir que um programa situado no espaço de usuário solicite ao kernel o controle do GPIO e de suas propriedades:

  • export: O programa no espaço de usuário solicita ao kernel o controle do GPIO no espaço de usuário.
  • unexport: Reverte as ações efetuadas pelo export.    

Após a exportação do pino, precisamos definir como o mesmo deverá trabalhar, se será como OUTPUT ou INPUT através do arquivo direction. Através do arquivo value, é possível realizar a leitura ou escrita no pino de acordo com as configurações definidas no método direction. O arquivo edge nos permite verificar se a tensão sofreu uma borda de subida, descida ou ambas, já o método active_low, permite a inversão dos níveis lógicos de leitura e/ou gravação.

Código

Como mencionado anteriormente, todo o código foi desenvolvido em C e devido à sua extensão, ficou inviável a disponibilização do mesmo no corpo deste artigo.

Sendo assim, iremos citar os principais pontos necessários para configuração de um pino GPIO utilizando a biblioteca sysfs, desde o export do pino até o unexport, onde o controle do pino é liberado do espaço de usuário.

Por fim, disponibilizamos os arquivos fonte no github caso queiram utilizar o código desenvolvido para efetuar testes.

Exportando o pino

Antes mesmo de realizar as configurações dos pinos como entrada/saída, é necessário solicitar ao kernel a permissão de controle do pino desejado a nível de usuário, ou seja, é exportado o controle do pino para o espaço de usuário do sistema.

Após a exportação ser concluída, os pinos estarão disponíveis para serem utilizados e configurados.

Segue abaixo o exemplo de código desenvolvido em C que realiza a exportação do pino:

Configurando o pino como INPUT ou OUTPUT

Após a exportação do pino para o controle no espaço do usuário, o pino está pronto para ser configurado. Dessa forma, é necessário informar que tipo de configuração o pino deverá trabalhar, ou seja, se sua direção deverá ser configurada como INPUT ou OUTPUT.

Para ilustrar este processo, o código abaixo detalha a configuração da direção do pino:

Efetuando a leitura

Quando o pino é configurado como INPUT, é possível realizar a leitura de valores 0V – baixo e 3,3V – alto de acordo com a configuração utilizada. Neste artigo utilizamos resistores de Pull-Up na entrada da porta, ou seja, sempre quando o botão estiver pressionado, o sinal baixo será injetado no pino, caso contrário permanecerá em estado alto.

Este processo de leitura está ilustrado no código abaixo:  

Escrita no pino

Quando o pino está configurado como OUTPUT, é possível efetuar a escrita dos valores zero e um na porta de acordo com a funcionalidade desejada, ou a atuação sobre determinada aquisição de sinal.

Este processo de escrita no pino, está ilustrado no código abaixo:

Unexport do pino

Por fim, após a desutilização do pino exportado, visando evitar que o mesmo esteja consumindo recursos da placa e do S.O, sempre é necessário que um unexport seja aplicado.

Para ilustrar esta ação, encaminhamos o código abaixo:

Esquema de ligação

Neste tópico, será descrito os esquemas de ligação dos circuitos utilizados para simular o código desenvolvido e serão divididos em duas partes, a parte que representa a configuração do pino de GPIO como OUTPUT e a outra como INPUT.

Ligação do pino de GPIO24 como OUTPUT:

Neste cenário, foi utilizado um resistor de 680 Ohms, com o objetivo de limitar a corrente em aproximadamente 20 mA para proteção do led.

GPIO24 como output
Figura 3 – GPIO24 como output

 

Ligação do pino de GPIO24 como INPUT:

Neste cenário, foi adotado um resistor de PULL-UP de 560 Ohms com o objetivo de limitar a corrente no pino em no máximo 6mA.

Com a utilização desta configuração, quando o botão estiver pressionado, o GPIO24 receberá um sinal comum do GND (0 V – baixo), caso contrário (botão não pressionado), o pino receberá o sinal do VCC (3,3 V – alto).

Resistor de pull up configurando o GPIO24 como input
Figura 4 – Resistor de pull up configurando o GPIO24 como input

Operação equivalente no terminal

Com o objetivo de ilustrar todas as operações descritas anteriormente de uma forma mais palpável, desde o export do pino até o seu unexport, a Figura 5 exemplifica todos as ações realizadas através de comandos shell:

Comando no terminal
Figura 5 – Comando no terminal
  1. O GPIO24 é exportado para o controle no espaço de usuário.
  2. A direção do GPIO24 é configurada como saída.
  3. É escrito no pino de GPIO24 os valores alto e baixo exemplificando um led alternando seu status de aceso  para apagado.
  4. Listagem da estrutura de diretórios presentes no controle de GPIO, com o intuito de ilustrar que o pino GPIO24 ainda encontra-se disponível para uso.
  5. O GPIO24 é liberado após a utilização do pino, ou seja, o unexport é aplicado ao mesmo.
  6. Após a liberação do pino, são listados os arquivos visando exemplificar que o pino de GPIO24 não está mais disponível para uso.  

Código disponível no github

Informamos que os códigos completos para a configuração dos pinos de GPIO como INPUT/OUTPUT estão disponíveis em leal-freitas para utilização.

Relatamos também que este código foi homologado na Raspberry Pi 3 model B, portanto as macros de definição dos pinos de GPIO precisam ser configuradas de acordo com as características do modelo da placa utilizado.

Conclusão

Com o desenvolvimento deste artigo, ficou claro o quão poderosa é a biblioteca sysfs, que nos permite exportar informações do espaço de núcleo ao espaço do usuário aliada a qualquer linguagem que possuem as propriedades de manipulação dos arquivos, permitindo assim a interação entre o software/firmware presente no espaço do usuário e o hardware de uma forma amigável visto que trabalhar com arquivos, links simbólicos e diretórios são bem acessíveis para os desenvolvedores.

Também ficou evidente com este trabalho que ao utilizar linguagens de baixo nível, as mesmas nos permitem e proporcionam um maior controle sobre os periféricos evitando assim, dependências de funções terceiras.

Aprenda Mais

PWM na Raspberry Pi com Python

RFID com Raspberry Pi e Python

Enviando temperatura dos núcleos da Raspberry Pi 3 para o ThingSpeak em C

Referências

GPIO Sysfs Interface for Userspace

GPIO

RPi GPIO Code Samples

GPIO with sysfs on a Raspberry Pi

GPIO: RASPBERRY PI MODELS A AND B

INSTALLING OPERATING SYSTEM IMAGES ON LINUX

The sysfs Filesystem

Sou Engenheiro Eletricista formado pela PUCPR e atualmente aluno de especialização em Sistemas Embarcados na Universidade Positivo, tenho como paixão o desenvolvimento de soluções voltadas a automação residencial utilizando sistemas embarcados. Possuo interesse em aplicar medidas embarcadas em ambientes residências envolvendo o conceito de IoE.

5 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
francis DAVID
francis DAVID
09/10/2017 18:16

Testei exportar a gpio usando o fopen e não foi possível, mesmo como root.
Tem alguma limitacao?

Ciro Peixoto
Ciro Peixoto
19/12/2016 07:53

Show de bola!!!! Parabéns pelo artigo!!

André Freitas
André Freitas
Reply to  Ciro Peixoto
19/12/2016 11:23

Ciro, muito obrigado!

Fabio_Souza_Embarcados
Fabio_Souza_Embarcados
14/12/2016 07:16

André, parabéns pelo artigo!

André Freitas
André Freitas
Reply to  Fabio_Souza_Embarcados
19/12/2016 11:22

Fabio, muito obrigado!

WEBINAR

Imagens de Ultrassom: Princípios e Aplicações

DATA: 26/10 ÀS 19:30 H