Řízení PS/2 myši

   Sběrnice PS/2 (IBM Personal System/2) se prvně objevila koncem osmdesátých let a i dnes je stále používána pro komunikaci s klávesnicí a myší. Vývoj sice nezadržitelně směřuje k postupnému vytlačení PS/2 ve prospěch USB, ale PS/2 myši i klávesnice jsou dnes stále výborně dostupné a nadále se vyrabějí, takže v následujících letech bude stále dost zařízení k experimentování. V devadesátých letech se na krátkou dobu objevily myšítka pro COM port, ale ty se v podstatě nikdy neuchytily - dnes je to spíš rarita, takže navrhovat pro ně nějaké zařízení není zrovna perspektivní (byť jsou nepochybně snáze ovladatelné).

Zapojení konektorů, význam signálů

   Pro myš i klávesnici se původně používaly miniaturní konektory mini-DIN. U klávesnic se pak jistou dobu využíval klasický 5-pinový DIN konektor, ale nakonec se opět přešlo k mini-DIN. Protokol však zůstal stejný. Oba konektory obsahují GND, napájení +5V a 2 signálové vodiče - hodiny (clk) a data. Při koupi nového mini-DIN konektoru je třeba vybrat správný typ, protože se vyrábí přinejmenším 6 různých variant, které se liší jak tvarem klíče, tak rozmístěním a počtem vývodů.

5-pinová DIN zásuvka:
1 - clk
2 - data
3 - nc
4 - GND
5 - +5V
6-pinová mini-DIN zásuvka pro PS/2 myš:
1 - data
2 - nc
3 - GND
4 - +5V
5 - clk
6 - nc

PS/2 protokol

   Jde o synchronní obousměrný protokol master-slave, který umožňuje připojit jen jediné slave zařízení (v našem případě myš). Důležitou vlastností je, že hodiny generuje vždy slave. Master (PC nebo v našem případě MCU) je ovšem nadřazen - pomocí clk signálu povoluje, zakazuje nebo přerušuje přenos dat. Hodinový kmitočet se pohybuje v rozmezí cca 10-16kHz. Oba signály (data i hodiny) jsou řešeny s otevřeným kolektorem podobně jako I2C. Vhodná hodnota zvedacích odporů je asi 1k - 2k2. Větší hodnoty odporů by už mohly nepříznivě prodlužovat hrany signálů.

Přenos "slave >> master"

   Slave může samovolně zahájit přenos jenoho bytu pokud jsou obě linky (clk i data) v úrovni high po dobu nejméně 50us. Datový rámec obsahuje celkem 11 bitů. Přenos je zahájen start bitem s úrovní low, následuje 8 bitů dat řazených od nejméně významného, dále je zde paritní bit (lichá parita - high pro sudý počet jedniček v datech) a konečně stop bit s úrovní high. Mimo to, že hodiny generuje slave je zde ještě jedna nepříjemnost - master by měl číst stav datové linky nikoliv se sestupnou hranou hodin, ale přesně uprotřed low úrovně hodin. To odpovídá přibližně 15-25us po sestupné hraně hodin. Toto je poměrně velká nepříjemnost, pokud je příjem řešen pomocí přerušení.


   Z vlastní zkušenosti bych ještě doplnil, že se vyplatí po detekování poslední vzestupné hrany hodin počkat alespoň 100us než se pokusíte o další přenos master >> slave. Bez tohoto zpoždění se většina PS/2 zařízení chovala dost nepředvídatelně. Navíc díky hodinám od slave zařízení může vlivem rušení nebo odpojení zařízení dojít k "vytuhnutí" master obvodu, takže rozhodně není od věci doplnit timeouty.

