Linux_embedded_cz3.pdf

(1711 KB) Pobierz
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
KURS
Wprowadzenie do
Linuksa embedded (3)
Obsługa portów GPIO
Dodatkowe materiały
na CD/FTP
Porty GPIO są jednym z  najprostszych układów peryferyjnych,
od obsługi których zwykle rozpoczynamy tworzenie programów
zapoznając się z  danym typem mikrokontrolera. W  wypadku
aplikacji pracującej pod RTOS’em lub bez systemu operacyjnego,
obsługa portów GPIO sprowadza się do wpisania do rejestrów
portu kilku wartości określających jego konigurację, czyli kierunku
wejście lub wyjście, załączenie lub wyłączenie rezystorów
podciągających itp. W  wypadku systemu Linux jest inaczej,
ponieważ programista ma do czynienia z  obsługą urządzeń,
a  porty GPIO umożliwiając ich sterowanie nie są urządzeniem
w  ogólnym rozumieniu tego słowa.
Dodatkowe materiały na CD/FTP:
ftp://ep.com.pl , user: 10925 , pass: 87thc181
• wszystkie poprzednie części kursu
w  przestrzeni użytkownika. Zapewnia on
zaawansowany interfejs dla LED’ów umożli-
wiający ich: włączanie, wyłączanie, włącza-
nie na określony czas bez interwencji aplika-
cji i sterowanie jasnością świecenia. Funkcja
sterowania jasnością zależy od możliwości
sprzętu i nie zawsze jest dostępna.
Aby używać sterownika LED Class Dri-
ver należy na etapie koniguracji jądra (De-
vice Drivers –> LED Devices) włączyć nastę-
pujące opcje:
– LED Class support,
– LED Support for GPIO connected LEDS.
Pierwsza opcja włącza w kernelu obsługę
LED Class Drivers, natomiast druga umożli-
wia używanie przez nią linii GPIO. Z uwagi
na to, że w tego rodzaju urządzeniach nie
istnieje system powiadamiania o dostępnych
zasobach sprzętowych, takich jak BIOS, na-
leży poinformować kernel, do której linii jest
dołączona dana dioda oraz jaka jest jej na-
zwa. Przypisanie poszczególnych urządzeń
jest realizowane w  kodzie jądra Linuksa,
odpowiedzialnym za inicjalizację maszyny.
Na przykład, aby diodom o nazwach led0
oraz led1 przypisać sterowanie za pomocą
portów PC2 oraz PC3, należy zadeklarować
strukturę jak na listingu 8 oraz zarejestrować
ją w systemie wywołując funkcję:
/* LEDs */
at91_gpio_leds(my_leds, ARRAY_
SIZE(my_leds));
Dopisanie diod LED w pliku konigura-
cyjny maszyny będzie skutkowało tym, że
w katalogu /sys/class/led0 oraz /sys/class/led1
pojawią się następujące pliki umożliwiające
kontrolowanie dołączonych diod LED:
– brightness: umożliwia sterowanie jasno-
ścią diody LED. W wypadku implemen-
tacji za pomocą linii GPIO jak powyżej,
wpisanie do tego pliku wartości 0 powo-
duje wyłączenie diody, natomiast wpisa-
nie wartości różnej od 0 spowoduje jej
włączenie.
– trigger: umożliwia ustawienie zaawan-
sowanych wyzwalaczy np. mruganie
Sposoby dostępu do portów GPIO
w systemie Linux
W Linuksie długo nie istniał standardowy,
bezpośredni sterownik linii GPIO, co ma swoje
uzasadnienie. Do portów GPIO najczęściej dołą-
czamy jakieś proste układy, na przykład diody
LED, przyciski itp. Zgodnie z ilozoią systemu
Linux właśnie te dołączone urządzenia, czyli
wspomniane diody LED i przyciski, powinny
mieć swoje sterowniki udostępniające je aplika-
cjom użytkownika. Porty GPIO stanowią tylko
mechanizm dołączania urządzeń, a nie urzą-
dzenie samo w sobie. To do jakiego wejścia lub
wyjścia dane urządzenie jest dołączone oraz
sposób jego sterowania nie powinien mieć zna-
czenia dla aplikacji. I to jest właśnie dodatkowe
zadanie sterowników urządzeń, które stanowią
dodatkową warstwę abstrakcji pomiędzy sprzę-
tem a aplikacją użytkownika. Na przykład dioda
LED izycznie może być dołączona bezpośred-
nio do linii GPIO, ale równie dobrze może być
do układu ekspandera I 2 C. Jednak to gdzie jest
ona dołączona z punktu widzenia funkcjonal-
ności aplikacji nie ma żadnego znaczenia.
Na początek zajmiemy się najbardziej ele-
ganckim sposobem dostępu do linii GPIO, czyli
sterownikami funkcjonalnymi, które używają
pojedynczo linii GPIO. Są to mianowicie sterow-
nik diod LED (LED class driver) oraz sterownik
podsystemu Linux Input System dla klawiatury
dołączonej do linii GPIO, czyli „GPIO Keys”.
Po skonigurowaniu portu, najczęściej
wpisując lub odczytując dane z pojedyn-
czego rejestru, mamy możliwość zmiany
stanu linii wyjściowej lub odczytu stanu
linii wejściowej. W podobny sposób są zbu-
dowane porty mikrokontrolerów rodziny
AT91, do której należy m.in.AT91RM9200.
Mamy w  nim możliwość sterowania li-
nia GPIO za pomocą kilkunastu rejestrów.
W wypadku Linuksa sytuacja komplikuje
się, ponieważ bezpośredni dostęp do por-
tów wejścia wyjścia z poziomu programu
użytkownika nie jest możliwy, a komuni-
kacja pomiędzy urządzeniami a  oprogra-
mowaniem musi odbywać się za pomocą
sterowników. Istnieje możliwość obejścia
tego za pomocą sterownika /dev/mem, ale
nie jest to rozwiązanie zalecane. Brak bez-
pośredniego dostępu do rejestrów oraz
całej izycznej przestrzeni adresowej jest
podyktowany względami bezpieczeństwa.
Nietrudno sobie wyobrazić aplikację, która
w wyniku zapisania błędnych danych po-
woduje awarię całego systemu. W Linuksie
nie istnieje jeden generyczny mechanizm
dostępu do portów GPIO z  przestrzeni
użytkownika, o tym dlaczego tak jest na-
piszemy w dalszej części tekstu. W części
praktycznej natomiast pokażemy w miarę
bezpieczny i uniwersalny sposób na dostęp
do portów GPIO w  Linuksie z  programu
użytkownika, na przykładzie płyty prototy-
powej BF210 za pomocą jednego z mecha-
nizmów – SYSFS GPIO, który nie jest jed-
nak całkowicie zgodny z ilozoią sterowni-
ków urządzeń.
Sterownik diod LED (Led Class
Driver)
Sterownik LED Class Driver, umożliwia
kontrolę diod LED z  aplikacji pracującej
96
ELEKTRONIKA PRAKTYCZNA 6/2011
883837001.095.png 883837001.106.png 883837001.117.png 883837001.128.png
Wprowadzenie do Linuksa embedded
– Keyboyard,
– GPIO buttons.
Driver ten również wymaga zdeiniowa-
nia struktur w pliku inicjalizacyjnym ma-
szyny zawierających informacje o  rodzaju
generowanych zdarzeń oraz o przypisanych
do nich liniach GPIO. Na przykład, jeżeli
chcemy, aby zbocze opadające na liniach
PC2 i PC3 wygenerowało zdarzenie od klawi-
szy „C” i „D”, należy zdeiniować struktury,
które umieszczono na listingu 9, a następnie
zarejestrować w kodzie inicjalizacyjnym ma-
szyny (listing 10).
Od strony aplikacji przestrzeni użytkow-
nika dostęp do wciśniętych klawiszy jest
realizowany za pomocą urządzenia /dev/
input/event0 udostępniającego ich kody. Za
pomocą funkcji blokującej read można uśpić
bieżący proces do momentu zaistnienia zda-
rzenia wciśnięcia klawisza, co jest bardzo
ważne w przypadku środowiska, w którym
może być uruchomionych wiele procesów.
Listing 8. Struktura przypisująca diodom LED0 i LED1 sterowanie za pomocą
wyprowadzeń PC2 i PC3
static struct at91_gpio_led my_leds[] = {
{
.name = “led0”,
.gpio = AT91_PIN_PC2,
.trigger = “timer”,
},
{
.name = “led1”,
.gpio = AT91_PIN_PC3,
.trigger = “timer”,
}
};
Listing 9. Deklaracja struktury, która spowoduje generowanie zdarzeń na skutek
zbocza opadającego na liniach PC2 i PC3
static struct gpio_keys_button my_buttons[] = {
{ .desc = „Key0”,
.gpio = AT91_PIN_PC2,
.active_low = 1,
.code = KEY_C,
.type = EV_KEY,
},
{ .desc = „Key1”,
.gpio = AT91_PIN_PC2,
.active_low = 1,
.code = KEY_D,
.type = EV_KEY,
},
};
static struct gpio_keys_platform_data my_button_data = {
.buttons = my_buttons,
.nbuttons = ARRAY_SIZE(my_buttons),
};
Metoda brute-force, czyli /dev/
mem
Przy omawiania sposobu dostępu do por-
tów GPIO z powodów czysto porządkowych
omówimy metodę, której nie powinno stoso-
wać się pod żadnym pozorem, a która bardzo
często jest używana przez początkujących
użytkowników. W Linuksie istnieje sterow-
nik reprezentowany przez plik /dev/mem,
którego zadaniem jest udostępnianie całej
pamięci izycznej. Dostęp do tego pliku ma
standardowo tylko administrator (root). Uży-
cie tego pliku umożliwia dostęp do izycz-
nej przestrzeni adresowej, a zatem również
do portów GPIO. W Linuksie istnieje rów-
nież możliwość użycia funkcji mmap, która
umożliwia mapowanie pliku w przestrzeni
adresowej procesu. Zatem stosując sterow-
nik /dev/mem oraz funkcje mmap możemy
uzyskać dostęp do dowolnych rejestrów
mikrokontrolera. Przykład użycia /dev/mem
wraz z mmap w celu uzyskania dostępu do
pamięci izycznej o adresie base i rozmiarze
1 strony przedstawiono na listingu 11.
Działanie funkcji sprowadza się do
otwarcia pliku /dev/mem, a następnie ma-
powanie tego pliku w przestrzeni adresowej
static struct platform_device gpio_keys_dev = {
.name = “gpio-keys”,
.id = 0,
.dev =
{
.platform_data = &my_button_data,
}
};
Lisiting 10. Rejestracja zdarzeń z listingu 1 w kodzie maszyny
for(i=0; i < ARRAY_SIZE(my_buttons); i++)
at91_select_gpio(my_buttons[i].gpio, 0);
platform_device_register(&gpio_keys_dev);
podczas aktywności interfejsu USB lub
karty sieciowej bez ingerencji programu
zewnętrznego np. wpisanie do tego pliku
wartości eth0 spowoduje mruganie dio-
dy LED w momencie aktywności interfej-
su sieciowego. Wpisanie wartości timer
umożliwia sterowanie mruganiem diod
LED.
– delay_on, delay_off: wpisanie do tych
plików wartości włączonej w ms określa
stosunek czasu włączenia do wyłączenia
diody, co umożliwia jej miganie z wybra-
nym wypełnieniem, gdy jako trigger wy-
brany został timer.
Na przykład, aby włączyć diodę led0 wy-
starczy z wiersza polecenia, wpisać:
echo 1 > /sys/class/led/led1/brightness
Dzięki uruchomieniu tego sterownika zysku-
jemy możliwość generowania zdarzeń w wy-
niku zmiany stanu linii GPIO. Jest to istotne,
ponieważ aplikacja korzystająca z podsyste-
mu Linux Input System może zostać uśpiona
do czasu wystąpienia zdarzenia od wciśnię-
cia klawisza. Należy pamiętać, że pracuje-
my w systemie wielozadaniowym i należy
unikać aktywnego odpytywania o stan linii,
tak jak to robi się w przypadku aplikacji dla
mikrokontrolerów. Aby umożliwić działanie
klawiatury dołączonej do linii GPIO, należy
w kernelu uaktywnić następujące opcje:
– Event Interface,
Listing 11. Przykład użycia /dev/mem wraz z mmap w celu uzyskania dostępu do
pamięci izycznej o adresie base i rozmiarze 1 strony
uint32_t *mmap_base_address(unsigned base)
{
int hwnd = open(„/dev/mem”,O_RDWR|O_SYNC);
if(hwnd<0)
{
//error handling
}
//Map to process space and calculate address
unsigned long map_addr = base & ~(getpagesize()-1);
void *mem = mmap(0,getpagesize(),PROT_READ|PROT_WRITE,MAP_SHARED,hwnd,map_
addr);
if(!mem)
{
//Error handling
}
uint32_t *regs = (uint32_t*) mem + (base-map_addr)/4;
return regs;
}
Sterownik klawiatury z użyciem
linii GPIO
W Linuksie obsługa klawiatury jest re-
alizowana za pośrednictwem podsystemu
Linux Input System zapewniającego obsługę
urządzeń wejściowych, takich jak myszki
i klawiatury za pomocą jednolitego interfej-
su. Istnieje możliwość uruchomienia sterow-
nika GPIO Keys, który umożliwia współpra-
cę prostych klawiszy dołączonych do linii
GPIO z podsystemem Linux Input System.
97
ELEKTRONIKA PRAKTYCZNA 6/2011
883837001.001.png
KURS
procesu. W wyniku jej działania otrzymu-
jemy wskaźnik do dowolnego obszaru pa-
mięci, a więc również do obszaru rejestrów
GPIO, których możemy używać, tak jak
w przypadku aplikacji pisanej dla mikrokon-
trolera. Rozwiązanie to jest bardzo niebez-
piecznie i nigdy w praktyce nie powinno być
używane. Bezpośredni dostęp do pamięci
izycznej powoduje że nawet niewielki błąd
w programie może spowodować zawiesze-
nie się całego systemu. Można powiedzieć,
że poprzez użycie tego mechanizmu tracimy
wszelkie zalety jakim jest użycie systemu
operacyjnego.
Listing 12. Przekształcenie wartości liczbowej przekazanej jako gpio na liczbę
//Write int to the selected item
int sysfsgpio_write_int(unsigned gpio, const char *item)
{
char buf[16];
snprintf( buf, sizeof(buf),”%d”, gpio);
return sysfsgpio_write(item,buf);
}
Listing 13.
enum gpio_dir
{
gpio_dir_input,
gpio_dir_output
};
int gpio_direction(unsigned gpio, enum gpio_dir dir)
{
char buf[32];
snprintf( buf, sizeof(buf),”gpio%d/direction”,gpio );
return sysfsgpio_write(buf, dir==gpio_dir_output?”out”:”in”);
}
Dostęp do linii GPIO za pomocą
sysfs gpio interface
Dwie opisane metody, które pośrednio
odnoszą się do portów GPIO są bardzo wy-
godne w wypadku, gdy mamy do czynienia
z gotowym urządzeniem i mamy ściśle okre-
ślone przeznaczenie poszczególnych linii.
W przypadku płytek uniwersalnych, takich
jak BF210, jest ciężko określić końcowe prze-
znaczenie linii GPIO i  zdeiniować odpo-
wiednie struktury w pliku inicjalizacyjnym
maszyny, natomiast użycie /dev/mem jest
zbyt niebezpieczne. Dawniej ten problem
rozwiązywało się za pomocą sterowników
pisanych specjalnie do obsługi GPIO, nato-
miast obecnie w jądrze istnieje możliwość
dostępu do portów GPIO z przestrzeni użyt-
kownika w bezpieczny sposób za pomocą
sysfs gpio interface. Ten interfejs jest dostęp-
ny za pomocą systemu plików sysfs w kata-
logu /sys/class/gpio. Należy tutaj podkreślić,
że w przypadku rozwiązań produkcyjnych
raczej należy używać mechanizmów typu
LED class driver czy GPIO keyboyard za-
miast interfejsu GPIO.
Poszczególne porty GPIO w  interfejsie
GPIO są identyikowane za pomocą liczby
porządkowej. W przypadku platformy AT91
linie portu PA0...PA31 mają identyikatory
32...63, linie portu PB identyikatory 64...95,
natomiast linie portu PC mają identyikato-
ry 96...127. Aby daną linię portu udostępnić
w przestrzeni użytkownika, należy do pliku
/sys/class/gpio/export wpisać numer porząd-
kowy linii, którą chcemy udostępnić. Na
przykład, aby udostępnić linię portu PB0
w wierszu polecenia należy wydać polecenie:
echo 64 > /sys/class/gpio/export.
Zwrócenie danej linii portu do prze-
strzeni jądra następuje poprzez wpisanie
numeru porządkowego linii do pliku /sys/
class/gpio/unexport. Mechanizm udostęp-
niania jest stosunkowo bezpieczny, ponie-
waż w przypadku, gdy chcemy wyeksporto-
wać do przestrzeni użytkownika linię portu
używaną przez inny driver, to nie zostanie
ona udostępniona, a funkcja read() pisząca
do pliku export nie powiedzie się zwracając
błąd. Dzięki takiemu podejściu mamy pew-
ność, że zmienimy koniguracji linii używa-
nej w przestrzeni jądra przez inny sterownik.
Wyeksportowanie danej linii GPIO do prze-
strzeni użytkownika spowoduje pojawienie
się w katalogu /sys/class/gpio katalogu gpio-
XXX, gdzie XXX określa numer porządkowy
linii GPIO. Dla wspomnianej linii PB0 po wy-
konaniu polecenia echo 64 > /sys/class/gpio/
export, gdy linia nie jest używana przez ją-
dro pojawi się katalog /sys/class/gpio/gpio64,
w którym znajdują się pliki umożliwiające
sterowanie linią GPIO:
– direction: wpisanie do niego wartości in
spowoduje ustawienie portu w kierunku
wejścia, wpisanie wartości out powoduje
ustawienie wybranego portu w kierunku
wyjścia.
– value: w przypadku odczytu umożliwia
odczytanie stanu linii portu. W przypad-
ku zapisu wpisanie wartości 1 ustawia
wybrany port w stan wysoki, wpisanie
wartości 0 zeruje wybrany port.
Na przykład aby skonigurować wy-
eksportowaną linie PB0 w  kierunku wyj-
ścia i ustawić na wyjściu stan niski należy
w wierszu poleceń wpisać następującą se-
kwencję:
echo out > /sys/class/gpio/gpio64/direction
echo 0 > /sys/class/gpio/gpio64/value
Naturalnie, w praktyce zapis oraz odczyt
wspomnianych plików realizowany bezpo-
średnio w programie na przykład za pomocą
wywołań systemowych read(), write(). Przed-
stawiony sposób nadaje się do sterowania
pojedynczymi liniami, do których są podłą-
czone takie peryferia, jak dioda LED, prze-
kaźnik itd. W przypadku realizacji bardziej
skomplikowanych sekwencji będziemy zmu-
szeni napisać sterownik jądra bezpośrednio
dla danego urządzenia, ponieważ dostęp za
pomocą sysfs-gpio z programu użytkownika
jest stosunkowo powolny.
KAMODLED8: (+5V – J2PIN1, GND – J2PIN2,
D0 - J2PIN5, D1 – J2PIN7, D2 – J2PIN17, D3
– J2PIN19, D4-J2PIN4, D5-J2PIN6, D6-J2PIN8,
D7-J2PIN10)
KAMODKB4x4: ( COL1 – J2PIN12, ROW1-J2PIN9)
Rysunek 6. Sposób połączenia modułów
gramie odczytywać, i zmieniać stan wybra-
nych linii portów.
Do uruchomienia programu z przykładu
jest potrzebny moduł komputera BF210 oraz
moduły KamodLed8 i KamodKB4x4. Na ry-
sunku 6 przedstawiono sposób połączenia
modułów.
Sterowanie portami GPIO, pokażemy na
bardzo prostym przykładzie, w którym każde
wciśnięcie klawisza „1” na klawiaturze KA-
MODKB4x4 będzie powodować zwiększenie
licznika binarnego, którego stan zostanie od-
zwierciedlony za pomocą diod D0...D3 mo-
dułu KAMODLED8.
Przykładowy program został napisany
w  pojedynczym pliku sysgpio.c. Wykorzy-
stując mechanizm dostępowy klasy GPIO,
napisano funkcje, których zadaniem jest
wpisywanie (podobnie jak polecenie echo)
wartości oraz odczyt (jak polecenie cat) pli-
Przykład sterowania liniami GPIO
za pomocą klasy GPIO
Po zapoznaniu się z  teoretycznymi
aspektami użycia GPIO, pokażemy na bazie
prostego przykładu dla ARMputera BF210,
jak za pomocą klasy GPIO we własnym pro-
98
ELEKTRONIKA PRAKTYCZNA 6/2011
883837001.012.png 883837001.023.png 883837001.034.png 883837001.045.png 883837001.050.png 883837001.051.png 883837001.052.png 883837001.053.png 883837001.054.png 883837001.055.png 883837001.056.png 883837001.057.png 883837001.058.png 883837001.059.png 883837001.060.png 883837001.061.png 883837001.062.png 883837001.063.png 883837001.064.png 883837001.065.png 883837001.066.png 883837001.067.png 883837001.068.png 883837001.069.png 883837001.070.png 883837001.071.png 883837001.072.png 883837001.073.png 883837001.074.png 883837001.075.png 883837001.076.png 883837001.077.png 883837001.078.png 883837001.079.png 883837001.080.png 883837001.081.png 883837001.082.png 883837001.083.png 883837001.084.png 883837001.085.png 883837001.086.png 883837001.087.png 883837001.088.png 883837001.089.png 883837001.090.png 883837001.091.png 883837001.092.png 883837001.093.png 883837001.094.png 883837001.096.png 883837001.097.png 883837001.098.png 883837001.099.png 883837001.100.png 883837001.101.png 883837001.102.png 883837001.103.png 883837001.104.png 883837001.105.png 883837001.107.png 883837001.108.png 883837001.109.png 883837001.110.png 883837001.111.png 883837001.112.png 883837001.113.png 883837001.114.png 883837001.115.png 883837001.116.png 883837001.118.png 883837001.119.png 883837001.120.png 883837001.121.png 883837001.122.png 883837001.123.png 883837001.124.png 883837001.125.png 883837001.126.png 883837001.127.png 883837001.129.png 883837001.130.png 883837001.131.png 883837001.132.png 883837001.133.png 883837001.134.png 883837001.135.png 883837001.136.png 883837001.137.png 883837001.138.png 883837001.002.png 883837001.003.png 883837001.004.png 883837001.005.png 883837001.006.png 883837001.007.png 883837001.008.png 883837001.009.png 883837001.010.png 883837001.011.png 883837001.013.png 883837001.014.png 883837001.015.png 883837001.016.png 883837001.017.png 883837001.018.png 883837001.019.png 883837001.020.png 883837001.021.png 883837001.022.png 883837001.024.png 883837001.025.png 883837001.026.png 883837001.027.png 883837001.028.png 883837001.029.png 883837001.030.png 883837001.031.png 883837001.032.png 883837001.033.png 883837001.035.png 883837001.036.png 883837001.037.png 883837001.038.png 883837001.039.png 883837001.040.png 883837001.041.png 883837001.042.png 883837001.043.png 883837001.044.png 883837001.046.png
Wprowadzenie do Linuksa embedded
snprintf( buf,
sizeof(buf),”gpio%d/value”,gpio
);
int res = sysfsgpio_read( buf,
buf,sizeof(buf) );
if(res < 0) return res;
return atoi(buf);
}
Listing 14. Licznik binarny
//SET signal termination
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGINT);
sigaddset(&sa.sa_mask,SIGTERM);
sa.sa_handler = terminate;
sigaction(SIGINT,&sa, 0);
sigaction(SIGTERM,&sa, 0);
//Initialize gpio
gpio_export(LED1);
gpio_export(LED2);
gpio_export(LED3);
gpio_export(LED4);
gpio_export(KEY);
//Set direction
gpio_direction(LED1,gpio_dir_output);
gpio_direction(LED2,gpio_dir_output);
gpio_direction(LED3,gpio_dir_output);
gpio_direction(LED4,gpio_dir_output);
gpio_direction(KEY,gpio_dir_input);
//Main loop
for(unsigned cnt=0;;)
{
//Read value and sleep
int val1 = gpio_get_value(KEY);
usleep(SLEEP_VALUE);
int val2 = gpio_get_value(KEY);
//Error handling
if(val1<0 || val2<0) { perror(“getval”); exit(-1); }
//Edge detection
if(val1==0 && val2==1)
{
cnt++;
if(gpio_set_value(LED1, cnt & 1)<0) { perror(“setval1”); cleanup();
exit(-1); }
if(gpio_set_value(LED2, cnt & 2)<0) { perror(“setval2”); cleanup();
exit(-1); }
if(gpio_set_value(LED3, cnt & 4),0) { perror(“setval3”); cleanup();
exit(-1); }
if(gpio_set_value(LED4, cnt & 8)<0) { perror(“setval4”); cleanup();
exit(-1); }
}
}
cleanup();
}
Funkcja ta odczytuje z pliku value stan
wybranej linii gpio w  postaci tekstowej 0
lub 1, a następnie przekształca ją na wartość
typu int. Przykładowy kod programu licz-
nika binarnego, wykorzystujący powyższe
funkcje przedstawiono na listingu 14.
Na początku jest instalowany jest hand-
ler dla sygnałów SIGINT oraz SIGTERM,
którego zadaniem jest oddanie przed zakoń-
czeniem programu linii GPIO za pomocą
funkcji gpio_unexport() do przestrzeni jądra.
Następnie jest wywoływana funkcja gpio_
export(), która powoduje wyeksportowanie
wybranych linii GPIO do przestrzeni użyt-
kownika. Linie diod LED1...LED4 są konigu-
rowane jako wyjście, natomiast linia klawi-
sza KEY, jest konigurowana jako wejście. Te-
raz program wchodzi do pętli nieskończonej,
w której jest odczytywany stan linii KEY, po
czym jest wywoływana funkcja usleep() usy-
piająca proces na 20 ms, a następnie ponow-
nie jest odczytywany stan linii KEY. W przy-
padku zmiany poziomu z „1” na „0” (zbocze
opadające) jest zwiększana wartość zmiennej
cnt, a następnie ustawiane są poszczególne
linie portów LED1...LED4 odzwierciedlające
stan bitów portu cnt. Zatrzymanie wykona-
nia programu, a więc zatrzymanie pętli głów-
nej odbywa się w wyniku utrzymania sygna-
łu SIGINT (wciśnięcie na konsoli CTRL+C),
lub SIGTERM (sygnał terminacji procesu),
w wyniku czego jest wywoływany umiesz-
czono na listingu 15 handler terminate(),
w którym na konsolę jest wysyłany komu-
nikat o zamknięciu programu, zostaje przy-
wrócony stary handler obsługi sygnałów, jest
wywoływana funkcja cleanup(), której zada-
niem jest zwrócenie linii GPIO do przestrze-
ni jądra poprzez wywołanie gpio_unexport(),
a następnie proces ulega zakończeniu dzięki
wywołaniu funkcji exit().
Opisany powyżej program ma wadę po-
legającą na tym, że stan linii klawisza jest
sprawdzany w aktywnej pętli, co nie jest do-
ków reprezentujących wybraną linię GPIO.
Zapis do plików jest realizowany za pomocą
funkcji biblioteki standardowej stdio fputs(),
natomiast odczyt jest realizowany za pomo-
cą funkcji fgets(), co realizują funkcje int
sysfsgpio_write(const char *item, const char
*value) oraz int sysfsgpio_read(const char
*item, char *value, size_t value_len). Ich za-
daniem jest odpowiednio, zapis oraz odczyt
pliku o nazwie przekazanej jako item w ka-
talogu /sys/class/gpio/ wartości tekstowej
przekazanej jako value. W przypadku powo-
dzenia funkcja zwraca 0, natomiast w przy-
padku niepowodzenia jest zwracana wartość
ujemna. Funkcja pomocnicza umieszczona
na listingu 12 przekształca wartość liczbową
przekazaną jako gpio na liczbę i zapisuje ją
do pliku określonego jako item za pomocą
funkcji sysfsgpio_write. Zadaniem funkcji
gpio_export jest udostępnienie portu GPIO
dla przestrzeni użytkownika poprzez wpi-
sanie numeru porządkowego portu do pliku
/sys/class/gpio/export:
//Export selected gpio
inline int gpio_export(unsigned
gpio)
{
return sysfsgpio_write_
int(gpio,”export”);
}
inline int gpio_unexport(unsigned
gpio)
{
return sysfsgpio_write_
int(gpio,”unexport”);
}
Funkcja gpio_direction umożliwia
skonigurowanie wybranej linii GPIO
w  kierunku wejścia lub wyjścia (listing
13). Jej działanie sprowadza się do wpisa-
nia do pliku direction wybranej linii gpio
przekazanej jako argument gpio, wartości
in lub out, co spowoduje ustawienie tej
linii jako wejściowej lub wyjściowej. Usta-
wienie wybranej linii portu na poziomie
wysokim lub niskim jest realizowane za
pomocą funkcji:
//Set gpio value
int gpio_set_value(unsigned gpio,
bool value)
{
char buf[32];
snprintf(buf,sizeof(buf),”gpio%d/
value”,gpio );
return sysfsgpio_write(buf,
value?”1”:”0”);
}
Listing 15. Wywołanie handlera
terminate
//Termination handler
void terminate(int sig)
{
printf(“Led program
terminated\n”);
cleanup();
//Restore default sig
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGINT);
sigaddset(&sa.sa_mask,SIGTERM);
sa.sa_handler = SIG_DFL;
sigaction(SIGINT,&sa, 0);
exit(-1);
}
Działanie tej funkcji sprowadza się do
wpisania „0” lub „1” do pliku value wartości
wybranej jako argument gpio linii GPIO. Od-
czyt linii portu jest realizowany za pomocą
funkcji:
int gpio_get_value(unsigned gpio)
{
char buf[32];
Podobną rolę pełni funkcja unexport,
której zadaniem jest zwrócenie linii o nume-
rze porządkowym przekazanym jako gpio do
przestrzeni jądra:
//Unexport selected gpio
99
ELEKTRONIKA PRAKTYCZNA 6/2011
883837001.047.png
KURS
iskImager, który można pobrać ze strony
https://wiki.kubuntu.org/Win32DiskImager .
Do czytnika kart SD należy włożyć kartę,
a  następnie podłączyć czytnik do kom-
putera. Teraz uruchomić program i  jako
opcje image ile wybrać plik example1.img,
natomiast jako device należy wybrać iden-
tyikator dysku, którym jest czytnik kart SD
(rysunek 7). Kliknięcie na guzik Write pow-
oduje rozpoczęcie zapisywania obrazu karty.
Z  poziomu systemu Linux, obraz można
nagrać na kartę za pomocą standardowego
polecenia dd (dd if=example.img of=/dev/
identyikator_urz_czytnika).
Po nagraniu obrazu karty należy ją
umieścić w gnieździe karty komputera BF210,
do portu DBGU należy dołączyć komputer
PC, na którym powinien być uruchomiony
program terminalowy (Hyperterminal, mini-
com itp.) skonigurowany z następującymi
parametrami transmisji 115200, n, 8, 1. Po
włączeniu zasilania powinien być widoc-
zny proces bootowania Linuksa, który pow-
inien zakończyć się wyświetleniem zachęty
do logowania bf210-at91 login:. Jako nazwę
użytkownika należy wpisać root, a na py-
tanie o hasło wcisnąć klawisz Enter. Po za-
logowaniu się należy wpisać polecenie sys-
gpio, co spowoduje uruchomienie opisanego
wcześniej przykładu. Wciskając klawisz „1”
możemy obserwować jak zmienia się stan
diod LED1...LED4 reprezentujący licznik bi-
narny. Zakończenie programu jest możliwe
poprzez wciśnięcie kombinacji klawiszy
CTRL+C, co spowoduje wypisanie komuni-
katu pożegnalnego oraz zakończenie pracy
programu.
Rysunek 7. Okno wyboru identyikatora
dysku
Kompilowanie programu ze źródeł
System Linux oraz wszystkie przykła-
dy zostały przygotowane z wykorzystaniem
pakietu OpenEmbedded. Sposób skompilo-
wania powyższego przykładu oraz systemu
wykracza poza ramy niniejszego artykułu.
Dodatkowe pakiety dla OpenEmbedded
oraz koniguracja dla BF210 są dostarczane
w postaci pliku oe.tar.gz. Aby skompilować
powyższy przykład, należy skonigurować
OpenEmbeded zgodnie z dokumentacją do-
stępną na stronie projektu i dołączyć pakiety
lokalne. Aby zbudować kompletny obraz dla
przykładu, należy wydać polecenie bitbake
ep-examples-image. Aby zbudować tylko pa-
kiet z powyższym przykładem, należy wydać
polecenie bitbake ep-example-sysfsgpio
Lucjan Bryndza, EP
brym rozwiązaniem w przypadku środowisk
wielozadaniowych. Wówczas dużo lepszym
rozwiązaniem byłoby użycie sterownika
GPIO KEYS i podsystemu Input. Takie roz-
wiązanie zapewniałoby uśpienie procesu do
momentu wciśnięcia klawisza bez koniecz-
ności cyklicznego sprawdzania stanu wej-
ścia KEY.
Uruchomienie przykładu, na
BF210
Skompilowany przykład wraz z  pod-
stawowym system Linux jest dostarczany
w postaci obrazu karty SD, w postaci poje-
dynczego pliku example1.img W  systemie
Windows obraz z przykładem można nagrać
na kartę SD za pomocą programu Win32d-
REKLAMA
100
ELEKTRONIKA PRAKTYCZNA 6/2011
883837001.048.png 883837001.049.png
 
Zgłoś jeśli naruszono regulamin