Amber board, gestione GPIO.

Click Here to Read the English version.

Una delle esigenze più comuni degli sviluppatori che realizzano un apparati elettronici è quella di gestire le uscite e gli ingressi digitali per attivare interruttori, acquisire lo stato di uno o più pulsanti o in generale interagire con altre periferiche per mezzo delle linee digitali d I/O (GPIO) messe a disposizione dai dispositivi utilizzati. Controllare da codice lo stato o il livello di un pin del microprocessore è una delle prime cose che si imparano quando si lavora con il codice e credo che la quasi totalità degli sviluppatori abbia almeno una volta nella loro vita realizzato il classico progetto del LED che lampeggia o della classica sequenza di luci che si accende in modalità “super-car”.
Quando si lavora con il firmware è infatti abbastanza semplice scrivere o leggere lo stato di un pin del proprio dispositivo; per compiere questa semplice operazione, il più delle volte è sufficiente scrivere o leggere un bit nel registro di I/O dedicato o aspettare lo scatenarsi del relativo interrupt se opportunamente configurato.
Cosa succede e nel nostro sistema gira un sistema operativo evoluto tipo Linux?
Possiamo ancora accedere alle linee di I/O della nostra CPU direttamente dalla nostra applicazione utente?
La risposta è ovviamente affermativa anche se la modalità può dipende dal sistema che stiamo utilizzando e dalla sua configurazione. In generale possiamo controllare e accedere allo stato dei GPIO ma dobbiamo farlo con metodologie diverse da quelle seguite nella programmazione di basso livello e con le regole e le limitazioni imposte dal sistema operativo.

Kernel e User Space

Come sicuramente molti di voi sapranno, quando si utilizza un sistema operativo esiste una netta distinzione tra “Kernel Space” ed “User Space”. Il sistema operativo gira in modo “privilegiato” in “Kernel Space” mentre le applicazioni utente girano un “User Space”. Lo spazio del kernel e lo spazio utente sono “separati” e questa separazione è necessaria al fine di impedire alle applicazioni utente di causare conflitti con le risorse hardware del sistema: il kernel supervisiona e accede alle risorse hardware mentre alle applicazioni user space non è consentito accedere a queste risorse direttamente. Se un’applicazione utente deve accedere alle risorse di sistema (deve leggere o scrivere lo stato di un GPIO ad esempio) lo deve fare tramite una richiesta al sistema operativo e attraverso chiamate di sistema dedicate.

GPIOLIB

