2008.11_Mechanizmy czasu rzeczywistego w Linux_[Programowanie].pdf

(1018 KB) Pobierz
439033276 UNPDF
Programowanie
Mechanizmy czasu rzeczywistego okiem programisty sterowników
rzeczywistego w Linux
Michał Strasburger
Jakiś czas temu na łamach magazynu Linux+ ukazał się artykuł o RTLinux opisujący mechanizmy czasu
rzeczywistego bazujące na mikrojądrze, w tym artykule opisane zostaną te dostarczane standardowo w
każdej dystrybucji linuksa z jądrem gałęzi 2.6, począwszy od wersji 2.6.9.
R ozwój systemu operacyjnego linux w kierunku
korzystują systemy czasu rzeczywistego do przetwarza-
nia danych, symulowania przepływu informacji (ruchu sie-
ciowego) i testowania urządzeń sieciowych. Nawet produ-
cenci urządzeń multimedialnych audio i video korzystają
z usług systemów czasu rzeczywistego. Przykładowe apli-
kacje z wykorzystaniem systemu operacyjnego Linux i me-
chanizmów czasu rzeczywistego można znaleźć w [1], [2],
[3] (Ramka W Sieci ).
Przykłady zastosowań
systemów czasu rzeczywistego
Systemy czasu rzeczywistego znajdują zastosowanie
w przemyśle, gdzie są wykorzystywane do precyzyjne-
go sterowania i nadzoru robotów, procesów technologicz-
nych i linii produkcyjnych. Spotkamy je w aplikacjach dla
środowisk dużego i podwyższonego ryzyka, takich jak ste-
rowanie elektrowni atomowych, systemy nawigacji i kon-
troli lotów, medyczne systemy podtrzymania życia pa-
cjentów. W przemyśle samochodowym systemy czasu rze-
czywistego realizują funkcje ABS, ESP i bezpośredniego
wtrysku paliwa. Nie wszystkie zadania systemów czasu
rzeczywistego są tak odpowiedzialne. Dostawcy usług te-
lekomunikacyjnych i producenci sprzętu sieciowego wy-
Systemy czasu rzeczywistego
System czasu rzeczywistego musi zagwarantować określo-
ny czas odpowiedzi na określone zjawiska zewnętrzne. Do-
stępny czas reakcji dzieli się na szereg czynności wykony-
wanych w ramach obsługi zdarzenia. I tak część czasu reak-
cji przypada z reguły:
• sensorowi, który wykrywa zjawisko,
• modułowi programu, który je analizuje i decyduje o
sposobie odpowiedzi,
• modułowi, który reaguje na zjawisko,
• nieprzewidzianym opóźnieniom (ok. 20-30% czasu re-
akcji)
54
listopad 2008
Mechanizmy czasu
wsparcia systemów wbudowanych ( embedded )
i systemów czasu rzeczywistego ( realtime )
osiągnął już bardzo dojrzały etap. Przyjrzyjmy
się, jakie mechanizmy można wykorzystać do zagwaranto-
wania szybkości pracy cząstki systemu czasu rzeczywistego,
jaką jest sterownik urządzenia.
439033276.020.png 439033276.021.png 439033276.022.png 439033276.023.png
 
