IO Programming pl


Linux I/O port programming mini-HOWTO Autor: Riku Saikkonen Riku.Saikkonen@hut.fi v, 28 Grudnia 1997 Wersja polska: MichaÅ‚ Szwaczko michalsz@lena.zsg.lublin.pl v1.0, 1 Marca 2000 Ten dokument HOWTO opisuje programowanie sprzÄ™towych rejestrów wejÅ›cia/wyjÅ›cia oraz zatrzymywanie na niewielkie okresy czasu pracy programów użytkownika dziaÅ‚ajÄ…cych na Linuxie pracujÄ…cym w architek­ turze Intel x86. Dokument zostaÅ‚ napisany w standardzie ISO-8859-2. OryginaÅ‚ tego dokumentu znajduje siÄ™ pod adresem ftp://ftp.icm.edu.pl/pub/Linux/sunsite/docs/HOWTO/mini ______________________________________________________________________ Spis treÅ›ci 1. WstÄ™p 2. Używanie rejestrów wejÅ›cia/wyjÅ›cia w programach napisanych w C 2.1 Metoda zwykÅ‚a 2.2 Metoda alternatywna: /dev/port 3. Przerwania (IRQ) oraz dostÄ™p DMA 4. Mierzenie czasu z dużą dokÅ‚adnoÅ›ciÄ… 4.1 Opóźnienia 4.1.1 Opóźnianie za pomocÄ… funkcji sleep() i usleep() 4.1.2 Opóźnianie za pomocÄ… funkcji nanosleep() 4.1.3 Opóźnianie za pomocÄ… operacji I/O na porcie 4.1.4 Opóźnianie za pomocÄ… instrukcji asemblerowych 4.1.5 Instrukcja rdtsc w Pentium 4.2 Mierzenie czasu 5. Inne jÄ™zyki programowania 6. Niektóre przydatne porty 6.1 Port równolegÅ‚y 6.2 Port joysticka/Port gier 6.3 Port szeregowy 7. Porady 8. W razie kÅ‚opotów 9. PrzykÅ‚adowy program 10. Wyrazy uznania 11. Od tÅ‚umacza ______________________________________________________________________ 11.. WWssttęępp Ten dokument HOWTO opisuje programowanie sprzÄ™towych rejestrów wejÅ›cia/wyjÅ›cia oraz zatrzymywanie na niewielkie okresy czasu pracy programów użytkownika dziaÅ‚ajÄ…cych na Linuxie pracujÄ…cym w architekturze Intel x86. Dokument ten jest nastÄ™pcÄ… bardzo maÅ‚ego IO- port mini-HOWTO tego samego autora. Dokument zostaÅ‚ napisany przez Riku Saikkonen. Copyright 1995-1997 Riku Saikkonen. Po szczegóły odnoÅ›nie praw autorskich zobacz Linux HOWTO copyright . JeÅ›li chcesz coÅ› poprawić lub dodać to Å›miaÅ‚o możesz do mnie pisać (Riku.Saikkonen@hut.fi)... Zmiany w stosunku do poprzedniej wersji (30 Marca 1997): · WyjaÅ›nienie kwestii odnoszÄ…cych siÄ™ do inb_p/outb_p oraz portu 0x80 · UsuniÄ™cie informacji o udelay(), jako że nanosleep() zapewnia jaÅ›niejszy sposób jego użycia. · PrzeksztaÅ‚cenie dokumentu na format SGML-Linuxdoc oraz niewielka reorganizacja. · Wiele mniejszych dodatków i modyfikacji. 22.. UUżżyywwaanniiee rreejjeessttrróóww wweejjśścciiaa//wwyyjjśścciiaa ww pprrooggrraammaacchh nnaappiissaannyycchh ww CC 22..11.. MMeettooddaa zzwwyykkÅ‚Å‚aa Procedury dostÄ™pu do portów (rejestrów) we/wy umieszczone sÄ… w /usr/include/asm/io.h (lub w linux/include/asm-i386/io.h w źródÅ‚ach jÄ…dra) Procedury te wystÄ™pujÄ… w formie makr do wstawienia a wiÄ™c wystarczy że zrobisz #include ; nie potrzebujesz już żadnych dodatkowych bibliotek. Z powodu ograniczeÅ„ w gcc (obecna wersja 2.7.2.3 i poniżej) oraz egcs (wszystkie wersje) programy wykorzystujÄ…ce te procedury _m_u_s_z_Ä… być kompilowane z wÅ‚Ä…czonÄ… optymalizacjÄ… (gcc -O1 lub wiÄ™cej) lub możesz też zrobić #define extern bez parametru (puste) zanim wÅ‚Ä…czysz . Do odpluskwiania (debugging) możesz użyć gcc -g -O (przynajmniej w nowoczesnych wersjach gcc), chociaż optymalizacja może spowodować, iż debugger bÄ™dzie zachowywaÅ‚ siÄ™ trochÄ™ dziwnie. JeÅ›li to sprawia Ci kÅ‚opot, procedury korzystajÄ…ce z rejestrów we/wy wstaw do osobnego pliku i tylko ten plik poddaj optymalizacji podczas kompilacji. Zanim dostaniesz siÄ™ do jakiegokolwiek portu we/wy, musisz nadać swemu programowi uprawnienia do tego. Robi siÄ™ to wywoÅ‚ujÄ…c funkcjÄ™ ioperm() (zdeklarowanÄ… w unistd.h i zdefiniowanÄ… w jÄ…drze) gdzieÅ› w okolicach poczÄ…tku programu (przed jakimkolwiek dostÄ™pem do portów) SkÅ‚adnia tego polecenia to ioperm(skÄ…d,ile,wÅ‚acz) gdzie skÄ…d jest pierwszym portem do którego chcesz mieć dostÄ™p a ile liczbÄ… kolejnych portów do których chcesz mieć dostÄ™p. Dla przykÅ‚adu ioperm(0x300, 5, 1) da ci dostÄ™p do portów od 0x300 do 0x304 (w sumie piÄ™c portów). Ostatni argument to wartoÅ›c logiczna mówiÄ…ca o tym czy program otrzyma dostÄ™p do portów (1 - prawda) bÄ…dź nie (0 - faÅ‚sz). Możesz wywoÅ‚ywać ioperm() wiele razy aby wÅ‚Ä…czyć wiele nieciÄ…gÅ‚ych obszarów rejestrów. Zajrzyj do ioperm(2) w podrÄ™czniku systemowym man po szczegóły odnoÅ›nie skÅ‚adni. WywoÅ‚anie ioperm() wymaga aby twój program miaÅ‚ uprawnienia root'a: wobec czego albo musisz uruchamiać go jako root albo dać mu suid root'a. Po wywoÅ‚aniu ioperm() możesz już zrezygnować z uprawnieÅ„ root'a. Nie wymaga siÄ™ abyÅ› w sposób jawny wyÅ‚Ä…czaÅ‚ uprzywilejowany dostÄ™p do portów (czyli ioperm(....,0)) na koÅ„cu programu; robi siÄ™ to automatycznie wraz z zakoÅ„czeniem procesu. Funkcja setuid() w wypadku użytkownika bez przywilejów root'a nie odbiera dostÄ™pu do portów przydzielonego przez ioperm() ale funkcja fork() już tak. (proces potomny nie dostaje dostÄ™pu ale proces-rodzic go zachowuje) ioperm() może jedynie umożliwić dostÄ™p do portów od 0x000 do 0x3FF. JeÅ›li chcesz używać innych portów (wyższych) musisz użyć funkcji iopl() (która daje ci dostÄ™p do wszystkich portów od razu) Użyj argumentu 3 (czyli iopl(3)) aby dać swemu programowi dostÄ™p do _w_s_z_y_s_t_k_i_c_h portów (bÄ…dź ostrożny - dostÄ™p do niewÅ‚aÅ›ciwych portów może wywoÅ‚ać najróżniejsze usterki komputera). Musisz mieć uprawnienia root'a aby wywoÅ‚ać iopl(). Po szczególy zajrzyj do podrÄ™cznika systemowego man: iopl(2) Teraz wÅ‚aÅ›ciwy dostÄ™p do portów.. Aby odczytać bajt (8 bitów) z portu, wywoÅ‚aj funkcjÄ™ inb(port), zwraca ona odczytanÄ… wartość. Aby zapisać bajt do portu wywoÅ‚aj outb(wartość,port) (zwróć uwagÄ™ na kolejność argumentów) Aby odczytać sÅ‚owo (16 bitów) z portów x i x+1 (jeden bajt z każdego Å‚Ä…czone w sÅ‚owo za pomocÄ… asemblerowej instrukcji inw) wywoÅ‚aj inw(x) Aby zapisać sÅ‚owo do tych dwóch portów użyj outw(wartość,x) JeÅ›li nie jesteÅ› pewien której instrukcji użyć (operujÄ…cej bajtem czy sÅ‚owem) prawdopodobnie bÄ™dziesz chciaÅ‚ użyć inb() i outb() - wiÄ™kszość urzÄ…dzeÅ„ zaprojektowana jest z bajtowo- zorientowanym dostÄ™pem do portów. Zauważ, że wykonanie każdej instrukcji operujÄ…cej na portach zajmuje co najmniej mikrosekundÄ™. Makra inb_p(),outb_p(),inw_p() i outw_p() dziaÅ‚ajÄ… identycznie z tymi powyżej ale dodatkowo wykonujÄ… opóźnienie (okoÅ‚o 1 mikrosekundy) po dostÄ™pie do portu. Możesz spowodować że opóźnienie bÄ™dzie wartoÅ›ci ok 4 mikrosekund jeÅ›li zrobisz #define REALLY_SLOW_IO zanim wÅ‚Ä…czysz Makra te zwykle (chyba że zrobisz #define SLOW_IO_BY_JUMPING, które jest raczej mniej dokÅ‚adne) używajÄ… zapisu do portu 0x80 zby uzyskać opóźnienie, wobec czego musisz najpierw dać dostÄ™p do portu 0x80 za pomocÄ… ioperm(). Zapisy do portu 0x80 nie powinny mieć wpÅ‚ywu na żadnÄ… czÄ™sć systemu. JeÅ›li chcesz poznać bardziej wszechstronne metody dostÄ™pu do portów czytaj dalej. W stosunkowo nowych dystrybucjach podrÄ™cznika systemowego man znajdujÄ… siÄ™ strony ioperm(2), iopl(2) oraz powyższych makr. 22..22.. MMeettooddaa aalltteerrnnaattyywwnnaa:: //ddeevv//ppoorrtt Innym sposobem dostÄ™pu do rejestrów I/O jest otworzenie urzÄ…dzenia /dev/port do zapisu lub/i odczytu za pomocÄ… funkcji open() (/dev/port to urzÄ…dzenie znakowe, numer główny 1, poboczny 4) (Funkcje f*() z biblioteki stdio majÄ… wewnÄ™trzne buforowanie wiÄ™c ich unikaj) NastÄ™pnie wywoÅ‚aj lseek() do odpowiedniego bajtu w tym pliku (pozycja 0 = port 0x00 pozycja 1 = port 0x01 itd) i czytaj (read()) lub zapisuj (write()) bajt lub sÅ‚owo. OczywiÅ›cie aby to zadziaÅ‚aÅ‚o twój program musi mieć możliwoÅ›c czytania i zapisywania do /dev/port. Metoda ta jest prawdopodobnie wolniejsza od metody normalnej pokazanej powyżej ale nie potrzebuje ani optymalizacji programu ani wywoÅ‚ywania ioperm(). Nie potrzebuje też uprawnieÅ„ root'a jeÅ›li nadasz zwykÅ‚ym użytkownikom lub jakiejÅ› grupie prawa dostÄ™pu do /dev/port - jest to jednak nieporzÄ…dane z punktu widzenia bezpieczeÅ„stwa systemu, jako że możliwe jest wtedy uszkodzenie systemu, a może nawet zdobycie przywilejów root'a przez bezpoÅ›redni dostÄ™p za pomocÄ… /dev/port do dysków, kart sieciowych itp. 33.. PPrrzzeerrwwaanniiaa ((IIRRQQ)) oorraazz ddoossttęępp DDMMAA Nie można bezpoÅ›rednio korzystać z IRQ lub DMA w programach użytkownika. Musisz napisać sterownik/moduÅ‚ do jÄ…dra; zajrzyj do The Linux Kernel Hacker's Guide po szczegóły a także do źródeÅ‚ jÄ…dra po przykÅ‚ady. W programach użytkownika nie można też przerwaÅ„ wyÅ‚Ä…czać. 44.. MMiieerrzzeenniiee cczzaassuu zz dduużżąÄ… ddookkÅ‚Å‚aaddnnoośścciiÄ…Ä… 44..11.. OOppóóźźnniieenniiaa Przede wszystkim trzeba stwierdzić że z powodu wielozadaniowej natury Linuxa nie można zagwarantować że procesy w trybie użytkownika bÄ™dÄ… mieć dokÅ‚adnÄ… kontrolÄ™ czasu. Twój proces może zostać rozpoczÄ™ty w każdej chwili i może mu to zająć od 10 milisekund do kilku sekund (na bardzo obciążonych systemach). Jednakże, dla wiÄ™kszoÅ›ci aplikacji używajÄ…cych portów I/O nie ma to wiÄ™kszego znaczenia. Aby zminimalizować to zjawisko możesz nadać swemu procesowi wyższy priorytet (zobacz nice(2) w podrÄ™czniku man) lub używać zarzÄ…dzania procesami w czasie rzeczywistym (patrz niżej) JeÅ›li chcesz berdziej precyzyjnie odmierzać czas niż pozwalajÄ… ci na to procesy w trybie użytkownika, możesz skorzystać ze wsparcia dla procesów użytkownika w czasie rzeczywistym. JÄ…dra 2.x.x majÄ… niewielkie wsparcie dla czasu rzeczywistego; zobacz sched_setscheduler(2) w podrÄ™czniku man. Jest również specjalne jÄ…dro które ma zaawansowane wsparcie dla czasu rzeczywistego. Zobacz aby uzyskać wiÄ™cej informacji na ten temat. 44..11..11.. OOppóóźźnniiaanniiee zzaa ppoommooccÄ…Ä… ffuunnkkccjjii sslleeeepp(()) ii uusslleeeepp(()) Zacznijmy teraz od Å‚atwiejszych wywoÅ‚aÅ„. JeÅ›li chcesz opóźnieÅ„ rzÄ™du sekund to najpewniej jest użyć sleep(). Dla opóźnieÅ„ rzÄ™du przynajmniej dziesiÄ…tek milisekund (10ms wydaje siÄ™ być najmniejszym możliwym opóźnieniem) powinieneÅ› użyć usleep(). Funkcje te oddajÄ… czas innym procesom a wiÄ™c czas procesora nie jest marnowany. Zajrzyj do sleep(3) i usleep(3) w podrÄ™czniku man po szczegóły dotyczÄ…ce tych funkcji. JeÅ›li potrzebujesz opóźnieÅ„ mniejszych niż 50 milisekund (w zależnoÅ›ci od prÄ™dkoÅ›ci procesora i samego komputera oraz obciążenia systemu) oddawanie czasu procesora zajmuje zbyt wiele czasu ponieważ linuxowy zarzÄ…dca procesów (w architekturze x86) zwykle zabiera okoÅ‚o 10-30 milisekund zanim zwróci kontrolÄ™ do twojego procesu. Z tego powodu dla maÅ‚ych opóźnieÅ„ usleep() zwykle opóźnia o trochÄ™ wiÄ™cej czasu niż podajesz w parametrze a przynajmniej okoÅ‚o 10 ms. 44..11..22.. OOppóóźźnniiaanniiee zzaa ppoommooccÄ…Ä… ffuunnkkccjjii nnaannoosslleeeepp(()) W serii jÄ…der 2.0.x znajduje siÄ™ nowa funkcja systemowa nanosleep() (zobacz nanosleep(2) w podrÄ™czniku man) która pozwala opóźniać lub zatrzymywać proces na krótkie okresy czasu (kilka mikrosekund lub wiÄ™cej). Dla uzyskania opóźnieÅ„ <=2ms, jeÅ›li (i tylko wtedy) twój proces jest ustawiony na zarzÄ…dzanie z wsparciem dla czasu rzeczywistego (poprzez sched_setscheduler()), nanosleep() używa pÄ™tli opóźniajÄ…cej; w przeciwnym razie zatrzymuje proces tak jak usleep(). PÄ™tla opóźniajÄ…ca używa udelay() (wewnÄ™trznej funkcji jÄ…dra użtwanej przez wiele jego modułów) a dÅ‚ugość pÄ™tli jest obliczana na podstawie wartoÅ›ci BogoMips (prÄ™dkość tego rodzaju pÄ™tli opóźniajÄ…cej jest jednÄ… z rzeczy którÄ… BogoMips dokÅ‚adnie mierzy) Zobacz /usr/include/asm/delay.h po szczegóły odnoÅ›nie dziaÅ‚ania tego mechanizmu. 44..11..33.. OOppóóźźnniiaanniiee zzaa ppoommooccÄ…Ä… ooppeerraaccjjii II//OO nnaa ppoorrcciiee InnÄ… metodÄ… opóźniania o niewielkie iloÅ›ci mikrosekund sÄ… operacje I/O na portach. Czytanie/zapisywanie jakiegokolwiek bajtu z/do portu 0x80 (patrz wyżej jak to siÄ™ robi) powinno dać opóźnienie prawie dokÅ‚adnie 1 mikrosekundy bez wzglÄ™du na typ procesora i jego prÄ™dkość. Możesz tak robić wiele razy aby uzyskać opóźnienie rzÄ™du kilku mikrosekund. Sposób ten nie powinien wywoÅ‚ywać żadnych szkodliwych efektów ubocznych na żadnym standardowym komputerze (nawet niektóre moduÅ‚y jÄ…dra go używajÄ…). W ten sposób uzyskujÄ… opóźnienie funkcje {in|out}[bw]_p() (zobacz asm/io.h). W zasadzie, instrukcje I/O na wiÄ™kszoÅ›ci portów w obszarze 0-0x3ff zbierajÄ… prawie dokÅ‚adnie 1 mikrosekundÄ™, wiÄ™c jeÅ›li na przykÅ‚ad używasz bezpoÅ›rednio portu równolegÅ‚ego po prostu wykonaj kilka razy inb() z tego portu aby uzyskać opóźnienie. 44..11..44.. OOppóóźźnniiaanniiee zzaa ppoommooccÄ…Ä… iinnssttrruukkccjjii aasseemmbblleerroowwyycchh JeÅ›li znasz typ procesora i prÄ™dkoÅ›c zegara w komputerze na którym bÄ™dzie dziaÅ‚aÅ‚ twój program, możesz na staÅ‚e uzyskać krótsze opóźnienia poprzez zastosowanie pewnych rozkazów asemblerowych (pamiÄ™taj jednak że twój proces może siÄ™ zacząć w dowolnym momencie wobec czego opóźnienia te mogÄ… być wiÄ™ksze od czasu do czasu) W tabeli poniżej wewnÄ™trzna prÄ™dkość procesora okreÅ›la liczbÄ™ cykli np dla procesora 50MHz (np. 486DX-50 lub 486DX2-50) jeden cykl zegara zajmuje 1/50000000 sekundy. (200 nanosekund). Instrukcja cykle zegara na 386 cykle zegara na 486 nop 3 1 xchg %ax,%ax 3 3 or %ax,%ax 2 1 mov %ax,%ax 2 1 add %ax,0 2 1 (Przykro mi ale niewiele wiem o Pentium. Pewnie podobnie do 486. Nie mogÄ™ znaleźć żadnej instrukcji która zajmowaÅ‚a by tylko jeden cykl zegara na 386. JeÅ›li możesz, używaj instrukcji jednocyklowych, w prze­ ciwnym razie architektura potokowa (pipelining) używana w nowoczesnych procesorach może dać jeszcze krótsze czasy) Rozkazy nop i xchg z tabeli powyżej nie powinny powodować żadnych skutków ubocznych. Reszta może modyfikować rejestr znaczników ale nie powinno mieć to znaczenia bo gcc powinno to wykryć. Użycie nop jest dobrym wyborem. Aby skorzystać z powyższego, trzeba w swoim programie wywoÅ‚ać funkcjÄ™ asm("instrukcja") SkÅ‚adnia instrukcji jest taka sama jak w tabeli powyżej. JeÅ›li chcesz użyć kilku instrukcji w jednym wywoÅ‚aniu funkcji asm rozdziel je Å›rednikami. Na przykÅ‚ad asm("nop ; nop ; nop ; nop") wywoÅ‚a cztery razy instrukcjÄ™ nop opóźniajÄ…c nasz program o 4 cykle na 486 lub Pentium (lub 12 cykli na 386) Funkcja asm() jest przez gcc tÅ‚umaczona na wstawkÄ™ w asemblerze a wiÄ™c nie ma zagrożenia przekroczenia limitu wywoÅ‚aÅ„ funkcji. Opóźnienia krótsze niż jeden cykl zegara nie sÄ… możliwe w architekturze Intel i386. 44..11..55.. IInnssttrruukkccjjaa rrddttsscc ww PPeennttiiuumm JeÅ›li masz Pentium, możesz odczytać ilość cykli zegara które upÅ‚ynęły od ostatniego uruchomienia komputera. Robi siÄ™ to za pomocÄ… takiego kodu w C: ______________________________________________________________________ extern __inline__ unsigned long long int rdtsc() { unsigned long long int x; __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); return x; } ______________________________________________________________________ Możesz odczytywać tÄ… wartość w celu opóźniania o dowolnÄ… ilość cykli. 44..22.. MMiieerrzzeenniiee cczzaassuu Dla czasów rzÄ™du sekundy prawdopodobnie najÅ‚atwiej bÄ™dzie użyć funkcji time(). Dla bardziej dokÅ‚adnych pomiarów: gettimeofday() jest dokÅ‚adne co do mikrosekundy (ale zobacz wyżej o zarzÄ…dzaniu procesami) Dla Pentium fragment kodu rdtsc powyżej jest dokÅ‚adny co do cykla zegarowego. JeÅ›li chcesz aby twój proces dostawaÅ‚ jakiÅ› sygnaÅ‚ po jakimÅ› czasie, użyj settimer() lub alarm(). Zajrzyj do stron podrÄ™cznika man dotyczÄ…cych tych funkcji. 55.. IInnnnee jjęęzzyykkii pprrooggrraammoowwaanniiaa Opis powyżej koncentruje siÄ™ na jÄ™zyku C. Powinien bezpoÅ›rednio odnoÅ›ić siÄ™ też do C++ i Objective C. W asemblerze musisz wywoÅ‚ać ioperm() lub iopl() tak jak w C ale potem możesz już używać instrukcji czytania/zapisywania portów bezpoÅ›rednio. W innych jÄ™zykach, jeÅ›li nie możesz wstawiać do programu wstawek w asemblerze lub C bÄ…dź jeÅ›li nie możesz użyć funkcji systemowych opisanych powyżej, najÅ‚atwiej bÄ™dzie napisać osobny program w C ze wszystkimi operacjami na portach I/O i wszystkimi opóźnieniami których potrzbujesz po czym skompilować go i zlinkować z resztÄ… twojego programu. Możesz też użyć /dev/port jak to opisano powyżej. 66.. NNiieekkttóórree pprrzzyyddaattnnee ppoorrttyy Teraz trochÄ™ informacji programistycznych dotyczÄ…cych zwykÅ‚ych portów które mogÄ… być bezpoÅ›rednio użyte do operacji I/O w logice TTL (lub CMOS). JeÅ›li chcesz używać tych lub innych zwykÅ‚ych portów zgodnie z ich normalnym przeznaczeniem (np chcesz sterować normalnÄ… drukarkÄ… bÄ…dź modemem) powinieneÅ› najpewniej użyć istniejÄ…cych sterowników (zwykle doÅ‚Ä…czonych do jÄ…dra) zamiast programować porty bezpoÅ›rednio jak to opisuje ten dokument. Ten rozdziaÅ‚ jest dla tych którzy chcÄ… podÅ‚Ä…czyć do standardowych portów komputera wyÅ›wietlacze LCD, silniki krokowe lub inne niestandardowe urzÄ…dzenia elektroniczne. JeÅ›li chcesz sterować jakimÅ› urżądzeniem produkowanym na rynek masowy, np. skanerem (które to urzÄ…dzenie jest już na rynku jakiÅ› czas) poszukaj raczej istniejÄ…cego sterownika Linuxowego. Dobrym miejscem aby zacząć jego poszukiwania jest Hardware-HOWTO www.hut.fi/Misc/Electronics jest dobrym źródÅ‚em informacji dotyczÄ…cych podÅ‚Ä…czania urzÄ…dzeÅ„ do komputera (jak i samej elektroniki w ogóle) 66..11.. PPoorrtt rróówwnnoolleeggÅ‚Å‚yy Adres bazowy portu równolegÅ‚ego (zwany poniżej >BASE) to 0x3bc dla /dev/lp0, 0x378 dla /dev/lp1 i 0x278 dla /dev/lp2. JeÅ›li chcesz sterować tylko czymÅ› co dziaÅ‚a jak normalna drukarka powinieneÅ› zapoznać siÄ™ z Printing-HOWTO. Oprócz standardowego trybu tylko-do-zapisu opisanego powyżej, w wiÄ™kszoÅ›ci portów równolegÅ‚ych istnieje jeszcze rozszeżony tryb dwukierunkowy. Po informacje na ten temat oraz na temat nowych trybów ECP/EPP (jak i samego standardu IEEE 1284 w ogóle) zajrzyj na http://www.fapo.com oraz na http://www.senet.com.au/~cpeacock/parallel.htm PamiÄ™taj, że skoro nie możesz używać DMA i IRQ w programach użytkownika, aby użyć trybów ECP/EPP bÄ™dziesz prawdopodobnie musiaÅ‚ napisać wÅ‚asny sterownik do jÄ…dra. Zdaje siÄ™, że ktoÅ› już pisze taki sterownik ale nie znam szczegółów. Port BASE+0 (port danych) kontroluje sygnaÅ‚y danych portu (D0 do D7 dla bitów od 0 do 7) Stany: 0=niski (0 V), 1=wysoki (5 V). Zapis do tego portu zatrzaskuje dane na pinach. Odczyt zwraca ostatnio zapisanÄ… danÄ… w trybie normalnym bÄ…dź rozszeżonym lub dane z innego urzÄ…dzenia w rozszeżonym trybie odczytu. Port BASE+1 (port statusu) jest tylko-do-odczytu i zwraca stan poniższych sygnałów wejsciowych. · Bity 0 i 1 sÄ… zarezerwowane. · Bit 2 Status IRQ (nie jest to sygnaÅ‚ z pina - nie wiem w jaki sposób to dziaÅ‚a) · Bit 3 ERROR (1=stan wysoki) · Bit 4 SLCT (1=stan wysoki) · Bit 5 PE (1=stan wysoki) · Bit 6 ACK (1=stan wysoki) · Bit 7 -BUSY (0=stan wysoki) (Nie jestem pewien stanów tych bitów.) Port BASE+2 (Port kontrolny) jest tylko do zapisu (odczyt zwraca ostatnio zapisanÄ… wartość) i kontroluje poniższe sygnaÅ‚y kontrolne: · Bit 0 -STROBE (0=stan wysoki) · Bit 1 AUTO_FD_XT (1=stan wysoki) · Bit 2 -INIT (0=stan wysoki) · Bit 3 SLCT_IN (1=stan wysoki) · Bit 4 gdy ustawiony na 1 - wÅ‚Ä…cza IRQ portu równolegÅ‚ego (co ma miejsce przy przejsciu sygnaÅ‚u ACK ze stanu niskiego do wysokiego) · Bit 5 kontroluje kierunek danych w trybie rozszeżonym (0 = zapis, 1 = odczyt) i jest caÅ‚kowicie tylko-do-zapisu. (Odczyt nie zwraca niczego użytecznego dla tego bitu). · Bity 6 i 7 sÄ… zarezerwowane. (Znowu nie jestem pewien stanów.) RozkÅ‚ad wyprowadzeÅ„. (25 pinowe żeÅ„skie gniazdo typu D) (i=wejscie, o=wyjscie): 1io -STROBE, 2io D0, 3io D1, 4io D2, 5io D3, 6io D4, 7io D5, 8io D6, 9io D7, 10i ACK, 11i -BUSY, 12i PE, 13i SLCT, 14o AUTO_FD_XT, 15i ERROR, 16o -INIT, 17o SLCT_IN, 18-25 Ground Specyfikacja IBM twierdzi że piny 1,14,16 i 17 (wyjscia kontrolne) majÄ… otwarte kolektory podpiÄ™te do +5V przez 4.7 kiloomowe oporniki (dostarcza 20 mA, pobór 0.55 mA, wyjscie w stanie wysokim +5V minus to co podpiÄ™te) Reszta pinów pobiera 24 mA, dostarcza 15 mA a wyjscie w stanie wysokim to minimum 2.4V. Stan niski dla wszystkich to maximum 0.5V. Porty równolegÅ‚e inne niż IBM prawdopodobnie odbiegajÄ… od tego standardu. Po wiÄ™cej informacji na ten temat zajrzyj na http://www.hut.fi/Misc/Electronics/circuits/lptpower.html Na koniec jeszcze ostrzeżenie: Uważaj z uziemieniem. ZepsuÅ‚em już parÄ™ portów przez podÅ‚Ä…czanie siÄ™ do nich gdy komputer byÅ‚ wÅ‚Ä…czony. Dobrze jest w takim wypadku używać portów równolegÅ‚ych nie zintegrowanych z pÅ‚ytÄ… głównÄ… (zwykle można dodać drugi port równolegÅ‚y do komputera za pomocÄ… taniej standardowej karty I/O (tzw ajoÅ‚ki - tÅ‚um); po prostu wyÅ‚Ä…cz porty których nie potrzebujesz i ustaw adres portu na karcie IO na jakiÅ› wolny adres. Nie musisz siÄ™ martwić o IRQ dla portu równolegÅ‚ego gdyż normalnie siÄ™ go nie używa) 66..22.. PPoorrtt jjooyyssttiicckkaa//PPoorrtt ggiieerr Port gier jest umieszczony pod adresami 0x200-0x207. JeÅ›li chcesz kontrolować normalny joystick to jest do tego specjalny sterownik w jÄ…drze, zobacz Plik nazywa siÄ™ joystick-*. RozkÅ‚Ä…d wyprowadzeÅ„ od stony portu (15-pinowe żeÅ„skie gniazdo typu D- shell): · piny 1,8,9,15: +5 V (zasilanie) · piny 4,5,12: Masa · piny 2,7,10,14: Wejscia cyfrowe (Odpowiednio: BA1, BA2, BB1, i BB2) · piny 3,6,11,13: Wejscia ``analogowe'' (Odpowiednio: AX, AY, BX, i BY) Piny +5V zwykle sÄ… podÅ‚Ä…czane bezpoÅ›rednio do linii zasilania na pÅ‚ycie głównej, wiÄ™c, w zależnoÅ›ci od pÅ‚yty, zasilacza i portu ,powinny dawać caÅ‚kiem sporo mocy. Cyfrowe wejÅ›cia sÄ… używane dla przycisków joysticków które możesz sobie podÅ‚Ä…czyć do portu (joystick A i B, dwa przyciski każdy) WejÅ›cia te powinny być na poziomach TTL a ich stan możesz odczytać z portu statusu (zobacz poniżej) Prawdziwy joystick zwraca stan niski (0V) kiedy przycisk jest naciÅ›niÄ™ty a stan wysoki (+5V z pinów zasilajÄ…cych przez jednokiloomowy rezystor) kiedy jest zwolniony. Tak-zwane wejÅ›cia analogowe w istocie mierzÄ… opór. Port joysticka ma przyÅ‚Ä…czony do tych 4 wejść poczwórny multiwibrator (quad one-shot multivibrator) (scalak 558) Na każdym wejÅ›ciu mamy rezystor 2.2k pomiÄ™dzy pinem a wejÅ›ciem multiwibratora oraz kondensator 0.01uF pomiÄ™dzy wyjÅ›ciem multiwibratora a masÄ…. Prawdziwy joystick ma jeszcze potencjometr dla każdej z osi (X i Y) umieszczony pomiÄ™dzy +5V a wÅ‚aÅ›ciwym pinem wejsćiowym (AX lub AY dla joysticka A oraz BX lub BY dla joysticka B) Kiedy jest aktywny, multiwibrator ustawia swoje wyjÅ›cia w stan wysoki (5V) i oczekuje aż każdy z kondensatorów osiÄ…gnie 3.3V po czym ustawia w stan niski odpowiednie linie wyjÅ›ciowe. Dlatego wÅ‚aÅ›nie czas trwania okresu kiedy multivibrator jest w stanie wysokim jest proporcjonalny do oporu potencjometru joysticka. (czyli pozycji joysticka na odpowiedniej osi) Relacja wyglÄ…da tak: R = (t - 24.2) / 0.011, gdzie R to opór potencjometru w omach a t to czas trwania stanu wysok­ iego w sekundach. Wobec tego aby odczytać wejśćia analogowe musisz najpierw uaktywnić multiwibrator (za pomocÄ… zapisu do odpowiedniego portu - patrz niżej) po czym odczytywać stan czterech osi (za pomocÄ… nastÄ™pujÄ…cych po sobie odczytów z portów) aż zmieniÄ… stan z wysokiego na niski po czym mierzysz czas trwania stanu wysokiego. Odczytywanie takie zużywa sporo czasu procesora, co w systemie wielozadaniowym takim jak Linux nie bÄ™dÄ…cym systemem czasu rzeczywistego powoduje niedokÅ‚Ä…dność rezultatów gdyż nie można odczytywać portu stale (chyba że użyjesz sterownika niskopoziomowego i wyÅ‚Ä…czysz przerwania na czas odczytów - ale to zabiera jeszcze wiÄ™cej czasu procesora). JeÅ›li wiesz że przejÅ›cie do stanu niskiego zajmie sygnaÅ‚owi dÅ‚użśzy czas (rzÄ™du 10 ms) możesz użyć usleep() przed odczytem oddajÄ…c w ten sposób czas procesora innym procesom. Jedynym portem do którego potrzebujesz mieć dostÄ™p to port 0x201 (inne porty zachowujÄ… siÄ™ identycznie bÄ…dź nie robiÄ… nic). Każdy zapis (nie ważne czego) do tego portu uaktywnia multiwibrator. Odczyt z tego portu zwraca stan poszczególnych sygnałów wejÅ›ciowych. · Bit 0: AX (stan (1=stan wysoki) wyjśćia multiwibratora) · Bit 1: AY (stan (1=stan wysoki) wyjśćia multiwibratora) · Bit 2: BX (stan (1=stan wysoki) wyjśćia multiwibratora) · Bit 3: BY (stan (1=stan wysoki) wyjśćia multiwibratora) · Bit 4: BA1 (wejśćie cyfrowe, 1=stan wysoki) · Bit 5: BA2 (wejśćie cyfrowe, 1=stan wysoki) · Bit 6: BB1 (wejśćie cyfrowe, 1=stan wysoki) · Bit 7: BB2 (wejśćie cyfrowe, 1=stan wysoki) 66..33.. PPoorrtt sszzeerreeggoowwyy JeÅ›li urzÄ…dzenie z którym siÄ™ komunikujesz przypomina coÅ› co dziaÅ‚Ä… jak RS-232 możęsz do tego celu użyć portu szeregowego. Linuxowy sterownik portu szeregowego powinien wystarczyć w prawie wszystkich zastosowaniach (nie powinienneÅ› mieć potrzeby programować port bezpoÅ›rednio, a nawet jeÅ›li chciaÅ‚byÅ› to robić prawdopodobnie musiaÅ‚byÅ› napisać wÅ‚asny moduÅ‚ do jÄ…dra.) Sterownik Linuxowy jest caÅ‚kiem wszechstronny a wiÄ™c używanie na przykÅ‚ad niestandardowych prÄ™dkoÅ›ci portu nie powinno być problemem. JeÅ›li chcesz dowiedzieć siÄ™ wiÄ™cej o programowaniu portu szeregowego w Linuxie zobacz stronÄ™ termios(3) w podrÄ™czniku systemowym man, źródÅ‚a sterownika (linux/drivers/char/serial.c), i . 77.. PPoorraaddyy JeÅ›li zależy Ci na dobrej obsÅ‚udze analogowej transmisji I/O, możesz podÅ‚Ä…czyć do portu równolegÅ‚ego przetworniki analogowo-cyfrowe bÄ…dż cyfrowo-analogowe (ADC,DAC).(Podpowiedź: weż zasilanie z portu joysticka bÄ…dż z wolnej wtyczki zasilania dysku twardego wyprowadzonej na zewnÄ…trz obudowy, chyba że masz urzÄ…dzenie nie wymagajÄ…ce dużej mocy, wtedy możesz wziąść zasilanie z samego portu. Możesz też użyć zewnÄ™trznego zasilacza.) Możesz też kupić kartÄ™ przetworników analogowo-cyfrowych i cyfrowo analogowych (AD/DA) (wiÄ™kszość starszych/wolniejszych takich kart jest sterowana za pomocÄ… portów I/O) JeÅ›li nie przeszkadza ci maÅ‚Ä… ilość kanałów (1 lub 2) niedokÅ‚adność oraz (możliwe) zÅ‚e zerowanie, dobra (i szybka) bÄ™dzie tania karta dżwiÄ™kowa wspierana przez Linuxowy sterownik. W czuÅ‚ych urzÄ…dzeniach analogowych niewÅ‚aÅ›ciwe uziemienie możę spowodować bÅ‚Ä™dy na wejÅ›ciach bÄ…dź wyjÅ›ciach. JeÅ›li przytrafi Ci siÄ™ coÅ› takiego, możesz spróbować odizolować elektrycznie urzÄ…dzenie od komputera przez użycie transoptorów (optocouplers) na _w_s_z_y_s_t_k_i_c_h sygnaÅ‚ach pomiÄ™dzy Twoim urzÄ…dzeniem a komputerem. Aby zapewnić lepszÄ… izolacjÄ™ zasilanie do transoptorów spróbuj wziąść z komputera (wolne sygnaÅ‚y na porcie mogÄ… dać wystarczajÄ…cÄ… ilość mocy) JeÅ›li szukasz oprogramowania do projektowania pÅ‚ytek drukowanych na Linuxa to jest darmowa aplikacja która nazywa siÄ™ Pcb i powinna sprawiać siÄ™ dobrze, przynajmniej wtedy kiedy nie robisz czegoÅ› bardzo skomplikowanego. ZaÅ‚Ä…czona jest ona do wielu dystrybucji Linuxa a dostÄ™pna na (plik pcb-*). 88.. WW rraazziiee kkÅ‚Å‚ooppoottóóww PP11.. Dostaje bÅ‚Ä…d segmentacji pamiÄ™ci kiedy dobieram siÄ™ do portów OO11.. Albo twój program nie ma uprawnieÅ„ root'a bÄ…dź wywoÅ‚anie ioperm() nie powiodÅ‚o siÄ™ z jakiegoÅ› innego powodu. Sprawdź wartość powrotnÄ… funkcji ioperm(). Sprawdź również czy rzeczywiśćie operujesz na portach do których uzyskaÅ‚eÅ› dostÄ™p za pomocÄ… ioperm() (zobacz P3). JeÅ›li używasz makr opóźniajÄ…cych (inb_p(), outb_p(), itd), pamiÄ™taj aby wywoÅ‚ać ioperm() również wtedy jeÅ›li chcesz uzyskać dostÄ™p do portu 0x80 PP22.. Nie mogÄ™ nigdzie znaleść deklaracji funkcji in*(), out*() i gcc narzeka na niezdefiniowane referencje. OO22.. Nie kompilowaÅ‚eÅ› z wÅ‚Ä…czonÄ… optymalizacjÄ… (-O), i w ten sposób gcc nie mógÅ‚ odnaleźć makr w katalogu asm/io.h. Albo nie wÅ‚Ä…czyÅ‚eÅ› w ogóle do swojego programu. PP33.. WywoÅ‚Ä…nie out*() nie robi nic bÄ…dź robi coÅ› dziwnego. OO33.. Sprawdź kolejność parametrów; powinno być outb(wartość, port), a nie outportb(port, wartość) co jest popularne w MS-DOS. PP44.. ChcÄ™ sterować standardowym urzÄ…dzeniem RS-232/portem równolegÅ‚ym/drukarkÄ…/joystickiem OO44.. Lepiej bÄ™dzie jak użyjesz istniejÄ…cych sterowników z jÄ…dra, X serwera lub czegoÅ› innego. Sterowniki te sÄ… zazwyczaj dosyć wszechstronne wiÄ™c nawet lekko niestandardowe urzÄ…dzenia z nimi współpracujÄ…. Zobacz wyżej informacje o zwykÅ‚ych portach, sÄ… tam odnoÅ›niki do stosownej dokumentacji. 99.. PPrrzzyykkÅ‚Å‚aaddoowwyy pprrooggrraamm Oto kawaÅ‚ek prostego przykÅ‚adowego programu demonstrujÄ…cego dostÄ™p do rejestrów I/O. ______________________________________________________________________ /* * example.c: bardzo prosty przykÅ‚ad dostÄ™pu do portów I/O * * Program ten nie robi nic użytecznego, zapisuje do portu, czeka i * odczytuje z portu. Kompilacja: gcc -O2 -o example example.c * Uruchamiac jako ./example bÄ™dÄ…c root'em / #include #include #include #define BASEPORT 0x378 /* lp1 */ int main() { /* Uzyskaj dostÄ™p do portów */ if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);} /* Ustaw wszystkie bity danych (D0-D7) w stan niski (0) */ outb(0, BASEPORT); /* Zaczekaj chwilkÄ™ (100 ms) */ usleep(100000); /* Odczytaj z rejestru statusowego (BASE+1) i wyÅ›wietl rezultat */ printf("status: %d\n", inb(BASEPORT + 1)); /* Już nie potrzebujemy portów */ if (ioperm(BASEPORT, 3, 0)) {perror("ioperm"); exit(1);} exit(0); } /* koniec example.c */ ______________________________________________________________________ 1100.. WWyyrraazzyy uuzznnaanniiaa PomogÅ‚o mi zbyt wiele osób aby je tutaj wszystkie wymienić, ale wszystkim bardzo dziÄ™kujÄ™. Nie odpowiedziaÅ‚em im wszystkim; przepraszam za to i jeszcze raz dziÄ™ki za pomoc. 1111.. OOdd ttÅ‚Å‚uummaacczzaa Niniejsze tÅ‚umaczenie objÄ™te jest prawami autorskimi MichaÅ‚a Szwaczko. Dozwolone jest rozpowszechnianie i dystrybucja na prawach takich samych jak dokument oryginalny.(Zobacz HOWTO-Copyright) Zmiany wprowadzone przeze mnie do dokumentu polegajÄ… na zastÄ…pieniu adresów niektórych serwerów ftp przez ich mirrory w Polsce. ZdajÄ™ sobie sprawÄ™ że tÅ‚umaczenie nie jest wolne od wad i bÅ‚Ä™dów. JeÅ›li znajdziesz jakieÅ›, proszÄ™ napisz do mnie: michalsz@lena.zsg.lublin.pl OficjalnÄ… stronÄ… grupy tÅ‚umaczy HOWTO jest http://www.jtz.org.pl

Wyszukiwarka

Podobne podstrony:
io programming pl 11
io programming pl 1
io programming pl 2
IO Programming pl (3)
IO Programming pl (2)
io programming pl 10
io programming pl 9
io programming pl 3
io programming pl 6
io programming pl 8
io programming pl 7
io programming pl 4
io programming pl 5
TK IO[pdf][PL] Pobrany z torrenty org ® nfo nfo
COMPACT IO PRESENTATION PL
amd102 io pl09
io port programming 3ogqzy3bscrrpgv753q3uywjfexgwwoiiffd46a 3ogqzy3bscrrpgv753q3uywjfexgwwoiiffd46a
acu 250 io pl14

więcej podobnych podstron