Přenos "master >> slave"

   Přenos bytu do zařízení se od opačného směru trochu liší. Předně master musí vyslat požadavek na přenos dat (request-to-send). To se provede následovně: Nejprve master stáhne hodiny do low úrovně na nejméně 100us, čímž bezpečně zablokuje případný přenos opačným směrem. Následně master stáhne do low i data (což je vlastně start bit) a počká dalších alespoň 5us, pak uvolní hodiny načež by měl slave zareagovat nejhůře do 10ms tak, že začne generovat hodiny. Polarita hodin je při přenosu do zařízení přesně opačná - slave vzorkuje data přesně uprostřed high úrovně hodin, master mění hodnotu dat během low úrovně hodin (nejlépe přesně uprostřed).


   Jak je z přiloženého grafu vidět, tak po přenosu všech datových bitů, liché parity a stop bitu následuje ještě potvrzovací bit "ack" generovaný slave zařízením a to ještě během high úrovně hodin, kde má slave vzorkovat stop bit! Opět je vhodné doplnit timeouty.

Komunikační protokol - příkazy

   Po připojení k napájení by myš měla provést "selftest" a v případě úspěchu vrátit hodnoty 0xAA (selftest ok) a 0x00 (mouse ID). ID 0x00 značí standardní 2/3-tlačítkovou myš. V rámci zpětné kompatibility se po resetu musí všechny myši nastavit do tohoto režimu. Různé rozšíření jako třeba známé "kolečko" se pak zapínají speciální sekvencí příkazů.
Reset (0xFF) - reset myšítka, odpověď by měla být 0xFA (ack - potvrzení příkazu), 0xAA (selftest ok) a opět ID 0x00.
Read ID (0xF2) - vrátit ID zařízení, odpověď by měla být 0xFA a ID. Několik základních ID je uvedeno v tabulce, ale existuje celá řada dalších rozšíření.

ID Zařízení
0x00 Standardní myš
0x03 M$ Intellimouse (myš s kolečkem)
0x04 Explorer mouse (myš s kolečkem, dva čudly navíc)
0xAB Klávesnice

Set sample rate (0xF3) - nastavení "vzorkovací frekvence" myši. Toto nastavení znamená, jak nejčastěji může myš ve stream módu odesílat aktuální hodnoty. Na příkaz 0xF3 by měla myš odpovědět 0xFA, následně master odešle byte s novou vzorkovací frekvencí a myš opět potvrdí příjem 0xFA nebo v případě nepodporované hodnoty 0xFC (error). Podporované vzorkovací frekvence jsou 10, 20, 40, 60, 80, 100 a 200 vzorků/s.
Set resolution (0xE8) - nastavit rozlišení myšítka. Myš odpoví 0xFA, následně master odešle novou hodnotu a myš odpoví 0xFA/0xFC. Hodnoty v tabulce mají význam spíše pro optické myši - klasické kuličkové sice zapnou nějaký násobitel detekovaných pulzů z optozávor, ale uvedeným rozlišením výsledek rozhodně neodpovídá. Přinejmenším se každá myš chová jinak.

hodnota význam
0x00 1/mm
0x01 2/mm
0x02 4/mm
0x03 8/mm

Set scaling 1:1 (0xE6) - nastavit měřítko 1:1. Odpověď 0xFA. Toto nastavení znamená, že myš odesílá skutečně načítaný počet dílků, o který se od posledního čtení pohnula.
Set scaling 2:1 (0xE7) - nastavit měřítko 2:1. Odpověď 0xFA. Toto nastavení upravuje odesílané hodnoty dx, dy podle charakteristiky v tabulce. Toto nastavení má patrně vliv pouze ve stream módu.

vstup výstup
0 0
1 1
2 1
3 3
4 6
5 9
N N*2