Programowanie
Mechanizmy czasu rzeczywistego okiem programisty sterowników
W klasyikacji systemów czasu rzeczywi-
stego ocenia się rolę systemu w środowisku
jego pracy i potencjalne straty spowodowa-
ne przekroczeniem wymaganego czasu reak-
cji na bodziec. Pod tym względem dzielimy
je na dwie grupy. Pierwsza obejmuje syste-
my o bezwzględnych wymogach czasu reak-
cji ( hard - realtime ) a druga te, w których wy-
mogi czasu reakcji mogą być w wyjątkowych
sytuacjach przekraczane ( soft - realtime ). Przy-
kładem systemu hard - realtime będzie układ
wspomagania hamowania w samochodzie,
gdzie kilka milisekund dodatkowego opóźnie-
nia może spowodować utratę przyczepności
samochodu do nawierzchni i bezpośrednie za-
grożenie życia pasażerów. Przykładem sytemu
typu soft - realtime może być system nawiga-
cji satelitarnej, w którym opóźnienie wyświe-
tlanej informacji o trasie (nawet o kilkadzie-
siąt milisekund) nie zostanie w żaden sposób
odczute przez kierowcę. Dodatkowo systemy
typu hard - realtime charakteryzują się czasem
reakcji znacząco krótszym niż systemy typu
soft - realtime . Do zastosowań typu hard-real-
time preferowane są rozwiązania dostarcza-
ne przez system operacyjny Linux z mikro-
jądrem, czyli wydzieloną częścią jądra, która
obsługuje tylko zadania o najwyższych prio-
rytetach. Do zastosowań soft-realtime z powo-
dzeniem można zastosować mechanizmy opi-
sane w tym artykule.
Twórca systemu czasu rzeczywistego za-
cznie od usunięcia z Linuksa niepotrzebnych
plików, programów, usług i modułów jądra;
my ograniczymy się tylko do tych modyika-
cji, które mają bezpośredni wpływ na nasz ste-
rownik. Po koniguracji jądra systemu opisane
zostaną mechanizmy, jakich możemy użyć w
procesie implementacji dla przyspieszenia do-
stępu do urządzenia i przyspieszenia wykony-
wania zadań sterownika. Prezentowane me-
chanizmy zakładają jednoprocesorową wersję
jądra, bazują na rozszerzeniach czasu rzeczy-
wistego posix1.b, posix1.c i innych mechani-
zmach dostarczanych w każdej dystrybucji Li-
nuksa, co gwarantuje przenośność kodu. Opisa-
ne mechanizmy poparte zostaną przykładami.
Zapraszam do lektury.
mie. Służy do tego zmienna HZ, zależna od ar-
chitektury i określająca częstotliwość przerwań
zegara systemowego. Dotychczas była ona
standardowo ustawiana na 100 powodując ge-
nerację przerwania zegarowego co 10 milise-
kund. Obecnie można jej wartość ustawić na-
wet na 1000, umożliwiając tym samym dzie-
sięciokrotnie częstsze przełączanie między pro-
cesami wykonywanymi w systemie. Oznacza
to szybsze dopuszczenie sterownika do pracy
w sytuacji, gdy ma on obsłużyć jakieś zdarze-
nie. Dodatkowo musimy się upewnić, że żad-
ne opcje oszczędzania energii nie są włączone,
a procesor będzie taktowany z najszybszą moż-
liwą częstotliwością.
Wydziedziczanie procesów wykonywa-
nych w trybie jądra (kernel preemption)
Zmiana częstotliwości przełączania proce-
sów w systemie nic nam nie da, jeżeli nie
zmusimy systemu operacyjnego do wydzie-
dziczania procesów wykonywanych w trybie
jądra. Standardowo w Linuksie proces uru-
chomiony wykonuje się aż skończy pewne
zadanie i sam decyduje o zwolnieniu proce-
sora. W takiej sytuacji czas odpowiedzi sys-
temu jest zdeterminowany przez czas wyko-
nywania najdłuższego zadania. Naszą inten-
cją jest wydziedziczenie procesu (odebranie
mu zasobów procesora), jeżeli jego czas wy-
konywania może spowodować przekroczenie
Tabela 1. Klasyikacja systemów z uwzględnieniem czasu reakcji na pobudzenie
HARD-REALTIME
SOFT-REALTIME
WYMOGI CZASU REAKCJI
- jakość systemu określa najgorszy możliwy przy-
padek w opóźnieniu obsługi zdarzenia
- możliwość utraty części zdarzeń czasu reakcji
czyli pozostawienia ich bez obsługi
(niedopuszczalne zgubienie zdarzenia)
- jakość usługi określa statystyczny przypadek
- możliwość utraty części zdarzeń czyli pozostawie-
nia ich bez obsługi
- czas reakcji rzędu dziesiątek mikrosekund - czas reakcji rzędu dziesiątek/setek milisekund
SKUTKI PRZEKROCZENIA CZASU REAKCJI
- zagrożenie zniszczenia systemu lub zdrowia/życia
użytkownika
- pogorszenie jakości usług systemu (np. obra-
zu wideo)
Tabela 2. Koniguracja jądra systemu linux do zastosowań w systemach czasu rzeczywistego
Lp Opcja
Sposób koniguracji
1. Częstotliwość przełącza-
nia zadań w systemie
Processor type and features → Timer frequency (250 HZ) -> (*) 1000
HZ
Processor type and features → [ ] Tickless System (Dynamic Ticks)
Power management options (ACPI, APM) ---> [*] CPU Frequency sca-
ling
[*] 'performance' governor
2. Wydziedziczanie pro-
cesów
Preemption Model ---> (*) Preemptible Kernel (Low-Latency Desktop)
[*] Voluntary Preemption
[*] Preempt The Big Kernel Lock
[*] Enable kernel irq balancing
3. Mechanizmy standardu
POSIX 1.b, 1.c
General setup → [*] System V IPC
[*] IPC Namespaces
[*] POSIX Message Queues
Processor type and features → [*] High Resolution Timer Support
[*] HPET Timer Support
Koniguracja jądra systemu
W Tabeli 2. zaprezentowano wybrane, omó-
wione poniżej opcje koniguracji jądra syste-
mu Linux do zastosowań w systemach czasu
rzeczywistego.
4. Optymalizacja obsługi
przerwań
Preemption Model ---> (*) Preemptible Kernel (Low-Latency Desktop)
[*] Enable kernel irq balancing
5. Opcje przydatne w pro-
cesie tworzenia aplikacji
(NIE MOGĄ BYĆ WŁĄ-
CZONE W DOCELO-
WYM SYSTEMIE)
Kernel hacking ---> Kernel debugging --->
[*] Collect scheduler statistics (NEW)
[*] Collect kernel timers statistics (NEW)
[*] RT Mutex debugging, deadlock detection
(NEW)
[*] Mutex debugging: basic checks (NEW)
[*] Write protect kernel read-only data struc-
tures (NEW)
Tajemnicza zmienna HZ.
Pierwszą rzeczą, jaką ma do dyspozycji projek-
tant sterownika jest koniguracja częstotliwości
potencjalnego przełączania procesów w syste-
www.lpmagazine.org
55
439033276.001.png 439033276.002.png 439033276.003.png 439033276.004.png 439033276.005.png 439033276.006.png 439033276.007.png 439033276.008.png 439033276.009.png 439033276.010.png 439033276.011.png 439033276.012.png 439033276.013.png
 