In Linux esiste un sistema di API oramai abbastanza standard per controllare e la gestione i GPIO chiamata GPIOLIB Linux. L’API è descritta nella documentazione ufficiale di Linux ed è disponibile nell’albero del kernel (linux / Documentation / gpio.txt) o in alternativa, lo stesso documento può essere trovato facilmente in Internet (ad esempio qui: http://lxr.free-electrons.com/source/Documentation/gpio/sysfs.txt).


Si tratta di un’interfaccia GPIO generica (realizzata con un apposito Driver) che una volta abilitata, in fase di configurazione e di build del kernel mette a disposizione una serie di files e link nel root file system tramite i quali è possibile configurare, leggere e scrivere i pin GPIO del microprocessore anche da User Space. Visto che in Linux tutto è un file, l’interazione con il driver che gestisce i GPIO viene fatta per mezzo dei file e dei link che troviamo in /sys/class/gpio.

Trovare l’ID del Pin

Per utilizzare un GIPO è necessario per prima cosa identificare il suo ID univoco che lo identifica; il suo valore dipende solitamente dal Multiplexing utilizzato dalla CPU.
Nei processori serie i.MX i GPIO sono raggruppati in ruppi di 32 elementi.
Per esempio il GPIO1_3 (GPIO della porta 1, pin numero 3) ha un ID uguale a 3.
In generale la formala per calcolare l’ID è la seguente: GPIO_ID = (nPORT-1)*32+nPIN.
Ad esempio l’ID del GPIO7_4 è 196 (196 = (7-1)*32+4=196 ).

L’export, il settings e la gestione del pin,

Una vola trovato l’ID è necessario effettuarne l’export in modo  che il kernel generi tutti i relativi link dai quale sarà possibile accedere al GPIO. L’export si effettua scrivendo l’ID del pin nel file /sys/class/gpio/export.

$ echo 196 > /sys/class/gpio/export

Una volta esportato è necessario impostare la direzione di ingresso o di uscita scrivendo le parole “in” o “out” nel link: /sys/class/gpio/gpio196/direction

$ echo out > /sys/class/gpio/gpio196/direction

Per impostare il livello alto o basso è necessario scrivere 1 o 0 nel file: /sys/class/gpio/gpio196/value

$ echo 1 > /sys/class/gpio/gpio196/value
$ echo 0 > /sys/class/gpio/gpio196/value

Se il Pin è configurato come ingresso, per leggere lo stato è sufficiente leggere il contenuto del file /sys/class/gpio/gpio196/value

$ cat /sys/class/gpio/gpio196/value

Qualora non ci interessi più accedere al GPIO possiamo liberando le risorse effettuando un export.

$ echo 196 > /sys/class/gpio/unexport

Tutto questi comandi possono ovviamente essere dati dalla consolle di sistema anche se per ovvi motivi il nostro interesse è avere la possibilità di manipolare i GPIO all’interno della nostra applicazione.

A tal proposito ho realizzato una classe per Qt che gestisce i GPIO e che permette di leggere e scrivere il loro contenuto dall’interno di una applicazioni  Qt.

Scheda relay di Amber2

Per testare tale classe ho utilizzato la scheda Relay della Amber2 di cui ho già parlato nell’articolo precedente.


Si tratta di un’estensione della board Amber2 e dispone di due relay con i quali è possibile controllare carchi esterni o attivare dispositivi; in pratica sono degli interruttori che possono essere accesi o spenti da software.
I due relay possono essere controllati in base ai settaggi della scheda da diversi GPIO del processore Imx6.

Nel video che segue potete vedere un semplice esempio di cosa può essere fatto con un piccolo programma Qt che gestisce la libreria.

https://drive.google.com/open?id=1IFenAdu3CeGBtTsWCOLIImmilQQUJlp7

Come già detto ho realizzato una classe da utilizzare in un progetto Qt per gestire i GPIO in modo comode e semplificato.


La classe può essere utilizzata per accedere singolarmente ad uno specifico GPIO o per attivare un servizio di Gpio Manager che registra e controlla i pin utilizzati e si occupa della loro gestione e della notifica del cambio di stato.

Utilizzando la classe GPIO è possibile controllare i pin con le seguenti righe di codice:

Si crea un oggetto GPIO al quale si passa il numero di porta ed ilo numero di PIN

GPIO* pinRelay1;
pinRelay1 = new GPIO(1,2);

Si apre il pin per inizializzarlo.

pinRelay1->openPin();

Si imposta la direzione,

pinRelay1->setDirection(GPIO::Out);

Si scrive il livello di uscita con la seguente linea di codice:

pinRelay1->setState(stat);

dove stat è una vaiabile booleana che può essere vera o falsa.

Per leggere lo stato è possibile chiamare la seguente funzione:

pinRelay1->getState()

che restituisce true o false a seconda del livello.

La classe appena descritta è molto comoda quando si devono gestire pin con direzione di uscita.
Se si devono gestire Pin sia in uscita che in ingresso è consigliabile utilizzare la classe GPIOManager.

Per prima cosa creiamo un’istanza della classe GPIOManager:

GPIOManager* pGPIOManager;
pGPIOManager = new GPIOManager(this);

Connettiamo il segnale di cambio stato del pin generato dal Manager ad uno slot in cui andremo a ricevere l’informazione del cambio.

connect(pGPIOManager, SIGNAL(onInputPinStatusChanged(GPIO*, bool)), this, SLOT(inputPinsStatusChangedSlot(GPIO*, bool)));

Procediamo con la definizione dei pin di uscita

pinRelay1 = pGPIOManager->addPin(1,2);
pinRelay2 = pGPIOManager->addPin(2,11);

e quelli d’ingresso

pGPIOManager->addPin(1,4,GPIO::In);
pGPIOManager->addPin(3,13,GPIO::In);

al termine, attiviamo il servizio.

pGPIOManager->startService();

Giunti a questo punto, ogni volta che uno dei pin di ingresso cambieranno di stato, lo slot inputPinsStatusChangedSlot verrà invocato e si avrà per tanto la possibilità di leggere il valore logico applicato.

Buon divertimento.

 

 

 

 

 


 

Coming soon…..

Una delle esigenze più comuni degli sviluppatori che realizzano un apparati elettronici è quella di gestire le uscite e gli ingressi digitali per attivare interruttori, acquisire lo stato di uno o più pulsanti o in generale interagire con altre periferiche per mezzo delle linee digitali d I/O (GPIO) messe a disposizione dai dispositivi utilizzati. Controllare da codice lo stato o il livello di un pin del microprocessore è una delle prime cose che si imparano quando si lavora con il codice e credo che la quasi totalità degli sviluppatori abbia almeno una volta nella loro vita realizzato il classico progetto del LED che lampeggia o della classica sequenza di luci che si accende in modalità “super-car”.
Quando si lavora con il firmware è infatti abbastanza semplice scrivere o leggere lo stato di un pin del proprio dispositivo; per compiere questa semplice operazione, il più delle volte è sufficiente scrivere o leggere un bit nel registro di I/O dedicato o aspettare lo scatenarsi del relativo interrupt se opportunamente configurato.
Cosa succede e nel nostro sistema gira un sistema operativo evoluto tipo Linux?
Possiamo ancora accedere alle linee di I/O della nostra CPU direttamente dalla nostra applicazione utente?
La risposta è ovviamente affermativa anche se la modalità può dipende dal sistema che stiamo utilizzando e dalla sua configurazione. In generale possiamo controllare e accedere allo stato dei GPIO ma dobbiamo farlo con metodologie diverse da quelle seguite nella programmazione di basso livello e con le regole e le limitazioni imposte dal sistema operativo.

Kernel e User Space

Come sicuramente molti di voi sapranno, quando si utilizza un sistema operativo esiste una netta distinzione tra “Kernel Space” ed “User Space”. Il sistema operativo gira in modo “privilegiato” in “Kernel Space” mentre le applicazioni utente girano un “User Space”. Lo spazio del kernel e lo spazio utente sono “separati” e questa separazione è necessaria al fine di impedire alle applicazioni utente di causare conflitti con le risorse hardware del sistema: il kernel supervisiona e accede alle risorse hardware mentre alle applicazioni user space non è consentito accedere a queste risorse direttamente. Se un’applicazione utente deve accedere alle risorse di sistema (deve leggere o scrivere lo stato di un GPIO ad esempio) lo deve fare tramite una richiesta al sistema operativo e attraverso chiamate di sistema dedicate.

GPIOLIB

In Linux esiste un sistema di API oramai abbastanza standard per controllare e la gestione i GPIO chiamata GPIOLIB Linux. L’API è descritta nella documentazione ufficiale di Linux ed è disponibile nell’albero del kernel (linux / Documentation / gpio.txt) o in alternativa, lo stesso documento può essere trovato facilmente in Internet (ad esempio qui: http://lxr.free-electrons.com/source/Documentation/gpio/sysfs.txt).


Si tratta di un’interfaccia GPIO generica (realizzata con un apposito Driver) che una volta abilitata, in fase di configurazione e di build del kernel mette a disposizione una serie di files e link nel root file system tramite i quali è possibile configurare, leggere e scrivere i pin GPIO del microprocessore anche da User Space. Visto che in Linux tutto è un file, l’interazione con il driver che gestisce i GPIO viene fatta per mezzo dei file e dei link che troviamo in /sys/class/gpio.

Trovare l’ID del Pin

Per utilizzare un GIPO è necessario per prima cosa identificare il suo ID univoco che lo identifica; il suo valore dipende solitamente dal Multiplexing utilizzato dalla CPU.
Nei processori serie i.MX i GPIO sono raggruppati in ruppi di 32 elementi.
Per esempio il GPIO1_3 (GPIO della porta 1, pin numero 3) ha un ID uguale a 3.
In generale la formala per calcolare l’ID è la seguente: GPIO_ID = (nPORT-1)*32+nPIN.
Ad esempio l’ID del GPIO7_4 è 196 (196 = (7-1)*32+4=196 ).

L’export, il settings e la gestione del pin,

Una vola trovato l’ID è necessario effettuarne l’export in modo che il kernel generi tutti i relativi link dai quale sarà possibile accedere al GPIO. L’export si effettua scrivendo l’ID del pin nel file /sys/class/gpio/export.

$ echo 196 > /sys/class/gpio/export

Una volta esportato è necessario impostare la direzione di ingresso o di uscita scrivendo le parole “in” o “out” nel link: /sys/class/gpio/gpio196/direction

$ echo out > /sys/class/gpio/gpio196/direction

Per impostare il livello alto o basso è necessario scrivere 1 o 0 nel file: /sys/class/gpio/gpio196/value

$ echo 1 > /sys/class/gpio/gpio196/value
$ echo 0 > /sys/class/gpio/gpio196/value

Se il Pin è configurato come ingresso, per leggere lo stato è sufficiente leggere il contenuto del file /sys/class/gpio/gpio196/value

$ cat /sys/class/gpio/gpio196/value

Qualora non ci interessi più accedere al GPIO possiamo liberando le risorse effettuando un export.

$ echo 196 > /sys/class/gpio/unexport

Tutto questi comandi possono ovviamente essere dati dalla consolle di sistema anche se per ovvi motivi il nostro interesse è avere la possibilità di manipolare i GPIO all’interno della nostra applicazione.

A tal proposito ho realizzato una classe per Qt che gestisce i GPIO e che permette di leggere e scrivere il loro contenuto dall’interno di una applicazioni Qt.

Scheda relay di Amber2

Per testare tale classe ho utilizzato la scheda Relay della Amber2 di cui ho già parlato nell’articolo precedente.


Si tratta di un’estensione della board Amber2 e dispone di due relay con i quali è possibile controllare carchi esterni o attivare dispositivi; in pratica sono degli interruttori che possono essere accesi o spenti da software.
I due relay possono essere controllati in base ai settaggi della scheda da diversi GPIO del processore Imx6.

Nel video che segue potete vedere un semplice esempio di cosa può essere fatto con un piccolo programma Qt che gestisce la libreria.

https://drive.google.com/open?id=1IFenAdu3CeGBtTsWCOLIImmilQQUJlp7

Come già detto ho realizzato una classe da utilizzare in un progetto Qt per gestire i GPIO in modo comode e semplificato.


La classe può essere utilizzata per accedere singolarmente ad uno specifico GPIO o per attivare un servizio di Gpio Manager che registra e controlla i pin utilizzati e si occupa della loro gestione e della notifica del cambio di stato.

Utilizzando la classe GPIO è possibile controllare i pin con le seguenti righe di codice:

Si crea un oggetto GPIO al quale si passa il numero di porta ed ilo numero di PIN

GPIO* pinRelay1;
pinRelay1 = new GPIO(1,2);

Si apre il pin per inizializzarlo.

pinRelay1->openPin();

Si imposta la direzione,

pinRelay1->setDirection(GPIO::Out);

Si scrive il livello di uscita con la seguente linea di codice:

pinRelay1->setState(stat);

dove stat è una vaiabile booleana che può essere vera o falsa.

Per leggere lo stato è possibile chiamare la seguente funzione:

pinRelay1->getState()

che restituisce true o false a seconda del livello.

La classe appena descritta è molto comoda quando si devono gestire pin con direzione di uscita.
Se si devono gestire Pin sia in uscita che in ingresso è consigliabile utilizzare la classe GPIOManager.

Per prima cosa creiamo un’istanza della classe GPIOManager:

GPIOManager* pGPIOManager;
pGPIOManager = new GPIOManager(this);

Connettiamo il segnale di cambio stato del pin generato dal Manager ad uno slot in cui andremo a ricevere l’informazione del cambio.

connect(pGPIOManager, SIGNAL(onInputPinStatusChanged(GPIO*, bool)), this, SLOT(inputPinsStatusChangedSlot(GPIO*, bool)));

Procediamo con la definizione dei pin di uscita

pinRelay1 = pGPIOManager->addPin(1,2);
pinRelay2 = pGPIOManager->addPin(2,11);

e quelli d’ingresso

pGPIOManager->addPin(1,4,GPIO::In);
pGPIOManager->addPin(3,13,GPIO::In);

al termine, attiviamo il servizio.

pGPIOManager->startService();

Giunti a questo punto, ogni volta che uno dei pin di ingresso cambieranno di stato, lo slot inputPinsStatusChangedSlot verrà invocato e si avrà per tanto la possibilità di leggere il valore logico applicato.

Buon divertimento.

 

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

This site uses Akismet to reduce spam. Learn how your comment data is processed.