Set stream mode (0xEA) - nastaví stream mód. Odpověď 0xFA. Stream mód je defaultní mód myšítka po resetu a znamená, že myš odešle patřičný packet obsahující informace o pohybu, čudlech apod. vždy, když dojde k nějaké změně stavu - pohyb myši, stisk/uvolnění čudlu, ... Packety však nejsou odesílány okamžitě, ale s nastavenou vzorkovací frekvencí. Formáty různých packetů budou popsány později.
Stream report disable (0xF5) - blokování stream módu. Odpověď 0xFA. Tento příkaz zakáže automatické odesílání odesílání změn ve stream módu (v podstatě ho vypne). Hodí se ho použít před jakýmkoliv dalším příkazem, aby nemohl být rušen automaticky odesílnými packety.
Stream report enable (0xF4) - odblokuje stream mód. Odpověď 0xFA. Tento příkaz opět povolí stream mód. Po resetu je stream mód blokován, takže je třeba tento příkaz použít.
Set remote mode (0xF0) - nastavit "vzdálený mód". Odpověď 0xFA. Přepne myš do tzv. vzdáleného módu. Narozdíl od stream módu myš nevrací packet vždy, když detekuje změnu, ale JEN po vyžádání příkazem "Read data".
Read data (0xEB) - vrátit packet ve vzdáleném módu. Odpověď 0xFA a patřičný packet - bude popsán později.

Komunikační protokol - rozšíření standardní myši
   Jak už jsem naznačil po resetu se všechny myši musí tvářit jako standardní 2/3-tlačítkové s ID 0x00. Známé rozšíření o "kolečko" (tzv. "M$ Intellimouse protocol") lze aktivovat pomocí speciální sekvence příkazů - po resetu myši zapíšeme postupně vzorkovací frekvence 200, 100 a 80. Pakliže myš podporuje toto rozšíření, tak při následném čtení ID vrátí hodnotu 0x03 a také změní formát packetů, takže už není zpětně kompatibilní! Pokud toto rozšíření není podporováno, došlo pouze k několika změnám vzorkovací frekvence a ID je stále 0x00.
   Další známé rozšíření je "kolečko" + 2 tlačítka (tzv. "Explorer mouse"). To lze aktivovat opět zápisem sekvence příkazů - tentokrát vzorkovací frekvence 200, 200 a 80. Pokud je mód podporován, změní se ID na 0x04.
   Další rozšíření nebudu rozebírat, protože jich je ještě hodně. Informace k nim naleznete v některých zdrojích.

Komunikační protokol - packety

   Zde popíši formát packetů, kterými myš vrací informace o změně polohy, stisku tlačítek, atd. V následující tabulce je uveden význam bitů 3-bytového packetu, který myš vrací ve standardním módu (ID 0x00).

- bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
byte 0 y_overflow x_overflow dy.8 dx.8 1 btn_middle btn_right btn_left
byte 1 dx.0 - dx.7
byte 2 dy.0 - dy.7

   První byte obsahuje především bitové příznaky jednotlivých tlačítek btn_left, btn_right a btn_middle (high pro stisknuté). Znaménková proměnná dx určuje relativní změnu polohy myši v ose x od posledního úspěšného přenosu packetu. Proměnná je tvořena devíti bity, takže je rozdělená - nižších 8 bitů je ve druhém bytu a znaménkový bit je v prvním bytu (dx.8). Hodnota dx se tedy může pohybovat v rozsahu -256 až +255. Obdobným způsobem je dělená i proměnná dy pro určení pohybu v ose y. Bity x_overflow a y_overflow jsou nastaveny pokud dojde k přetečení dx/dy.
   M$ Intellimouse (ID 0x03) používá 4-bytové packety dle následující tabulky:

- bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
byte 0 y_overflow x_overflow dy.8 dx.8 1 btn_middle btn_right btn_left
byte 1 dx.0 - dx.7
byte 2 dy.0 - dy.7
byte 3 dz.3 dz.3 dz.3 dz.3 dz.0 - dz.3

   Jak je vidět, první 3 byty se nijak nezměnily. Jedinou změnou oproti standardní myši je rozšíření o 4.byte, který obsahuje 4-bitovou znaménkovou proměnnou dz. Rozsah hodnot tedy může být -8 až +7 pulzů. Horní 4 bity by měly obsahovat kopii bitu dz.3, ale raději bych na to nespoléhal.
   Explorer mouse protokol (kolečko + 2 tlačítka, ID 0x04) je velmi podobný předchozímu, pouze poslední byte obsahuje navíc 2 příznakové bity pro rozšiřující tlačítka.

- bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
byte 0 y_overflow x_overflow dy.8 dx.8 1 btn_middle btn_right btn_left
byte 1 dx.0 - dx.7
byte 2 dy.0 - dy.7
byte 3 0 0 btn_5 btn_4 dz.0 - dz.3

Připojení k AVR - remote mód

   K testování komunikace s myší jsem použil opět veterána ATmega32 na 16MHz. Myš je připojena přímo k pinům AVRka, externě jsou zapojeny jen zvedací odpory. Otevřené kolektory jsou vytvořeny softwarově pomocí ddrb.x bitů - ddrb.x=1 pro low úroveň a ddrb.x=0 pro high úroveň. Port.x bity jsou trvale 0.

   Firmware po připojení napájení vyšle reset příkaz, následně načte ID a detekuje připojené zařízení. Pokud je nalezena myš, pokusí se zinicializovat M$ Intellimouse protokol, nastaví rozlišení 8kroků/mm a nastaví myš do remote módu. Následně v nekonečné smyčce vysílá příkaz "Read data" a zpracovává přijaté hodnoty - sčítá dx, dy a dz hodnoty. Všechny operace jsou ošetřeny timeoutem, takže lze myš připojovat/odpojovat i za chodu.
   Původně jsem chtěl připojit LCD a zobrazovat absolutní pozici a stav tlačítek, ale nakonec jsem se rozhodl pro propojení s PC přes COM port. Komunikace je nastavena na 115200bd bez parity. AVR po přijetí příkazu 's' vrátí jeden z následujících znaků:

Znak Význam
n žádné zařízení není přípojeno
d připojeno neznámé zařízení
k připojena klávesnice
m připojena standardní myš
i připojena M$ Intellimouse
a bude následovat níže popsaný packet

   Vrátí-li AVRko znak 'a', bude bezprostředně následovat dalších 8B dat. První vrácený byte bude 'm'/'i' podle typu připojené myši (stejně jako v předchozí tabulce). Následují 16bit znaménkové proměnné dx, dy a dz (low byte první). Poslední vrácený byte je kopií 1.bytu packetu, který vrací myš (předevsím stavy tlačítek). Po vrácení těchto 8 bytů jsou proměnné dx, dy a dz vynulovány.
Zdroje a bin.


   Tento jednoduchý prográmek posílá přes api funkce widlím zprávy, které emulují práci myši. Měly by fungovat 3 základní tlačítka a kolečko. V žádném případě však NELZE použít emulovanou myš k ovládání samotného prográmku, protože dochází ke ztrátám mouse_up události a z toho jsou widle trochu mimo. Prográmek doporučuji používat velmi opatrně - v případě nějaké poruchy ve firmwaru AVRka nebo při chybách přenosu (špatný krystal) by mohlo dojít k nepředvídatelnému chování kurzoru myši (náhodné klikání apod.). Sice se mi to nikdy nestalo (a to jsem s tím ovládal PC celý den), ale jistota je jistota :-). Hlavně je třeba nastavit správný COM port a přenosovou rychlost (115200bd) v souboru "config.ini". V případě použití USB-COM převodníku s FT232 je ještě třeba v ovladačích nastavit latency na 1-2ms (co nejméně).

Zdroje

   Zde je několik webů, kde jsem hledal informace:

[1] - http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
[2] - http://www.computer-engineering.org/ps2mouse/
[3] - http://www.computer-engineering.org/ps2protocol/
[4] - http://www.networktechinc.com/ps2-prots.html

Poslední aktualizace: 8.9.2007