Programowanie
Mechanizmy czasu rzeczywistego okiem programisty sterowników
czasu reakcji systemu na bodziec zewnętrz-
ny. Do tego celu służy mechanizm zwany
kernel preemption .
Ta opcja narzuca nam styl programowa-
nia nazywany z ang. reentant coding techni-
que . Jest to sposób zabezpieczania się w pro-
gramach przed nieintencyjną zmianą danych
wykorzystywanych przez współbieżnie wyko-
nywane wątki aplikacji. Funkcja, która prze-
chowuje lokalny zbiór wartości dla każdego
wywołującego ją wątku jest funkcją tzw. wie-
lowejściową ( reentant ).
Niżej wymienione zasady skutecznie za-
bezpieczają nas przed korupcją danych:
Po włączeniu opcji wydziedziczania procesów
musimy jeszcze procesowi/wątkowi sterowni-
ka nadać odpowiednio wysoki priorytet, aby
mógł wydziedziczać inne procesy (w dalszej
części artykułu opisany zostanie sposób zmia-
ny priorytetu wątku).
• mechanizmy synchronizacji dostępu do
dzielonych zasobów: semafory i muteksy
• mechanizm komunikacji między wątkami
(message passing)
• pamięć dzielona między wątkami (shared
memory)
Rozszerzenia POSIX1.b i POSIX1.c
Dostrzegając chęć zastosowania Linuksa
w systemach embedded i realtime programi-
ści rozwijający system zaimplementowali dwie
grupy rozszerzeń systemowych mechanizmów
zdeiniowane w standardzie POSIX1.b i POSI-
X1.c Należą do nich:
POSIX1.c:
• wsparcie dla obsługi wielowątkowości w
obrębie jednego procesu obejmujące: two-
rzenie, kontrolę, synchronizację, prioryte-
ty i usuwanie wątków, jak również obsłu-
gę sygnałów przez wątki.
• użycie zmiennych lokalnych zamiast glo-
balnych,
• wyłączanie przerwań na czas wykonywa-
nia krytycznych operacji
• używanie systemowych mechanizmów
synchronizacji dostępu do dzielonych za-
sobów np. semafory czy muteksy
• kompilując kod naszego sterownika nale-
ży również użyć lagi _REENTANT
POSIX1.b:
Zoptymalizowany
czas reakcji na przerwanie
Programista sterownika ma w tym przypadku
możliwość dwojakiego usprawnienia mechani-
zmu przerwań:
• algorytmy szeregowania procesów dla
systemów czasu rzeczywistego (np. Ro-
und Robin)
• wysokiej rozdzielczości zegary (high-reso-
lution timers)
• sygnały czasu rzeczywistego (realtime si-
gnals)
• zagwarantować niski czas opóźnienia re-
akcji na przerwanie, czyli minimalny czas
między zgłoszeniem przerwania i rozpo-
częciem jego obsługi ( low interrupt laten-
cy )
• dodatkowo można jeszcze zoptymalizo-
wać czas reakcji na przerwanie pod wzglę-
dem powtarzalności czyniąc system bar-
dziej przewidywalnym – w tym przypad-
ku reakcja na przerwanie nie zawsze bę-
dzie tak błyskawiczna jak to możliwe, ale
czas do rozpoczęcia obsługi przerwania
będzie możliwie ujednolicony dla wszyst-
kich zdarzeń ( interrupt balancing )
Listing 1. Prosty program sprawdzający wsparcie systemu dla wątków posix
#include “unistd.h”
#include “stdio.h”
int main ( void )
{
long rezultat = 0L ;
printf ( “\ n Wsparcie dla w ą tk ó w POSIX : );
rezultat = sysconf ( _SC_THREADS );
( rezultat > 0 ? printf ( jest .” ) : printf ( brak ! ));
}
Opcje przydatne
podczas tworzenia aplikacji
W piątym wierszu Tabeli 2. pokazano opcje
koniguracji systemu pomocne w debugowaniu
i optymalizacji. Powinny one być wyłączone w
docelowym systemie, gdyż powodują dodatko-
we, znaczne opóźnienia w realizacji zadań sys-
temu operacyjnego.
Tabela 3. Wybrane opcje standardu POSIX dla wsparcia aplikacji czasu rzeczywistego
OPCJA STANDARDU POSIX ZNACZENIE
_SC_THREADS
wsparcie dla wątków i muteksów w standardzie POSIX
_SC_THREAD_ THREADS_MAX
maksymalna ilość wątków możliwych do stworzenia w obrębie
jednego procesu
Mechanizm
komunikacji ze sprzętem
Standardowo sterowniki urządzenia to mo-
duły jądra, które komunikują się ze sprzę-
tem przez wywołania systemowe. Jest to
mechanizm wynikający z architektury sys-
temu i ze względów jego bezpieczeństwa,
czy jednak nadaje się do zastosowania w
systemach czasu rzeczywistego? Okazu-
je się, że nie zawsze! Jeżeli aplikacja mu-
si komunikować się z urządzeniem kilka-
krotnie zanim podejmie decyzję o reakcji,
to czas przełączania kontekstów jest zbyt
wysoką ceną za poprawną pracę urządzenia.
_SC_THREAD_ PRIORITY_SCHE-
DULING
wsparcie różnych algorytmów szeregowania i różnych warto-
ści priorytetów dla wątków w obrębie procesu
_SC_THREAD_ PRIO_INHERIT
wsparcie dla dziedziczenia priorytetów przez wątki
_SC_REALTIME_SIGNALS
wsparcie dla sygnałów czasu rzeczywistego
_SC_RTSIG_MAX
maksymalna liczba sygnałów czasu rzeczywistego dostęp-
nych dla jednej aplikacji
_SC_TIMERS
wsparcie dla zegarów czasu rzeczywistego
_SC_MONOTONIC_CLOCK
wsparcie dla źródła sygnału zegarowego napędzającego ze-
gary czasu rzeczywistego
_SC_SHARED_MEMORY_OBJECTS
wsparcie dla współdzielonych zasobów pamięci
_SC_MESSAGE_PASSING
wsparcie dla komunikacji międzywątkowej i międzyprocesoro-
wej (kolejek wiadomości)
56
listopad 2008
439033276.014.png 439033276.015.png
Programowanie
Mechanizmy czasu rzeczywistego okiem programisty sterowników
Wtedy pozostaje nam użycie mechanizmu
bezpośredniego dostępu do pamięci z apli-
kacji (z przestrzeni użytkownika!). Nie
każdy programista sterowników jest zwo-
lennikiem tej metody, ale znalazła ona po-
pularność i zastosowanie w tysiącach ste-
rowników dla urządzeń w systemach czasu
rzeczywistego i systemach wbudowanych.
Powszechnie znana jest jako metoda imple-
mentacji sterowników działających w prze-
strzeni użytkownika ( user - mode drivers ). W
opinii autora jest nawet bardziej bezpieczną
metodą dostępu do urządzenia, gdyż niepo-
żądana próba dostępu do obszarów chronio-
nych pamięci z poziomu użytkownika skut-
kuje błędem aplikacji segmentation fault
a ten sam krok wykonany z przestrzeni ją-
dra może doprowadzić do niestabilności a
wręcz zawieszenia jądra systemu.
Listing 2. Tworzenie wątku i deklaracja obsługi sygnału SIGINT
/* Adres początku pamięci sprzętowej urządzenia */
#deine POCZ_PAMIECI_URZADZENIA 0x0000
/* Rozmiar mapowanego obszaru pamięci */
#deine ROZMIAR_PAMIECI_URZADZENIA 0x1000
pthread_t watek1_sterownika = ( pthread_t ) 0 ;
pthread_t watek2_sterownika = ( pthread_t ) 0 ;
void procedura_watku1 ( void );
void procedura_watku2 ( void );
int main ( void )
{
void * wsk_pamieci = ( void *) 0 ;
watek1_sterownika = pthread_self ();
if ( signal ( SIGINT , ( void *) wylacz_sterownik ) = = SIG_ERR ) {
printf ( “\ n Nie udana operacja deklaracji obs ł ugi sygna ł u );
}
Mechanizmy
komunikacji wątków sterownika
Aby zapewnić sterownikowi działającemu w
przestrzeni użytkownika szybkość pracy zakła-
damy implementację wielowątkową zamkniętą
w jednym procesie (POSIX1.c). Daje nam to
możliwość użycia zasobów dzielonych ( shared
memory ), mechanizmów przesyłania informa-
cji ( message passing ) szybszych od IPC Syste-
mu V i synchronizacji za pomocą szybkich sy-
gnałów ( realtime signals ), które umożliwiają
przekazywanie parametrów wraz z dostarcze-
niem sygnału do wątku.
wsk_pamieci = mapuj_pamiec ( POCZ_PAMIECI_URZADZENIA ,
ROZMIAR_PAMIECI_URZADZENIA );
if ( wsk_pamieci != 0 )
{
printf ( ”\ n Mapowanie pami ę ci nie powiod ł o si ę” );
return (- 6 );
}
if ( tworz_watki () < 0 ) {
printf ( “\ n Nie udana pr ó ba stworzenia w ą tk ó w sterownika );
return (- 7 );
}
procedura_watku1 ();
}
Mechanizmy
dostarczania przerwań do sterownika
• Sterownik informowany przerwaniem o
zmianie stanu urządzenia ( interrupt - dri-
ven driver ). Ten akapit artykułu poświę-
cony został tak naprawdę jedynej sła-
bej stronie naszej koncepcji sterownika
pracującego w przestrzeni użytkowni-
ka. Tą słabą stroną jest brak szybkiego
i spójnego mechanizmu obsługi przerwań
z poziomu sterownika (przestrzeni użyt-
kownika). Prace nad stworzeniem takie-
go mechanizmu nadal trwają. Można so-
bie wyobrazić wykorzystanie mechani-
zmu obsługi przerwań w przestrzeni ją-
dra systemu i rejestrację obsługi prze-
rwania, w której jedynie generujemy sy-
gnał dostarczany do procesu sterowni-
ka aby poinformować go o przerwaniu.
W przypadku użycia sygnału czasu rze-
czywistego mamy gwarancję, że sygnał
dostanie dostarczony do procesu, ale nie
mamy gwarancji, że potrwa to tak krót-
ko jak tego oczekujemy. W 2006 roku
void wylacz_sterownik ( int signo )
{
puts ( Sterownik wylaczony );
/* Zakończenie pracy wątków */
if ( pthread_self () = = watek2_sterownika )
{
/* Zwolnienie alokowanej pamięci */
puts ( ”\ nWatek 2 wylaczony );
/* Unicestwienie wątku */ ;
pthread_exit (( void *) NULL );
}
else if ( pthread_self () = = watek1_sterownika )
{
puts ( ”\ nWatek 1 wylaczony );
_exit ( 0 );
}
}
58
listopad 2008
439033276.016.png 439033276.017.png
Programowanie
Mechanizmy czasu rzeczywistego okiem programisty sterowników
pojawiła się idea zaprezentowana przez
Petera Chubb zrzeszonego w grupie ER-
TOS 1 ( Embedded Real - Time Operating
Systems ) polegająca na stworzeniu spe-
cjalnego pliku w systemie /proc, któ-
ry byłby odczytywany przez sterownik
aby sprawdzić czy wystąpiło przerwa-
nie. Koncepcja ta jednak nie gwarantuje
spójności. Biorąc pod uwagę brak gwa-
rancji, że procedura obsługi przerwania
kiedyś się skończy, jedynym sposobem
zabezpieczenia systemu przed zawiesze-
niem w takiej sytuacji jest wyłączenie
przerwania procesora i wymazanie la-
gi informującej o jego zgłoszeniu przed
rozpoczęciem obsługi przerwania. Spra-
wa komplikuje się dodatkowo, gdy nasz
sterownik ma obsłużyć kilka przerwań
o różnych priorytetach i dopuszczamy
ich zagnieżdżanie.
• Sterownik odpytujący o stan urządzenia
( polling - driven driver ). Sterownik urzą-
dzenia nie musi komunikować się ze
sprzętem wykorzystując przerwania ( in-
terrupt - driven access ), większość urzą-
dzeń tego nie wymaga, alternatywą jest
cykliczne odpytywanie urządzenia o jego
stan ( polling - driven access ). Możemy so-
bie wyobrazić, że urządzenie, do którego
piszemy sterownik generuje zdarzenie nie
częściej niż co 10 milisekund i informuje
o nim procesor, aby ten mógł je obsłużyć.
Procesor może mieć wyłączone przerwa-
Listing 3. Funkcja mapuje obszar pamięci izycznej urządzenia do obszaru pamięci wirtualnej procesu sterownika
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
printf ( "Otwarcie /dev/mem nie powiodło się, kod
błędu: %d! \n " , dp );
return (( void *)- 4 );
}
/* Mapowanie pamieci urzadzenia do przestrzeni
adresowej procesu */
mem_wsk = mmap ( NULL , dlugosc_mapy , ( PROT_READ |
PROT_WRITE ) , MAP_SHARED , dp , adres_izyczny );
void * mapuj_pamiec ( off_t adres_izyczny , size_t dlugosc_
mapy )
{
int dp ; /* deskryptor pliku */
void * mem_wsk ; /* wskaznik na zmapowany obszar
pamieci urzadzenia
(wirtualny adres w przestrzeni adresowej procesu)
*/
if (( mem_wsk == MAP_FAILED ) || ( mem_wsk == NULL )) {
printf ( "Mapowanie pamięci urządzenia nie
powiodło się \n " );
close ( dp );
return (( void *)- 5 );
}
/* Tylko root może otrzymać dostęp do /dev/mem */
if ( geteuid () != 0 ) {
printf ( "Brak uprawnień do otwarcia /dev/mem!
(uruchom z uprawnieniami roota) \n " );
return (( void *)- 1 );
}
/* Zamkniecie pliku odwzorowującego pamięć systemu
(/dev/mem) */
if ( close ( dp ) != 0 ) {
printf ( "Zamkniecie /dev/mem nie powiodło się! \
n " );
}
return ( mem_wsk );
}
/* Weryikacja adresu izycznego początku mapowanego
obszaru pamięci */
if (( adres_izyczny % PAGE_SIZE ) != 0 ) {
printf ( "Adres izyczny nie jest wielokrotnością
PAGE_SIZE)! \n " );
return (( void *)- 2 );
}
/* przykłady dostępu do rejestrów urządzenia,
// zdeiniować jeden z poniższych trybów dostępu
// (uwaga, specyiczne dla kompilatora):
/* Weryikacja zakresu mapowanego obszaru pamieci */
if (( dlugosc_mapy % PAGE_SIZE ) != 0 ) {
printf ( "Długość mapowanego obszaru pamięci musi
być wielokrotnością PAGE_SIZE! \n " );
return (( void *)- 3 );
}
//#deine ACCESS_MODE (unsigned int)
/* 32-bitowy */
//# deine ACCESS_MODE ( unsigned short int )
/* 16-bitowy */
//# deine ACCESS_MODE ( unsigned char )
/* 8-bitowy */
/* Otwarcie pliku odwzorowujacego pamiec systemu (/
dev/mem) w trybie rw */
dp = open ( "/dev/mem" , O_RDWR | O_SYNC ) < 0 )
if ( dp < 0 )
{
// Zapis warto ś ci do rejestru :
*(( volatile ACCESS_MODE *)( adres_rejestru )) = wartosc ;
// Odczyt warto ś ci rejestru :
wartosc = ( ACCESS_MODE )*(( volatile ACCESS_MODE *)( adres_
rejestru ));
* /
www.lpmagazine.org
59
439033276.018.png 439033276.019.png
Zgłoś jeśli naruszono regulamin