České vysoké učení technické v Praze Fakulta elektrotechnická Katedra počítačové grafiky a interakce
Diplomová práce
Čtečka pomocí webové kamery Bc. Petr Strnad
Vedoucí práce: Prof. Ing. Pavel Zahradník, CSc.
Studijní program: Otevřená informatika Obor: Softwarové inženýrství květen 2014
ii
iii
iv
Poděkování Děkuji vedoucímu práce prof. Ing. Pavlu Zahradníkovi, CSc. za konzultace a cenné rady při vývoji.
v
vi
Prohlášení Prohlašuji, že jsem předloženou práci vypracoval samostatně a že jsem uvedl veškeré použité informační zdroje v souladu s Metodickým pokynem o dodržování etických principů při přípravě vysokoškolských závěrečných prací. V Praze dne 12.5.2014
vii
viii
Abstract The work deals with enabling the XMOS XK-1A microcontroller to be able to connect to a web camera through USB, in order to download a still picture from the camera and process the image data to recognize numbers in the picture.
Abstrakt Práce se zabývá zprovozněním komunikace XMOS XK-1A mikrokontroléru s webovou kamerou prostřednictvím USB, za účelem stažení obrázku z kamery a zpracováním obrazových dat pro rozpoznání číslic v obrázku.
ix
x
Obsah Kapitola 1 Úvod..........................................................................................................................1 1.1Popis problému, specifikace cíle.......................................................................................1 Kapitola 2 Analýza a návrh řešení..............................................................................................3 2.1XK-1A mikrokontrolér......................................................................................................3 2.1.1Hardware...................................................................................................................4 2.1.2Porty...........................................................................................................................5 2.1.3Vlákna a komunikace mezi nimi...............................................................................6 2.1.4Frekvence...................................................................................................................6 2.2xTIMEcomposer................................................................................................................8 2.3xSCOPE.............................................................................................................................8 2.4Jazyk XC...........................................................................................................................9 2.5USB konektor..................................................................................................................10 2.6USB host stack................................................................................................................12 2.6.1Idle stav....................................................................................................................13 2.6.2Reset zařízení...........................................................................................................13 2.6.3Kódování informace při přenosu.............................................................................13 2.6.4CRC.........................................................................................................................14 2.6.5Endpoint...................................................................................................................14 2.6.6Druhy paketů...........................................................................................................15 2.6.6.1Token paket......................................................................................................15 2.6.6.2Data paket........................................................................................................16 2.6.6.3Handshake paket..............................................................................................16 2.6.7Transakce.................................................................................................................17 2.6.7.1OUT transakce.................................................................................................17 2.6.7.2IN transakce.....................................................................................................17 2.6.7.3SETUP transakce.............................................................................................17 2.6.8Typy přenosů...........................................................................................................21 2.6.8.1Řídící (control) přenosy...................................................................................21 2.6.8.2Interrupt přenosy..............................................................................................21 2.6.8.3Izochronní přenosy...........................................................................................21 2.6.8.4Hromadné (bulk) přenosy................................................................................22 2.6.9Enumerace...............................................................................................................22 2.7Možné problémy..............................................................................................................22 Kapitola 3 Popis řešení.............................................................................................................23 3.1Hardware.........................................................................................................................23 3.2Konfigurace.....................................................................................................................26 3.3Implementace..................................................................................................................27 3.3.1Zpracování dat během jejich přijímání – neúspěšné................................................27 3.3.2Zpracování dat před odesláním a po přijetí.............................................................28 3.3.3Popis zdrojového kódu............................................................................................28 3.3.3.1USB/xc/IO/USBIn...........................................................................................28 3.3.3.2USB/xc/IO/USBOut.........................................................................................29 3.3.3.3USB/cpp/DataCont..........................................................................................29 3.3.3.4USB/cpp/CRC..................................................................................................30 3.3.3.5USB/cpp/NRZI................................................................................................30 3.3.3.6USB/cpp/Packet...............................................................................................30 3.3.3.7USB/cpp/Controller.........................................................................................32 3.3.3.8Reader..............................................................................................................32 xi
3.3.3.9Simulator..........................................................................................................32 3.3.3.10Tests...............................................................................................................33 Kapitola 4 Výsledky testování..................................................................................................35 4.1Detekce připojení zařízení...............................................................................................35 4.2Potvrzení přijetí paketů s GetDescriptor požadavkem....................................................36 4.3Přijetí Data paketu s deskriptorem..................................................................................36 Kapitola 5 Závěr........................................................................................................................39 Literatura...................................................................................................................................41
xii
Seznam ilustrací Obr. 2.1: XK-1A mikrokontrolér. Zdroj: [1]...............................................................................3 Obr. 2.2: XK-1A s připojeným XTAG2 Debug adaptérem. Zdroj: [9].......................................4 Obr. 2.3: Schéma XK-1A mikrokontroléru. Zdroj: [2]...............................................................5 Obr. 2.4: Klesající výkon jednotlivých vláken s rostoucím počtem vláken. Zdroj: [7]..............7 Obr. 2.5: Ukázka reprezentace hodnot proměnných v xSCOPE. Zdroj: [15].............................8 Obr. 2.6: XK-1A Rozšiřovací oblasti. Zdroj: [2]......................................................................10 Obr. 2.7: Přidělení pinů rozšiřovacích oblastí k portům. Zdroj: [2]..........................................11 Obr. 2.8: Schéma zapojení konektoru pro USB host. Zdroj: [3]...............................................11 Obr. 2.9: Non-return-to-zero-inverted kódování informace. Zdroj: [5]....................................13 Obr. 3.1: Vyrobený USB konektor............................................................................................23 Obr. 3.2: Detail vyrobeného USB konektoru............................................................................24 Obr. 3.3: XK-1A s připojeným USB konektorem.....................................................................24 Obr. 3.4: Zvolené piny na rozšiřovací oblasti. Zdroj: [2].........................................................25 Obr. 3.5: Správné nasunutí svorkovnice konektoru. Zdroj: [2]................................................25 Obr. 3.6: Konfigurace frekvence referenčních hodin................................................................26 Obr. 3.7: Debug konfigurace s aktivním xSCOPE....................................................................26 Obr. 3.8: Zpoždění zápisu kvůli pomalému zpracování dat......................................................28 Obr. 3.9: UML diagram tříd paketů...........................................................................................31 Obr. 3.10: Nastavení propojení portů v simulátoru...................................................................33 Obr. 4.1: Úspěšná detekce připojeného zařízení.......................................................................35 Obr. 4.2: Obdržený ACK paket na Setup fázi GetDescriptor řídícího přenosu........................36 Obr. 4.3: Obdržený NAK paket na datovou část GetDescriptor řídícího přenosu....................37
Seznam tabulek Tabulka 2.1: Stavy datových vodičů. Zdroj: [4].......................................................................12 Tabulka 2.2: Formát Token paketu. Zdroj: [8]..........................................................................15 Tabulka 2.3: Poddruhy Token paketu. Zdroj: [8]......................................................................15 Tabulka 2.4: Formát Data paketu. Zdroj: [8]............................................................................16 Tabulka 2.5: Poddruhy Handshake paketu. Zdroj: [8]..............................................................16 Tabulka 2.6: Formát Setup datového paketu. Zdroj: [11].........................................................18 Tabulka 2.7: Seznam standardních požadavků na zařízení. Zdroj: [11]...................................19 Tabulka 2.8: Seznam standardních požadavků na interface. Zdroj: [11]..................................20 Tabulka 2.9: Seznam standardních požadavků na endpoint. Zdroj: [11]..................................20
xiii
xiv
Kapitola 1
Úvod
Existuje hned několik open-source projektů, které se zaměřují na zpracovávání obrazových dat a rozpoznávání informací v nich obsažených, ať již jde o rozpoznávání obličejů a obličejových výrazů, nebo jen prosté přečtení číslic. Tyto projekty se ovšem zaměřují převážně na platformy s operačním systémem, a tedy očekávají, že jim operační systém zprostředkuje přístup ke zdroji obrazových dat, například k připojené webové kameře. Nutnost použití platformy s operačním systémem však může značně omezovat využití, a často může být žádoucí, aby tato funkcionalita byla implementována na embeddovaných systémech či samostatných mikrokontrolérech.
1.1 Popis problému, specifikace cíle Původním celkovým cílem práce byl návrh a implementace čtečky pro vývojovou desku XK-1A od společnosti XMOS s mikroprocesorem XS1-L1. Čtečka si tedy měla být schopna přečíst fotografii z připojené webové kamery, a následně v získané fotografii rozpoznat číslice z vyfotografovaných displejů měřících přístrojů. Během rešerše však vyšlo najevo, že samotné zprovoznění USB funkcionality na zařízení XK-1A bude daleko složitější, než se zprvu zdálo. Nejenže žádný z existujících open-source projektů pro USB host stack není se zařízením přímo kompatibilní, ale navíc rozdíly v architektuře a fakt, že XMOS používá svou vlastní upravenou verzi jazyka C, znamenaly nutnost naprogramovat celý USB host stack od začátku. Po domluvě s vedoucím práce se tedy jako hlavní cíl této diplomové práce ustanovila implementace USB host stacku pro komunikaci zařízení XK-1A s webovou kamerou.
1
KAPITOLA 1 ÚVOD
2
Kapitola 2
Analýza a návrh řešení
2.1 XK-1A mikrokontrolér XK-1A (viz. Obr. 2.1) je cenově dostupný vícejádrový mikrokontrolér od společnosti XMOS, který umožňuje paralelní spuštění až osmi vláken [12] se stabilním a přesně předvídatelným výkonem každého jádra.
Obr. 2.1: XK-1A mikrokontrolér. Zdroj: [1].
3
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.1.1 Hardware Mikrokontrolér obsahuje: • jeden XS1-L1 32-bitový procesor s 64 kB RAM pamětí na čipu (viz Obr. 2.3, označen jako A), •
dva XSYS porty (jeden „samec“ a jedna „samice“) pro připojení XTAG2 Debug adaptéru (viz. Obr. 2.2) nebo dalšího XMOS mikrokontroléru (označeny B),
•
čtyři LED diody (označeny C),
•
dvě tlačítka (označeny D),
•
dvě rozšiřující vstupně-výstupní oblasti (označeny E),
•
128 kB SPI FLASH paměti (označena F),
•
20 MHz oscilátor (označen G),
•
konektor pro 5V napájecí adaptér (označen H).
Mikrokontrolér může být napájen buď externím 5V adaptérem, nebo prostřednictvím XTAG2 Debug adaptéru připojeného k počítači pomocí USB. [2]
Obr. 2.2: XK-1A s připojeným XTAG2 Debug adaptérem. Zdroj: [9]
4
C
C
E
G
A
F
B
B
D
H
E
Obr. 2.3: Schéma XK-1A mikrokontroléru. Zdroj: [2].
2.1.2 Porty Jednotlivé piny rozšiřovacích oblastí jsou mapovány na tzv. porty. Porty mohou mít velikost 1, 4 nebo 8 bitů, a zastřešují odpovídající počet pinů, díky čemuž je možné na rozšiřovací oblasti připojit jak sériové, tak paralelní rozhraní. Jeden pin může spadat pod více portů, ovšem v danou chvíli jej může využívat vždy pouze jeden port. Existuje několik způsobů přístupu k portům, kdy každý z nich má své výhody a nevýhody: •
Synchronní čtení a zápis: jako jediné je obousměrné a umožňuje tedy použít jeden port jak ke vstupu, tak k výstupu. Používá výchozí hodinový 100MHz signál. Vždy je přečteno pouze tolik bitů, jaká je velikost portu.
•
Synchronní čtení nebo zápis o specifické frekvenci: port je možné nakonfigurovat, aby používal hodinový signál s konkrétní frekvencí získanou vydělením výchozího hodinového signálu mocninou čísla dvě. Možné frekvence tedy jsou 50MHz, 25MHz, atd. Konfigurací portu se ztrácí možnost používat jej obousměrně. Vždy je přečteno pouze tolik bitů, jaká je velikost portu.
•
Bufferované čtení nebo zápis o specifické frekvenci: místo čtení pouze aktuálního stavu pinů portu je možné port nakonfigurovat, aby si hodnoty pinů při hodinovém signálu ukládal do bufferu o specifické velikosti. Takto je možné například jednobitový port bufferovat do bufferu o velikosti až 32 bitů. Díky tomu může program přečíst 32 hodnot jedinou instrukcí, místo aby byla 32krát přečtena jedna hodnota za druhou. Tím se značně sníží prodleva, způsobená přístupem k portům. Obdobně je možné do bufferu uložit 32 bitů naráz a mikrokontrolér se postará o jejich postupné odeslání.
[13] 5
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.1.3 Vlákna a komunikace mezi nimi Mikrokontrolér je velmi striktní v oddělování přístupu jednotlivých vláken ke zdrojům. Pokud nějaké vlákno přistoupilo k určité alokované části paměti, žádné jiné vlákno k ní nemá přístup, dokud není dealokována, a to ani v případě, že první vlákno s danou částí paměti v danou chvíli nepracuje. Stejná situace nastává při přístupu vlákna k vstupním / výstupním portům, LED diodám apod. Jediný způsob, jak si vlákna mohou předávat data či řídící signály, je prostřednictvím kanálů. Kanály zajišťují synchronní komunikaci mezi dvěma konkrétními vlákny a musejí být explicitně vytvořeny. Speciálním druhem kanálů jsou tzv. proudové (streaming) kanály. Proudové kanály mají vlastní buffer a komunikace po nich tedy probíhá asynchronně, navíc jsou data přenášena extrémně rychle, neboť proudové kanály mají rezervovánu kapacitu přímo v přepínači vláken. Odeslání dat přes proudový kanál se provede během jediné instrukce procesoru a data jsou odeslána okamžitě, za předpokladu, že není buffer kanálu plný. Pokud je buffer plný, musí odesílající vlákno vyčkat, dokud přijímací vlákno nezpracuje část dat z bufferu a uvolní tak místo. Kvůli nutnosti rezervování kapacity v přepínači je však počet použitých proudových kanálů omezen, a je tedy vhodné je používat pouze v případech, kdy je rychlost předání dat opravdu důležitá.[7]
2.1.4 Frekvence Procesor samotný pracuje v základu na 400MHz frekvenci, nicméně jednotlivá vlákna mohou pracovat maximálně na 100MHz frekvenci. Maximální efektivnosti je tedy dosaženo, pokud jsou paralelně spuštěna čtyři vlákna. Při spuštění více než čtyř vláken začne rychlost jednotlivých vláken klesat, kdy každé vlákno pracuje na frekvenci (400 / počet vláken) MHz (viz. Obr. 2.4). V praxi však mají pracující vlákna k dispozici většinou vyšší výkon, neboť je velká pravděpodobnost, že některá vlákna čekají na IO operace apod. Dále mikrokontrolér generuje pro vstupně-výstupní porty výchozí hodinový signál o frekvenci 100MHz, který může být dále dělen na nižší frekvence. USB však pracuje na frekvenci 12MHz a nejbližší frekvence, které lze dosáhnout dělením 100MHz signálu, je 12.5MHz. Jelikož by při delších přenosech mohlo docházet k desynchronizaci hodin mezi odesílatelem a příjemcem, je potřeba získat zdroj 12MHz hodinového signálu. XK-1A sice umožňuje využít externí zdroj hodinového signálu, nicméně také umožňuje detailnější konfiguraci frekvence jak procesoru (maximálně však 500MHz), tak frekvence výchozího hodinového signálu. Jako zdroj je použit 20MHz oscilátor na mikrokontroléru (viz. Obr. 2.3), jehož frekvence se dělí a násobí konfigurovatelnými konstantami.[14]
6
Garantovaný počet MIPS za sekundu pro každé vlákno
100 90 80 70 60 50 40 30 20 10 0 1
2
3
4
5
6
7
8
Počet aktivních vláken
Obr. 2.4: Klesající výkon jednotlivých vláken s rostoucím počtem vláken. Zdroj: [7].
7
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.2 xTIMEcomposer xTIMEcomposer je vývojové prostředí pro XMOS mikrokontroléry, které je postaveno na Eclipse IDE. Mezi nejpodstatnější funkcionalitu, kterou zahrnuje, patří: •
Kompilátor s konfiguracemi pro jednotlivé XMOS mikrokontroléry. Zkompilovaný kód je možné okamžitě nahrát do zařízení prostřednictvím XTAG2 Debug adaptéru.
•
Simulátor pro testování programů v kontrolovaném prostředí.
•
Debuger, umožňující program debugovat jak v simulátoru, tak přímo v mikrokontroléru.
•
Timing analyzer pro výpočet časové náročnosti nezávislých bloků kódu.
•
xSCOPE systém pro sledování hodnot konkrétních proměnných za běhu programu bez jeho zastavení nebo zpomalení.
[16]
2.3 xSCOPE xSCOPE je systém umožňující neinvazivní monitorování stavu aplikace. Po zaregistrování konkrétních proměnných jsou jejich hodnoty za běhu programu odesílány do XTAG2 Debug adaptéru, kde jsou bufferovány, aby bylo zajištěno minimální zpomalení programu. Díky tomu je možné monitorovat proměnné i u programů, které komunikují s externími zařízeními a vyžadují tak práci v reálném čase. Stejným způsobem je možné monitorovat hodnoty na pinech rozšiřovacích oblastí. Umožňuje jak zobrazování dat v reálném čase, tak „offline“ sběr dat a jejich ukládání do souboru pro pozdější prohlédnutí. [15]
Obr. 2.5: Ukázka reprezentace hodnot proměnných v xSCOPE. Zdroj: [15].
8
2.4 Jazyk XC XMOS používá svou vlastní upravenou verzi jazyka C nazvanou XC, která přináší rozšíření pro práci s hardwarem a vlákny: •
Proměnné typu port a jejich vstupní :> a výstupní <: operátory. Prvním operátorem je vždy port, druhým proměnná.
•
Proměnné typu clock, jejichž konfigurací a přiřazením k portu je možné upřesnit frekvenci hodinového signálu pro operace čtení a zápisu portu.
•
Proměnné typu chanend, reprezentující kanál pro komunikaci s jiným vláknem. Vstupní a výstupní operátory jsou totožné jako v případě portů.
•
Proměnné typu timer, které jsou interně inkrementovány mikrokontrolérem v 10 nanosekundových intervalech a umožňují tak získání relativního času prostřednictvím :> operátoru, který uloží aktuální hodnotu timeru do proměnné. Také umožňují uspat vlákno po určitou dobu: timer tmr; unsigned int waitUntil; tmr :> waitUntil; waitUntil += 100; tmr when timerafter(waitUntil) :> (void);
•
Spuštění více vláken. V takovém případě nesmí main() obsahovat žádné instrukce kromě deklarace kanálů a par {} instrukci obsahující seznam funkcí, kdy se každá funkce spustí v samostatném vlákně.
Zároveň však jazyk XC vynucuje jistá nepříjemná omezení: •
Neumožňuje dynamickou alokaci paměti, všechna pole hodnot tedy musí být vytvořena s konstantní velikostí.
•
Ruší ukazatele. Pokud je potřeba funkci předat jako parametr pole, musí být předáno jako reference s pevně definovanou délkou. Např.: void foo(int array[n], int n) { .. }
Naštěstí XMOS umožňuje mít v projektu jak XC, tak klasické C a dokonce C++ soubory a volat jejich kód. K tomu je zapotřebí mít v XC souboru deklarovánu funkci jako extern a v hlavičkovém C/C++ souboru deklarovánu odpovídající funkci opět jako extern (v případě C++ extern „C“). Jako odpovídající funkce je považována funkce se stejným názvem a parametry s vyjímkou parametrů typu port, chanend a timer, která jsou v C/C++ souboru nahrazena typem unsigned int, a referencí na pole, která jsou nahrazena pointery.
9
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.5 USB konektor Jelikož XK-1A mikrokontrolér nemá žádný USB konektor (viz. Obr. 2.1), je nutné jej pro zařízení nejprve vyrobit. K dispozici je sice XTAG2 Debug adaptér, který je určen pro připojení mikrokontroléru k počítači a který USB konektor obsahuje (viz. Obr. 2.2), nicméně ten je potřebný pro přenos již zpracovaných dat z mikrokontroléru do počítače. Mikrokontrolér naštěstí obsahuje dvě šestnáctipinové rozšiřovací oblasti, které jsou určeny právě pro připojení rozšiřujících vstupních či výstupních zařízení (viz. Obr. 2.6). USB standard vyžaduje, aby pro napájení zařízení bylo na prvním pinu konektoru 5V napětí, na čtvrtém pinu pak uzemnění (viz. Obr. 2.8). Z nákresu a popisu rozšiřovacích oblastí mikrokontroléru (viz. Obr. 2.6) je patrné, že jak 5V napětí, tak uzemnění, jsou k dispozici na dvou krajních pinech každé rozšiřovací oblasti. Dále konektor musí mít na každém datovém pinu (D+ a D-) 27 ohmový rezistor a zároveň být přes 15 kilo ohmový rezistor připojit k uzemnění. Zobrazené kondenzátory na datových pinech slouží převážně jako filtr signálu a není nutné je v konektoru mít. Navíc je ještě nutné mít každý datový pin konektoru připojen nikoliv na jeden, nýbrž na dva piny v rozšiřovací oblasti. Mikrokontrolér totiž umožňuje piny bufferovat pouze jednosměrně, tedy buď jako vstupní, nebo výstupní, avšak USB používá oba piny obousměrně. Jsou tedy zapotřebí čtyři jednopinové porty z jediné rozšiřovací oblasti. Podle rozdělení pinů na Obr. 2.7 jsou použitelné pouze piny XD12, XD13, XD22, XD23, nebo XD0, XD1, XD10, XD11. Napojením každého pinu konektoru na dva piny na mikrokontroléru je tedy umožněno rychlejší čtení a posílání dat pomocí bufferování, díky kterému se sníží zpoždění spojené se čtením a zápisem hodnot.
GND XD11
XD12
XD13
5V
XD14
XD15
XD10
XD16
XD17
XD9
XD8
3V3
XD7
XD6
XD18
XD19
GND
3V3
XD20
XD21
XD5
XD4
XD22
XD23
XD3
XD2
5V
XD1
XD0
Obr. 2.6: XK-1A Rozšiřovací oblasti. Zdroj: [2].
10
GND
GND
Pin
Port 1b
XD0
P1A0
XD1
P1B0
4b
Processor 8b
XD2
P4A0 P8A0
XD3
P4A1 P8A1
XD4
P4B0 P8A2
XD5
P4B1 P8A3
XD6
P4B2 P8A4
XD7
P4B3 P8A5
XD8
P4A2 P8A6
XD9
GPIO_A
P4A3 P8A7
XD10
P1C0
XD11
P1D0
XD12
P1E0
XD13
P1F0
XD14
P4C0 P8B0
XD15
P4C1 P8B1
XD16
P4D0 P8B2
XD17
P4D1 P8B3
XD18
P4D2 P8B4
XD19
P4D3 P8B5
XD20
P4C2 P8B6
XD21
GPIO_B
P4C3 P8B7
XD22
P1G0
XD23
P1H0
Obr. 2.7: Přidělení pinů rozšiřovacích oblastí k portům. Zdroj: [2].
Obr. 2.8: Schéma zapojení konektoru pro USB host. Zdroj: [3].
11
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.6 USB host stack Aby si mikrokontrolér mohl stáhnout obrázek z připojené webové kamery, je kromě hardwarového konektoru ještě nutné implementovat USB host stack. USB komunikace vždy funguje jako master-slave, zde označováno jako host-device. Existuje již několik projektů, které implementují USB host stack pro mikrokontroléry, jako například LUFA [6]. Bohužel však všechny tyto projekty stack implementují pro zařízení od jiných výrobců, navíc pro modely s USB konektorem, které primárně fungují jako device. Samotná obsluha hardwaru, od časování, přerušení až po vstupně-výstupní operace je tedy naprosto nepoužitelná pro mikrokontrolér XK-1A a musí být naprogramována celá od začátku. K tomu je tedy nutné hlubší studium USB standardu pro komunikaci. Při připojení zařízení (device, v tomto případě webová kamera) si hostitel přečte aktuální hodnoty na D+ a D- datových vodičích a z výsledku je schopen rozpoznat, na jaké rychlosti zařízení pracuje. Pokud je D+ nastaveno na 1 a D- na 0, pak zařízení pracuje na fullspeed rychlosti (12Mbit/s). Pokud je naopak D+ nastaveno na 0 a D- na 1, zařízení podporuje pouze lowspeed rychlost (1.5Mbit/s). Z toho může hostitel odvodit tzv. bittime, který říká, jak dlouho trvá přenesení jednoho bitu. Pro fullspeed rychlost bittime odpovídá 83.33 nanosekundám, pro lowspeed je to pak 666.66 nanosekund. Při samotné komunikaci se rozpoznávají čtyři základní stavy na datových vodičích: Stav
Lowspeed reprezentace Fullspeed reprezentace D+
D-
D+
D-
J
0
1
1
0
K
1
0
0
1
SE0
0
0
0
0
SE1
1
1
1
1
Tabulka 2.1: Stavy datových vodičů. Zdroj: [4]. Jak je patrné, stavy J a K při lowspeed rychlosti jsou přesně opačné než při fullspeed rychlosti. Stav SE1 by neměl nikdy nastat a je považován za chybu při přenosu. SE0 je používán jako určitý druh řídícího signálu a označuje například konec paketu, případně se používá jako signál pro reset zařízení. Pro potřeby této práce stačí počítat pouze s fullspeed rychlostí, neboť webové kamery vždy pracují ve fullspeed rychlosti (v lowspeed rychlosti pracují např. USB klávesnice) [10].
12
2.6.1 Idle stav Mezi jednotlivými pakety jsou datové vodiče v takzvaném idle stavu, který odpovídá základnímu J stavu a liší se tedy při fullspeed a lowspeed rychlostech. Tímto stavem se signalizuje, že je zařízení stále připojeno a připraveno. Zároveň jsou v tomto stavu vodiče po připojení zařízení k hostiteli, neboť na straně zařízení je přímo v konektoru jeden z datových vodičů přes odpor připojen k 5V. Tím se zajistí, že mimo komunikaci je udržován idle stav, ale zároveň velikost odporu stále umožňuje stáhnout hodnotu datového vodiče na nulu. [4]
2.6.2 Reset zařízení Aby hostitel mohl začít komunikovat se zařízením, potřebuje jej nejprve zresetovat do výchozího, nenakonfigurovaného stavu. Toho dosáhne posláním reset signálu – oba datové vodiče nastaví na nulu (SE0 stav) a tento stav podrží po dobu 10 až 20 milisekund. Následně pak vrátí oba vodiče zpět do idle stavu (J) a může začít s konfigurací zařízení.[4]
2.6.3 Kódování informace při přenosu USB standard používá non-return-to-zero-inverted space kódování informace (viz. Obr. 2.9). Změna stavu datových vodičů (ze stavu J na K či naopak) tedy znamená nulu, nezměněný stav pak znamená jedničku.
Obr. 2.9: Non-return-to-zero-inverted kódování informace. Zdroj: [5].
Díky tomu signál ve většině případů obsahuje dostatek přechodů k tomu, aby si příjemce signálu mohl s každým přechodem znovu sesynchronizovat vnitřní hodiny pro časování čtení hodnot z datových vodičů. Aby se předešlo i případům, kdy přenášená informace obsahuje příliš mnoho za sebou jdoucích jedniček, které by znamenaly neměnnost signálu, provádí se ještě tzv. bit stuffing. To znamená, že se po každých šesti po sobě jdoucích jedničkách do informace přidá nula, která zajistí změnu stavu. Příjemce si tedy opět může sesynchronizovat časování, avšak tuto nulu nepřidá do dekódované informace. [5]
13
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ Při samotném přenosu se informace rozděluje do paketů o určité maximální délce. Každý paket začíná 8bitovým synchronizačním signálem, který je tvořen třemi KJ stavy následovanými dvěma K stavy (tedy KJKJKJKK). Příjemce může tyto tři KJ stavy využít pro nastavení a synchronizaci vnitřních hodin a následující dva K stavy pak označují samotný začátek přenášeného paketu. Bity jsou zároveň přenášeny „lowest significant bit first“, tedy číslo 5 (00000101b) by bylo přeneseno jako 10100000. Dokončení přenosu poté odesílatel signalizuje tzv. EOP (End of Packet) signálem, kdy po dobu dvou bittimů drží datové vodiče ve stavu SE0 a následně po jeden bittime ve stavu J. Stav SE0 není nikdy používán pro přenos informace a nezaměnitelně tedy označuje konec přenosu. Vysílání J stavu se pak postará o nastavení idle stavu, který je následně udržován odporem připojeným na 5V na straně připojeného zařízení.
2.6.4 CRC Většina paketů používá pro kontrolu správného přenesení svého obsahu Cyklickou redundantní kontrolu, tzv. CRC, konkrétně CRC o délce 5 a 16 bitů. XK-1A obsahuje funkce pro výpočet pouze CRC32, je tedy potřeba implementovat vlastní funkce pro výpočet kontrolních součtů.
2.6.5 Endpoint Endpointy jsou zdroje nebo cíle toku dat při komunikaci a jsou přítomny pouze na straně zařízení. Každý OUT (směr je brán z pohledu hosta, OUT tedy znamená od hosta k zařízení) endpoint má svůj vlastní buffer, do kterého USB device stack ukládá data přijatá od hosta. Tato data může následně obslužný software zařízení zpracovat. Pokud chce zařízení poslat data hostovi, nemůže začít rovnou vysílat. Místo toho data uloží do bufferu odpovídajícího IN endpointu. Zde data čekají, dokud si o ně host nezažádá, načež je USB device stack odešle. Obslužný software tedy nemusí zbytečně čekat, ale může zatím obsloužit jiné přijaté požadavky. [8]
14
2.6.6 Druhy paketů USB při komunikaci využívá čtyři základní druhy paketů: Token, Data, Handshake a Special (poslední není pro účely práce podstatný a týká se převážně USB 2.0 a highspeed rychlosti). Každý paket začíná osmibitovým PID číslem, které určuje, o jaký druh a případně poddruh paketu se jedná. PID číslo je rozděleno na čtyři a čtyři bity, kdy druhé čtyři bity jsou pouze negací prvních čtyř, aby bylo zajištěno, že se hodnota přenesla správně.
2.6.6.1 Token paket Token paket vždy začíná transakci přenosu dat a určuje, k jakému zařízení a kterému endpointu na zařízení se transakce vztahuje. Samotný paket má pevně danou délku 16 bitů, obsahuje adresu cílového zařízení, cílový endpoint, a jejich kontrolní CRC5 součet. PID ADDR ENDP CRC5 8 bitů 7 bitů
4 bity 5 bitů
Tabulka 2.2: Formát Token paketu. Zdroj: [8]. Podle PID se rozlišují tři základní poddruhy token paketu a navíc speciální SOF (Start of Frame) paket, který místo ADDR a ENDP hodnot obsahuje Frame Number (11 bitů). Komunikace se rozděluje do tzv. Framů, kdy jeden frame trvá jednu milisekundu. PID
Název
Použití
0001 OUT
Hostitel signalizuje, že bude odesílat data k zařízení.
1001 IN
Hostitel signalizuje, že zařízení může začít posílat data.
0101 SOF
Označuje počátek nového framu.
1101 SETUP
Hostitel signalizuje, že bude odesílat konfigurační informace k zařízení. Tabulka 2.3: Poddruhy Token paketu. Zdroj: [8]
15
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.6.6.2 Data paket Slouží pro přenost samotných dat. Datová část („payload“) může mít různou délku a je následována jejím kontrolním CRC16 součtem: PID
DATA
CRC16
8 bitů 0-1024 bajtů 16 bitů Tabulka 2.4: Formát Data paketu. Zdroj: [8]. U data paketů může PID nabývat pouze hodnot 0011 pro DATA0, nebo 1011 pro DATA1 (highspeed rychlost ještě definuje další dva, ovšem highspeed rychlost by XK-1A mikrokontrolér nestíhal zpracovávat). Důvodem pro použití dvou poddruhů je kontrola obdržení paketů – DATA0 a DATA1 se střídají, pokud tedy příjemce obdrží dvakrát za sebou paket se stejným PID, muselo dojít ke ztrátě jednoho paketu.
2.6.6.3 Handshake paket Používán pro signalizaci stavu, či jako odpověď při úspěšném či neúspěšném obdržení paketů v transakci. Samotný paket obsahuje pouze PID, který určuje aktuální stav: PID Název
Význam
0010 ACK
Příjemce signalizuje úspěšné obdržení paketu.
1010 NAK
Příjemce nemůže přijmout data, nebo odesílatel nemůže odeslat data.
1110 STALL Endpoint není k dispozici. Tabulka 2.5: Poddruhy Handshake paketu. Zdroj: [8]. NAK paket zpravidla znamená, že je zařízení zaneprázdněno a nemůže přijímat data (ještě nestihlo zpracovat předchozí požadavek a endpoint má plný buffer), nebo nemá připravena žádná data pro odeslání.
16
2.6.7 Transakce Transakce je sekvence tří (v určitých případech pouze dvou) paketů, která provádí jednoduchý, avšak bezpečný přenos dat [4].
2.6.7.1 OUT transakce Host odešle OUT Token paket (PID 0001), následovaný Data paketem. Pokud zařízení oba pakety úspěšně obdrželo (PID obou paketů odpovídá očekávaným hodnotám a jejich kontrolní CRC součty jsou v pořádku), odpoví Handshake paketem: •
ACK pokud byly pakety úspěšně uloženy do bufferu, odkud si je může obsluhující software přečíst, nebo
•
NAK pokud je buffer plný a pakety do něj nemohly být uloženy (např. proto, že obsluhující software ještě nestihl zpracovat předešlou transakci), nebo
•
STALL pokud došlo k chybě zařízení.
Pokud zařízení nepřijalo oba pakety úspěšně, pak celou transakci ignoruje, a žádný Handshake paket neodešle.
2.6.7.2 IN transakce Host odešle IN Token paket (PID 1001). Pokud zařízení paket úspěšně přijalo, odešle: •
Data paket pokud má data k odeslání, nebo
•
NAK Handshake paket pokud zařízení pracuje, ale nemá žádná data k odeslání, nebo
•
STALL Handshake paket pokud došlo k chybě.
Pokud zařízení odpovědělo Data paketem a host jej úspěšně přijal, pak host odpoví ACK Handshake paketem pro signalizaci úspěšného přijetí. V případě NAK a STALL odpovědí host ACK paket neodesílá.
2.6.7.3 SETUP transakce Host odešle SETUP Token paket (PID 1101), následovaný DATA0 Data paketem (nikdy ne DATA1), který obsahuje požadavek o délce 8 bytů (viz. Tabulka 2.6). Podle druhu příjemce se rozlišují standardní požadavky pro zařízení (viz. Tabulka 2.7), interface (viz. Tabulka 2.8) a endpoint (viz. Tabulka 2.9). Pokud zařízení oba pakety úspěšně přijalo, odpoví ACK Handshake paketem. Narozdíl od OUT transakce nesmí nastat NAK ani STALL odpověď. Zařízení musí být schopno na SETUP transakce reagovat i v případě chyby, tedy STALL situace nemůže nastat. Navíc ve chvíli, kdy zařízení přijme SETUP Token, musí okamžitě přestat zpracovávat a zahodit předchozí SETUP transakci, a nemůže tedy ani nastat situace s plným bufferem (NAK). 17
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
Offset 0
Název
Bytů
bmRequestType 1
Hodnota Bitmapa
Význam Bit 7: Směr toku dat 0 = Host k zařízení 1 = Zařízení k hostovi Bity 6-5: Typ 0 = Standardní 1 = Kategorie 2 = Výrobce 3 = Rezervováno Bity 4-0: Příjemce 0 = Zařízení 1 = Interface 2 = Endpoint 3 = Jiné 4-31 = Rezervováno
1
bRequest
1
Hodnota
Konkrétní požadavek
2
wValue
2
Hodnota
Podle požadavku
4
wIndex
2
Index nebo offset Podle požadavku
6
wLength
2
Počet
Počet bytů pro přenos v datové fázi.
Tabulka 2.6: Formát Setup datového paketu. Zdroj: [11].
18
bmRequestType
bRequest
wValue
wIndex wLength
Data
0
0
2
Stav zařízení
Feature selektor
0
0
-
00000000b SET_FEATURE (0x03)
Feature selektor
0
0
-
00000000b SET_ADDRESS (0x05)
Nová adresa zařízení
0
0
-
10000000b GET_STATUS (0x00) 00000000b
CLEAR_FEATURE (0x01)
10000000b
GET_DESCRIPTOR (0x06)
0 nebo Typ a index ID deskriptoru jazyka
Délka deskriptoru
Deskriptor
00000000b
SET_DESCRIPTOR (0x07)
0 nebo Typ a index ID deskriptoru jazyka
Délka deskriptoru
Deskriptor
10000000b
GET_CONFIGURATION (0x08)
0
0
1
Data konfigurace
00000000b
SET_CONFIGURATION (0x09)
Index 0 konfigurace
0
-
Tabulka 2.7: Seznam standardních požadavků na zařízení. Zdroj: [11].
19
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
bmRequestType
bRequest
wValue
wIndex
10000001b
GET_STATUS (0x00)
0
Interface 2
Stav interface
00000001b
CLEAR_FEATURE (0x01)
Feature selektor
Interface 0
-
00000001b
SET_FEATURE (0x03)
Feature selektor
Interface 0
-
10000001b
GET_INTERFACE (0x0A)
0
Interface 1
Alternativní nastavení
ID alternativního nastavení
Interface 0
-
SET_INTERFACE 00000001b (0x11)
wLength Data
Tabulka 2.8: Seznam standardních požadavků na interface. Zdroj: [11].
bmRequestType
bRequest
wValue
Windex
wLength Data
10000010b
GET_STATUS (0x00)
0
Endpoint 2
Stav endpointu
00000010b
CLEAR_FEATURE (0x01)
Feature selektor
Endpoint 0
-
00000010b
SET_FEATURE (0x03)
Feature selektor
Endpoint 0
-
10000010b
SYNCH_FRAME (0x12)
0
Endpoint 2
FrameNumber
Tabulka 2.9: Seznam standardních požadavků na endpoint. Zdroj: [11].
20
2.6.8 Typy přenosů USB standard definuje čtyři typy přenosů dat, z nichž každý má své specifické využití a výhody. Každý endpoint má definován konkrétní typ přenosu [4].
2.6.8.1 Řídící (control) přenosy Používány pro získání stavu a informací o zařízení a k jeho konfiguraci před použitím. Sestávají ze dvou, případně tří fází : 1. Setup fáze: odeslání požadavku (viz. Tabulka 2.6) do zařízení prostřednictvím SETUP transakce. Požadavek může být buď na přečtení stavu či nastavení zařízení, interface, nebo endpointu. 2. Nepovinná datová fáze: jedna a více IN nebo OUT transakcí. Požadavek ze Setup fáze určuje, kolik dat má být přeneseno. Pokud objem dat přesahuje maximální velikost paketu, budou data rozdělena mezi několik transakcí. 3. Fáze kontroly stavu: oznámení o úspěšnosti přenosu. Je tvořena: •
jednou IN transakcí pokud byla datová fáze tvořena OUT transakcemi, nebo datová fáze nebyla součástí přenosu, nebo
•
jednou OUT transakcí pokud byla datová fáze tvořena IN transakcemi.
[10]
2.6.8.2 Interrupt přenosy Jelikož je veškerá USB komunikace řízena hostem, zařízení nemůže samo od sebe odeslat urgentní data. Místo toho však zařízení může u odpovídajícího Interrupt endpoint deskriptoru určit, jak často by se jej měl host dotazovat na data. Díky tomu má endpoint garantovanou maximální délku prodlevy odeslání urgentních dat. Typicky je využívají klávesnice při stisku klávesy, nebo myši při pohybu nebo stisku tlačítka. [10]
2.6.8.3 Izochronní přenosy Izochronní přenosy probíhají nepřetržitě a periodicky. Přijatá data jsou kontrolována vůči jejich CRC součtům, ovšem v případě chybného paketu se čtení neopakuje. Využívají se např. pro streamování videa či audia, kdy nezáleží na občasných výpadcích dat, ovšem je nutné data přenášet v reálném čase a vyhnout se desynchronizaci. [10]
21
KAPITOLA 2 ANALÝZA A NÁVRH ŘEŠENÍ
2.6.8.4 Hromadné (bulk) přenosy Určené pro nárazově velké objemy dat, které nemusí být přeneseny v reálném čase, ovšem musejí být přeneseny bez chyb. Typicky používány pro přenos dat z a do Flash disků, externích pevných disků, atd. [10]
2.6.9 Enumerace Enumerace je proces identifikace a nastavení nově připojeného USB zařízení. Sestává z: 1) Detekce napětí na D+ nebo D- vodiči. Díky tomu host ví, že bylo připojeno zařízení, a zároveň zda se jedná o fullspeed nebo lowspeed zařízení. 2) Vyčkání po dobu 100 milisekund, aby se ustálilo napětí a zařízení se mohlo inicializovat. 3) Resetování zařízení vysíláním SE0 stavu po dobu 10 – 20 milisekund. 4) Dotázání se zařízení prostřednictvím řídícího přenosu na adresu 0 a endpoint 0 na jeho Device Deskriptor pro zjištění maximální délky paketu. 5) Přiřazení unikátní adresy zařízení prostřednictvím řídícího přenosu. 6) Postupné přečtení všech konfigurací. 7) Výběr a přiřazení konfigurace zařízení podle účelu použití (pokud má zařízení více než jednu konfiguraci).
2.7 Možné problémy Jelikož vlákna mikrokontroléru pracují na frekvenci 100MHz [7], trvá zpracování jedné instrukce 10ns. To by mohlo znamenat problém při použití s fullspeed zařízeními, jako je právě webová kamera, neboť mikrokontrolér má k dispozici pouze 8 instrukcí pro zpracování jednoho bitu. Řešením by mohlo být rozdělení programu do více vláken, kdy jedno vlákno bude pouze číst hodnoty pinů a posílat je dalším vláknům pro následné zpracování. Druhým možným řešením by bylo ukládání obdržených dat do paměti, a jejich zpracování až po obdržení celého paketu, což by ovšem způsobilo zpomalení komunikace jako celku, neboť mikrokontrolér by mohl odpovědět až po prodlevě způsobené dekódováním a zpracováním paketu.
22
Kapitola 3
Popis řešení
3.1 Hardware Jako základ konektoru byl zvolen prodlužovací USB kabel, od kterého byl odstřižen konec se „samcem“. Místo odstřiženého konce se jednotlivé vodiče v kabelu připájely podle schématu 2.8 k odporům a následně k odpovídajícím pinům na 20ti pinové svorkovnici (viz. Obr. 3.1 a Obr. 3.2), která se nasune na piny rozšiřovací oblasti mikrokontroléru. Jako datové piny byly zvoleny XD22 a XD23 a ty byly na svorkovnici ještě vodiči propojeny s piny, které budou po nasunutí svorkovnice na rozšiřovací oblast odpovídat XD12 a XD13 (viz. Obr. 3.4). Díky tomu je každý vodič k dispozici na dvou pinech, kdy jeden pin může být využit pro čtení a druhý pro odesílání.
Obr. 3.1: Vyrobený USB konektor. 23
KAPITOLA 3 POPIS ŘEŠENÍ
Obr. 3.2: Detail vyrobeného USB konektoru.
Obr. 3.3: XK-1A s připojeným USB konektorem.
24
Jak je patrné z Obr. 3.4, svorkovnice se na mikrokontrolér nasazuje na rozšiřovací oblast, která je dále od tlačítek a blíže k čipu. Zároveň XTAG2 Debug adaptér je možné na mikrokontrolér připojit jen na jediném místě, a pomáhá tedy s rozlišením správné rozšiřovací oblasti (viz. Obr. 3.3). Rozšiřovací oblast má dvě řady po osmi pinech, svorkovnice dvě řady po deseti. Svorkovnice musí být otočena tak, aby kabel k ni připojený byl dále od XTAG2 Debug adaptéru. Následně se nasadí na rozšiřovací oblast, aby strana svorkovnice s kabelem byla připojena na piny, na opačné straně (směrem k XTAG2 Debug adaptéru) pak bude svorkovnice přečnívat (viz Obr. 3.5).
Výstupní piny Vstupní piny GND XD11
Napájení XD12
XD13
5V
XD14
XD15
XD10
XD16
XD17
XD9
XD8
3V3
GND
XD7
XD6
XD18
XD19
GND
3V3
XD20
XD21
XD5
XD4
XD22
XD23
XD3
XD2
5V
XD1
XD0
GND
Obr. 3.4: Zvolené piny na rozšiřovací oblasti. Zdroj: [2].
GND XD11
XD12
XD13
5V
XD14
XD15
XD10
XD16
XD17
XD9
XD8
3V3
GND
XD7
XD6
XD18
XD19
GND
3V3
XD20
XD21
XD5
XD4
XD22
XD23
XD3
XD2
5V
XD1
XD0
GND
Obr. 3.5: Správné nasunutí svorkovnice konektoru. Zdroj: [2].
25
KAPITOLA 3 POPIS ŘEŠENÍ
3.2 Konfigurace Jelikož je pro USB čtení a zápis potřeba získat 12MHz hodinový signál, bylo v XN souboru, který obsahuje konfigurační data pro mikrokontrolér, nastavena jako cílová frekvence referenčních hodin 96MHz (viz. Obr. 3.6). Při kompilaci se automaticky dopočítají hodnoty pro konstanty, použité pro dělení a násobení 20MHz signálu z hardwarového oscilátoru. Zároveň se tímto změní i frekvence procesoru, v tomto případě z 400MHz na 480MHz. Po vydělení referenčního 96MHz hodinového signálu osmi tedy vyjde signál o frekvenci 12MHz.
Obr. 3.6: Konfigurace frekvence referenčních hodin. Dále byla připravena xSCOPE konfigurace (config.xscope soubor) pro monitorování pinů rozšiřovacích oblastí a vytvořena Debug spouštěcí konfigurace se zapnutým xSCOPE (viz. Obr. 3.7). Zatímco však při spuštění v simulátoru fungoval xSCOPE bez problémů, při spuštění v mikrokontroléru program zamrzl ihned po startu a vůbec se jej nepovedlo spustit. xSCOPE konfigurace tedy musela být vynechána.
Obr. 3.7: Debug konfigurace s aktivním xSCOPE. 26
3.3 Implementace 3.3.1 Zpracování dat během jejich přijímání – neúspěšné Původním záměrem bylo čtení a odesílání dat rozdělit do několika paralelně běžících vláken a zpracovávat data přímo během čtení a odesílání. Jelikož mikrokontrolér garantuje pro každé vlákno plný výkon při maximálním počtu čtyř paralelně spuštěných vláken, bylo čtení implementováno jako pipeline o čtyřech fázích: 1. Přečtení aktuálního stavu na D+ a D- vodičích. Jelikož je možné použít bufferované porty, je prodleva mezi čtením obou hodnot minimální. Bez bufferování by vlákno muselo čekat na sestupnou hranu hodinového signálu přiřazeného k danému portu, a hodnotu z druhého vodiče by tak mohla přečíst až při další sestupné hraně. Přečtený stav odešle následujícímu vláknu. 2. Dekódování stavu. Vlákno přijme data z předchozího vlákna v pipelině, bit po bitu je prochází a porovnává je s posledním zapamatovaným stavem. Pokud je aktuální stav totožný s předchozím, jedná se o 1, pokud ne, jedná se o 0. Výsledný bit odešle následujícímu vláknu. 3. Bit stuffing. Vlákno přijme bit z předchozí fáze a podle jeho hodnoty větví zpracování: •
Pokud jde o jedničku, inkrementuje čítač pro po sobě jdoucí jedničky a odešle bit do následujícího vlákna v pipelině.
•
Pokud jde o nulu, zkontroluje, zda čítač pro po sobě jdoucí jedničky již není roven šesti. Pokud ano, pak nulu ignoruje. Pokud ne, pak ji pošle následujícímu vláknu. V obou případech zresetuje čítač.
4. Agregace. Vlákno přijímá jednotlivé bity a sestavuje z nich bajty, ze kterých následně sestaví celý obdržený paket. Komunikace mezi vlákny byla řešena pomocí proudových (streamovaných), bufferovaných kanálů na procesoru. Jak odeslání dat do kanálu, tak jejich příjem tedy trvaly pouze jednu instrukci a jednalo se tak o nejrychlejší způsob předávání dat mezi vlákny. Zároveň odeslání dat do kanálu nemusí čekat až se cílové vlákno uvolní, za předpokladu, že je stále místo v bufferu kanálu. Obdobně byla řešena pipeline pro zápis. Bohužel ani při rozdělení na čtyři vlákna nebylo zpracování dat dostatečně rychlé, buffery komunikačních kanálů se postupně zaplnily a vlákna na sebe musela čekat, viz. výstup hodnot na pinech testovacího odeslání dat při spuštění v simulátoru na Obr. 3.8.
27
KAPITOLA 3 POPIS ŘEŠENÍ
Obr. 3.8: Zpoždění zápisu kvůli pomalému zpracování dat. Dalším problémem tohoto druhu implementace byla snížená čitelnost kódu, neboť všechna vlákna musejí být vytvořena přímo v main() funkci. Navíc muselo každé vlákno obsluhovat jak jednu fázi čtení, tak jednu fázi zápisu, a být vnitřně větveno podle aktuálně aktivní pipeline. Zároveň muselo obsahovat dva proudové kanály pro příjem a odesílání dat vláknům ve čtecí pipelině, a další dva pro příjem a odesílání dat vláknům v zapisovací pipelině.
3.3.2 Zpracování dat před odesláním a po přijetí Jelikož veškerou komunikaci po USB řídí host, kdy zařízení čeká s odesíláním dat na IN token, může být zpracování dat trochu opožděno bez dopadu funkcionalitu. Veškerá přijímaná data jsou pouze ukládána do bufferu bez jakéhokoliv zpracování, pouze se detekuje SE0 značící konec paketu. Teprve po přijetí celého paketu se začnou data dekódovat, odstraní se bit stuffing a sestaví dekódovaný paket. Při odesílání se paket nejprve zakóduje a následně se zakódovaná data odesílají bit po bitu (respektive po 32 bitových částech) Od vícevláknové implementace bylo upuštěno pro lepší čitelnost a přehlednost kódu. Většina programu je napsána v C++, pouze nejnižší funkce, jako je samotné čtení a zápis hodnot na piny, jsou psány v XC a následně volány z C++.
3.3.3 Popis zdrojového kódu 3.3.3.1 USB/xc/IO/USBIn Stará se o všechny nízkoúrovňové vstupní operace nad porty. Poskytuje funkce:
28
•
usbInitIn(): zajišťuje inicializaci vstupních portů, invertování D+ portu pro snazší práci, konfiguraci hodin a jejich spuštění,
•
waitForConnection(): čeká na připojení zařízení k USB konektoru,
•
usbRecv(): stará se o čtení dat do poskytnutého bufferu, pro minimalizaci prodlevy mezi odesláním paketu a nasloucháním na vstupních portech se funkce synchronizuje s koncem poslední výstupní operace.
3.3.3.2 USB/xc/IO/USBOut Stará se o všechny nízkoúrovňové výstupní operace nad porty. Poskytuje funkce: •
usbInitOut(): zajišťuje konfiguraci a spuštění výstupních hodin,
•
usbInitOutPorts(): inicializuje výstupní porty, invertuje D+ port a aktivuje je,
•
usbSendReset(): udržuje SE0 signál po dobu alespoň 10 milisekund a následně vrátí datové vodiče do J stavu za účelem resetu zařízení,
•
usbSendResume(): udržuje K signál po dobu alespoň 20 milisekund, následovaný SE0 signálem po dobu dvou lowspeed bittimů a J stavem po dobu jednoho lowspeed bittimu za účelem probuzení zařízení,
•
usbHandleSOF(): čeká, dokud neuplynula jedna milisekunda od posledního StartOfFrame paketu, načež odešle další,
•
usbSend(): odešle zakódovaná data po USB (nestará se o jejich zakódování).
Mikrokontrolér u výstupních portů udržuje hodnotu z posledního zápisu. Kdyby zůstaly porty stále aktivní, zařízení by nemohlo odeslat odpověď, neboť by datové vodiče byly neustále obsazeny. Pokud tedy není specifikováno jinak, pak se po všech výstupních operacích automaticky deaktivují výstupní porty a následně se znovu aktivují před provedením další výstupní operace.
3.3.3.3 USB/cpp/DataCont Třída, sloužící jako jednoduchý kontejner pro zakódovaná data. Obsahuje: •
pole unsigned integerů pro samotná data,
•
délku pole,
•
počet bitů dat v prvcích pole (snadno se tedy může přejít z implementace s 32 bitovými bufferovanými porty na 8 bitové),
•
počet bitů dat v posledním prvku pole (ten může mít kvůli bit stuffingu nepředvídatelnou délku).
29
KAPITOLA 3 POPIS ŘEŠENÍ
3.3.3.4 USB/cpp/CRC Poskytuje funkcionalitu pro výpočet CRC5 a CRC16 kontrolních součtů používaných u většiny paketů. Algoritmus pro přidání bitu do součtu vypadá následovně: outBit = ((crc & 1) != 0); crc >>= 1; crc &= bitMask; if (outBit ^ bit) { crc ^= polyMask; } Kde bit je přidávaný bit, crc je aktuální hodnota crc kontrolního součtu, polyMask je maska odpovídající CRC polynomu (101001 pro CRC5, 10100000000000011 pro CRC16)
3.3.3.5 USB/cpp/NRZI Obsahuje třídy pro zakódování paketů do non-return-to-zero-inverted kódu a zpětné dekódování NRZI dat na pakety podle kapitoly 2.6.3Kódování informace při přenosu. Dekódování je implementováno pouze pro Data a Handshake pakety, neboť ostatní pakety může odesílat pouze host.
3.3.3.6 USB/cpp/Packet Obsahuje abstraktní Packet třídu, ze které dědí všechny třídy konkrétních paketů (viz. Obr. 3.9) s datovou strukturou podle kapitoly 2.6.6Druhy paketů. Jednotlivé třídy paketů definují: •
své platné PID kódy a metody pro jejich kontrolu,
•
metody pro zakódování do non-return-to-zero-inverted pomocí NRZI tříd,
•
výpočet kontrolního CRC součtu, pokud jej daný druh paketu má obsahovat.
Při změně jakékoliv vnitřní proměnné paketu se automaticky nastaví příznak pro vygenerování nového CRC součtu (pokud paket CRC součet obsahuje), který se vygeneruje při nejbližším přístupu k CRC proměnné.
30
Obr. 3.9: UML diagram tříd paketů.
31
KAPITOLA 3 POPIS ŘEŠENÍ
3.3.3.7 USB/cpp/Controller Třída, starající se o komplexní obsluhu a inicializaci USB konektoru s pomocí popsaných XC funkcí a C++ tříd: 1) Spustí inicializaci jednotlivých vstupních a výstupních portů a hodin. 2) Čeká na připojení zařízení. 3) Po připojení odešle 100 StartOfFrame paketů, čímž zajistí 100 milisekundovou prodlevu po připojení. 4) Odešle Reset signál. 5) Odešle dalších 100 StartOfFrame paketů. 6) Zahájí proces enumerace: 1) Odešle Get Descriptor požadavek. 2) Odešle Set Address požadavek. Po dokončení inicializace by dále měla poskytovat funkcionalitu pro stažení obrázku ze zařízení (webové kamery). Bohužel se však webová kamera během enumerace hlásí jako zaneprázdněna, nemůže tedy být úspěšně nakonfigurována a bez konfigurace nemůže být použita pro snímání obrázků.
3.3.3.8 Reader Hlavní třída, jež by měla využívat Controller objekt pro stažení obrázku z webové kamery. Následně by měla obrázek zpracovat za účelem rozpoznání číslic v něm, a rozpoznané číslice odeslat do počítač přes XTAG2 Debug adaptér. Nedokončeno kvůli problémům s konfigurací webové kamery.
3.3.3.9 Simulator Jednoduchý simulátor připojeného USB zařízení. Pro používání je nutné v Globals.h nastavit SIMULATOR 1, a spustit program v režimu simulátoru (menu Run – Debug Configurations – v záložce Main vybrat Run on: Simulator) s nastaveným propojením portů podle Obr. 3.10
32
Obr. 3.10: Nastavení propojení portů v simulátoru.
3.3.3.10
Tests
Jelikož XMOS přímo nepodporuje žádné testovací frameworky (obzvláště pro jazyk XC), byly napsány alespoň základní testovací funkce. Testy se zapínají v Globals.h nastavením RUN_TESTS 1. Testována je: •
CRC5 a CRC16 funkcionalita podle [17],
•
NRZI kódování a dekódování samostatných dat,
•
kódování a dekódování Handshake a Data paketů, včetně automatického výpočtu CRC kontrolních součtů.
33
KAPITOLA 3 POPIS ŘEŠENÍ
34
Kapitola 4
Výsledky testování
Testováno bylo na XK-1A mikrokontroléru s XTAG2 Debug adaptérem, které byly zapůjčeny od vedoucího práce prof. Ing. Pavla Zahradníka, CSc. Použitá testovaná webová kamera byla Logitech C110. Kvůli nefunkčnosti xSCOPE při použití s mikrokontrolérem, a kvůli nemožnosti krokovat program za běhu, probíhalo testování prostřednictvím opakovaného spouštění programu v debug módu s breakpointy nastavenými vždy po nějakém klíčovém momentu. Spouštěcí debug konfigurace byla vytvořena v xTIMEcomposeru po kompilaci (pravý klik na projekt a volba Build Project) pomocí menu Run – Debug Configurations – Vytvoření nové konfigurace s Build Configuration: Debug; Run on: hardware; Target: XMOS XTAG-2 connected to L1[0].
4.1 Detekce připojení zařízení Prvním klíčovým momentem byla detekce připojení zařízení, první breakpoint tedy byl nastaven v Controller.cpp první instrukci po návratu z waitForConnection() funkce, čemuž odpovídá řádek 64. Bez připojené kamery mikrokontrolér pouze čekal, po jejím připojení se program zastavil na nastaveném breakpointu (viz. Obr. 4.1), detekce připojení zařízení tedy funguje.
Obr. 4.1: Úspěšná detekce připojeného zařízení.
35
KAPITOLA 4 VÝSLEDKY TESTOVÁNÍ
4.2 Potvrzení přijetí paketů s GetDescriptor požadavkem Dalším důležitým momentem je odeslání GetDescriptor požadavku prostřednictvím řídícího přenosu. Nejprve je odeslán SETUP token, následovaný Data paketem, který obsahuje samotný požadavek. Na tyto dva pakety má zařízení odpovědět ACK Handshake paketem (PID 0010b, PID doplněný o svou vlastní negaci kvůli kontrole správnosti 1101 0010b). Tentokrát byl tedy breakpoint nastaven na řádek po dekódování odpovědi – Controller.cpp:290. Po spuštění a připojení webové kamery se program opět zastavil na nastaveném breakpointu a jako hodnota m_pid paketu je 1101 0010(viz. Obr. 4.2 vpravo nahoře). Základní komunikace tedy funguje a mikrokontrolér je schopen úspěšně odeslat pakety do zařízení, které je rozpozná a potvrdí jejich přijetí.
Obr. 4.2: Obdržený ACK paket na Setup fázi GetDescriptor řídícího přenosu.
4.3 Přijetí Data paketu s deskriptorem Následuje datová část řídícího přenosu. Nyní může zařízení odpovědět buď Data paketem, který obsahuje deskriptor, nebo NAK či STALL Handshake paketem. Breakpointy tedy byly nastaveny dva, jeden v Controller.cpp:247, jehož dosažení by znamenalo přijetí Data paketu, a druhý v Controller.cpp:258, jehož dosažení znamená přijetí Handshake paketu. Jak je patrné z Obr. 4.3, program se zastavil na breakpointu, který odpovídá Handshake paketu. V pravé horní části snímku je také vidět, že přijatý paket má PID 1011010, potažmo 01011010, což je PID NAK Handshake paketu. To znamená, že zařízení nemá na endpointu připravena žádná data pro odesílání, a tedy jeho obslužný software zatím nezpracoval předchozí GetDescriptor 36
požadavek, přestože byl úspěšně přijat. Situace se bohužel nemění ani při prodlevě mezi Setup fází a datovou fází, ani při opakovaném zasílání požadavku. Web kamera je tedy z nějakého důvodu buď zaneprázdněna, nebo neaktivní, a není možné z ní získat data, ani ji nakonfigurovat.
Obr. 4.3: Obdržený NAK paket na datovou část GetDescriptor řídícího přenosu.
37
KAPITOLA 4 VÝSLEDKY TESTOVÁNÍ
38
Kapitola 5
Závěr
V rámci diplomové práce byl úspěšně vyroben funkční konektor pro připojení USB zařízení (v tomto případě webové kamery) k mikrokontroléru XK-1A. Dále byla implementována obsluha hardwaru pro čtení a posílání dat prostřednictvím tohoto konektoru a USB host stack. Bohužel je však z USB host stacku funkční zjevně pouze „nejnižší“ vrstva, tedy funkční komunikace se zařízením ve formě odesílání a příjmu paketů. Vyšší vrstvy stacku, které již komunikují s obslužným softwarem webové kamery, a ne pouze s USB device stackem zařízení, jsou z neznámého důvodu nefunkční. Případné budoucí rozšíření práce by tedy sestávalo ze zprovoznění vyšších vrstev USB host stacku, úspěšného dokončení enumerace, stažení obrazových dat z webové kamery a jejich zpracování.
39
KAPITOLA 5 ZÁVĚR
40
Literatura [1] web: solderpad.com. SolderPad – XMOS XK-1A Development board. http://solderpad.com/xmos/xmos-xk-1a/ stav z 9.1.2014. [2] web: xmos.com. XMOS XK-1A Harware Manual. http://www.xmos.com/download/public/XK-1A-Hardware-Manual%281.1.0%29.pdf stav z 9.1.2014. [3] web: openwrt.org. USB schematic. http://wiki.openwrt.org/_media/oldwiki/openwrtdocs/hardware/comtrend/usb-schematic.png stav z 9.1.2014. [4] web: usbmadesimple.co.uk. USB Made Simple: A Series of Articles on USB, Part 3. http://www.usbmadesimple.co.uk/ums_3.htm stav z 9.1.2014. [5] Přispěvatelé Wikipedie. Non-return-to-zero [online]. [cit.18.12.2013]. Dostupné z: http://en.wikipedia.org/wiki/Non-return-to-zero [6] web: fourwalledcubicle.com. LUFA – Lightweight USB Framework for AVRs. http://www.fourwalledcubicle.com/LUFA.php stav z 10.1.2014. [7] web: xmos.com. XC Concurrency. https://www.xmos.com/published/xc-concurrency stav z 10.5.2014. [8] web: beyondlogic.org. USB in a NutShell: Common USB Packet Fields. http://www.beyondlogic.org/usbnutshell/usb3.shtml stav z 9.3.2014. [9] web: thexmoschallenge.files.wordpress.com. XMOS XK-1A + XTAG2. http://thexmoschallenge.files.wordpress.com/2010/03/100_2912.jpg stav z 1.4.2014 [10] web: beyondlogic.org, USB in a NutShell: Endpoint Types. http://www.beyondlogic.org/usbnutshell/usb4.shtml stav z 3.4.2014 [11] web: beyondlogic.org, USB in a NutShell: USB Requests. http://www.beyondlogic.org/usbnutshell/usb6.shtml stav z 3.4.2014 [12] Přispěvatelé Wikipedie. XCore XS1-L1 [online]. [cit.22.11.2013]. Dostupné z: http://en.wikipedia.org/wiki/XCore_XS1-L1 [13] web: xmos.com. XMOS Programming Guide: I/O. https://www.xmos.com/node/17653?page=26 stav z 20.4.2014 [14] web: xmos.com. XS1-L Clock Frequency Control. https://www.xmos.com/published/xs1l_clk?secure=1 stav z 20.4.2014
41
LITERATURA [15] web: xmos.com. xSCOPE. http://www.xmos.com/de/products/tools/xscope stav z 23.4.2014 [16] web: xmos.com. xTIMEcomposer STUDIO. https://www.xmos.com/products/tools/xtimecomposer stav z 23.4.2014 [17] web: usb.org. Cyclic Redundancy Checks in USB. http://www.usb.org/developers/whitepapers/crcdes.pdf stav z 24.4.2014
42