Vyvoj USB ovladaca 2
V tejto časti sa oboznámime s hardvérom, ktorým bude vývojová doska pre ARM mikroprocesor SAM3X8H od Atmelu. Ukážeme si ako pomocou Atmel Software Framework umožniť nášmu procesoru komunikovať pomocou USB a popíšeme si, ako bude naše zariadenie fungovať.
Atmel Software Framework (ASF)
Každý, kto sa niekedy zahrával s myšlienkou naučiť sa naprogramovať USB zariadenie, určite narazil na problém, ako svoj kód otestovať. Vytvoriť USB ovládač je jedna vec, úspešne ho nainštalovať je vec druhá, ale zistiť, či ovládač funguje tak ako má je bez príslušného zariadenia, s ktorým by ovládač komunikoval, takmer nemožné. V začiatkoch vám USB môže priniesť skutočne nečakané problémy, ktoré ale majú pôvod v maličkostiach spôsobených nepozornosťou alebo neznalosťou. Vidieť potom vaše zariadenie pracovať tak ako má pomocou vášho ovládača je pre geeka ako ja malý zázrak.
Celý tento seriál mohol vzniknúť aj vďaka tomu, ako Atmel pristupuje ku svojim produktom. Príkladom jeAtmel Software Framework, služby, komponenty a ovládače určené pre mikroprocesory od Atmelu. Niekoľkými kliknutiami v programe Atmel Studio pridáte funkčnosť USB do vášho zariadenia bez toho, aby ste museli ovládať rôzne špecifikácie USB alebo samotnú komunikáciu pomocou USB, o ktorú sa stará sada služieb a ovládačov ASF. Pokiaľ vaša aplikácia potrebuje odoslať interrupt pakety pomocou USB, stačí vám vedieť názov jednej funkcie plus to ako ju použiť, nič viac, nič menej.
Funkcie v ASF sú zrozumiteľné, popísané aj s príkladmi a sú konzistentné naprieč viacerými typmi mikroprocesorov. Nezáleží na tom, či niekto použije SAM3, SAM4, UC3, XMega alebo iný mikroprocesor, ktorý podporuje USB, princíp bude vždy rovnaký. Na ukážku vývoja ovládača a zariadenia k nemu je preto ASF ako stvorená, keďže tento seriál bude vedený v duchu všeobecného návodu, nie exaktný postup pre jeden typ mikroprocesora.
Atmel Software Framework – USB
Podpora USB je v ASF rozdelená do niekoľkých vrstiev:
UDD – USB Device Driver
Ovládač fyzického rozhrania USB. Pod týmto pojmom si predstavte niečo, čo pracuje s registrami mikroprocesora vyhradenými pre USB. Používateľ ani ďalšie vrstvy, ktoré sú založené na UDD, sa tak nemusia starať priamo o fyzické vlastnosti a funkčnosť USB (kódovanie prenosu, frekvencia a pod.), ktoré sú dostupné cez registre (procesor SAM3X obsahuje on-chip PHY (physical – fyzický) ovládač, vstavaný do mikroprocesora).
UDC – USB Device Controller
Slúži na základnú komunikáciu s hostom. Spravuje konfiguráciu zariadenia, ktorú následne poskytuje hostovi. Programátor nastaví informácie v konfigurácii ako napr. rýchlosť, ktorou bude zariadenie komunikovať (USB High-speed alebo Full-speed), nastaví maximálne veľkosti zásobníkov pre jednotlivé endpointy, názov zariadenia a meno výrobcu a pod. UDC sa postará o to, aby sa táto konfigurácia dostala hostovi v podobe deskriptorov. Dá sa teda povedať, že okrem iného UDC spravuje nultý endpoint, ktorý je určený pre kontrolné prenosy.
Pokiaľ UDD obdrží kontrolný paket, posunie ho ďalej UDC, ktorý, pokiaľ je určený rozhraniu, informuje o tom vyššiu vrstvu (UDI) a tá následne dáta spracuje. Tento prípad nastane vtedy, keď budeme nášmu zariadeniu posielať a prijímať z neho kontrolné údaje my. Nultý endpoint teda slúži na viacero účelov. Štandardné požiadavky (deskriptory, nastavenie adresy a pod.) rieši UDD a UDC, pokiaľ požiadavku určíme rozhraniu, prevezme ju UDI. Celkom jednoduché a veľmi efektívne rozdelenie práce medzi vrstvy USB služieb.
UDI – USB Device Interface
Pre nás veľmi dôležité – rozhranie USB zariadenia. Ako z minulého dielu viete, rozhranie je zoskupenie určitých funkcií zariadenia. Napr. taká tlačiareň môže mať jedno rozhranie – tlačiareň. Multifunkčná tlačiareň bude mať rozhrania minimálne dva a to tlačiareň a skener. ASF ponúka hneď niekoľko pripravených UDI rozšírení, napr. HID (Human Interface Device) pre myši a klávesnice, MSC (Mass Storage Class) pre zariadenia poskytujúce úložisko dát, CDC (Communications Device Class) pre virtuálny sériový port. V našom prípade použijeme UDI Vendor, ktoré implementáciu funkčnosti zariadenia ponecháva na „vendorovi“, čiže na nás.
Úvod do kódu
Na začiatok nám bude postačovať vytvoriť aplikáciu, ktorá bude schopná inicializovať sa a pripojiť sa pomocou USB s tým, že po pripojení na počítač sa operačný systém bude snažiť nainštalovať ovládač pre naše zariadenie.
Keďže programujem v prostredí Atmel Studio 6.0, vytvorím projekt na vývojovú dosku SAM3-EK, ktorá obsahuje procesor SAM3X8H. Atmel Studio vytvorí prednastavené konfiguračné súbory, pretože procesor potrebuje vedieť aké rozhrania a zariadenia má pripojené na svojich pinoch. Napr. aby som bol schopný rozsvietiť LED, musím procesoru oznámiť, na ktorom pine sa LED nachádza a taktiež to, že tento pin sa má používať ako výstup. Celá táto inicializácia je vygenerovaná ASF presne pre vývojovú dosku SAM3-EK.
Celá naša hlavná aplikácia bude bežať v jednom cykle, v ktorom sa každých 25 milisekúnd skontroluje stav tlačidiel a vykoná sa konverzia ADC (Analog To Digital) pre potenciometer a teplotný senzor. Pokiaľ sa v cykle zistí, že stav tlačidiel nesúhlasí s naposledy uloženým stavom, aplikácia sa pokúsi odoslať nový stav pomocou interrupt prenosu, ale k tomu sa dostaneme v ďalšej časti seriálu, kde budú jednotlivé prenosy presnejšie popísané.
Prerušeniam, ktoré budú súvisieť s USB, sa procesor bude venovať až keď nastanú, keďže sú to interrupty (prerušenia). V nich budeme riešiť ostatné prenosové módy.
Na to, aby sa v aplikácii mohlo využívať USB, musíme pomocou ASF pridať do projektu USB služby pre zariadenie (SAM3X8H podporuje taktiež služby hosta a On-The-Go (host alebo zariadenie, tzv. dual-role)). Obrázok z Atmel Studio napovie, aké vrstvy bude aplikácia využívať:
Vrstvy USB služieb v Atmel Software Framework
Keďže zariadenie nebude používať štandardné triedy USB (HID, CDC, MSC a pod.), do projektu som vložil „vendor_class“. ASF následne vloží UDI (rozšírené o „vendor_class“), ďalej UDC a UDD (SAM UOTGHS – USB On-The-Go High Speed). Iste si všimnete, že UDD má pri sebe zvolenú možnosť „without_sleepmgr“. Procesory SAM3 podporujú niekoľko módov behu programu, či už backup mód, pri ktorom procesor spotrebúva minimálne množstvo energie ale kód sa nevykonáva, pokiaľ procesor niečo „neprebudí“, alebo normálny mód, v ktorom náš kód bude pracovať bežne. Sleep manager slúži na to, aby spravoval tieto módy a zabezpečil, aby procesor nevošiel do „spánku“ ak niektorý komponent vyžaduje aktívny mód. Pokiaľ ale naše zariadenie „zaspí“, zobudiť ho môžu len určité udalosti, napr. IRQ z USB (ak host odošle SOF paket, používateľ zapojí kábel medzi hostom a naším zariadením a pod.). Z dôvodu, aby bol kód prehľadný, keďže má byť všeobecne zameraný, Sleep manager nepoužijem. Zariadenie teda bude pracovať stále rovnako vo svojom cykle, kde bude kontrolovať stav tlačidiel a uskutočňovať prevod pomocou ADC.
Konfigurácia USB v zariadení
Jednou zo základných vecí je správne nakonfigurovať USB v ASF. Implementácia od nás očakáva, aby sme definovali niektoré základné funkcie, ktoré budú volané službami UDI, UDC a UDD. Taktiež musíme nastaviť VID (Vendor ID) a PID (Product ID), môžeme nastaviť meno výrobcu a názov zariadenia a pod. Tieto údaje budú slúžiť deskriptoru zariadenia a konfigurácie.
Následne je potrebné nastaviť rozhrania a endpointy. Keďže naša aplikácia bude mať jedno rozhranie, zariadenie nie je tzv. composite device (obsahovalo by viacero rozhraní), UDI potrebuje iba niekoľko informácií k tomu, aby si deskriptor rozhrania a endpointov vytvorilo samo, a to konkrétne iba veľkosti na endpointoch pre bulk, isochronous a interrupt. Adresy endpointov si UDI určí samo.
Kód konfigurácie:
// VID – Vendor ID
#define USB_DEVICE_VENDOR_ID 0xABCD
// PID – Product ID
#define USB_DEVICE_PRODUCT_ID 0x1234
// Verzia zariadenia
#define USB_DEVICE_MAJOR_VERSION 1
#define USB_DEVICE_MINOR_VERSION 0
// Odber zo zbernice v mA
#define USB_DEVICE_POWER 100
// Atribúty Zariadenie je napájané externe, nie zo zbernice USB
#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_SELF_POWERED)
// Meno výrobcu
#define USB_DEVICE_MANUFACTURE_NAME "Matej Tomcik"
// Názov zariadenia
#define USB_DEVICE_PRODUCT_NAME "SAM3X-EK"
// Zariadenie podporuje High Speed
#define USB_DEVICE_HS_SUPPORT
// Funkciu, ktorú bude volať UDD pri zistení zmeny napätia na VBus
#define UDC_VBUS_EVENT(b_vbus_high) app_vbus_action(b_vbus_high)
extern void app_vbus_action(bool b_vbus_high);
// Funkciu, ktorú bude volať UDD, keď dostane SOF paket
#define UDC_SOF_EVENT() app_sof_action()
extern void app_sof_action(void);
// Funkciu, ktorú UDD zavolá pri vstupe zariadenia do SUSPEND módu
#define UDC_SUSPEND_EVENT() app_suspend_action()
extern void app_suspend_action(void);
// Funkciu, ktorú UDD zavolá pri výstupe zariadenia zo SUSPEND módu
#define UDC_RESUME_EVENT() app_resume_action()
extern void app_resume_action(void);
// Funkciu, ktorú UDI volá pri povolení rozhrania
#define UDI_VENDOR_ENABLE_EXT() app_vendor_enable()
extern bool app_vendor_enable(void);
// Funkciu, ktorú UDI volá pri zastavení rozhrania
#define UDI_VENDOR_DISABLE_EXT() app_vendor_disable()
extern void app_vendor_disable(void);
// Funkciu, ktorú UDI volá, keď dostane kontrolný paket OUT určený vendor rozhraniu
#define UDI_VENDOR_SETUP_OUT_RECEIVED() app_setup_out_received()
extern bool app_setup_out_received(void);
// Funkciu, ktorú UDI volá, keď dostane kontrolný paket IN určený vendor rozhraniu
#define UDI_VENDOR_SETUP_IN_RECEIVED() app_setup_in_received()
extern bool app_setup_in_received(void);
Funkcie, ktoré sme v konfigurácii definovali
- app_vbus_action – UDD zavolá túto funkciu, keď zistí zmenu napätia na VBus. V prvom článku ste si mohli všimnúť, čo sa nachádza vo vnútri USB kábla. Na VBus v USB sa nachádza +5V, keď prepojíte hosta so zariadením pomocou USB kábla, procesor zistí, že na jednom z pinov sa objaví napätie +5V. Vtedy UDD zavolá funkciu definovanú makrom UDC_VBUS_EVENT a ako parameter použije boolean hodnotu, ktorá je pravdivá ak sa na VBus nachádza +5V, inak false. Aplikácia túto funkciu využije, aby po pripojení zariadenia na zbernicu spustila USB služby, ktoré budú následne kontrolovať, čo sa na USB zbernici odohráva a komunikovať s hostom. Po odpojení zariadenia zo zbernice ich aplikácia zastaví.
- app_sof_action – UDD volá túto funkciu, keď dostane SOF paket. Aplikácia ju nevyužíva. Pokiaľ by sme ale chceli naše zariadenie počas nečinnosti uviesť do spánku pomocou Sleep manager, v tejto funkcii by sme dostali priestor vykonať akcie, ktoré budú v našom prípade v hlavnom cykle.
- app_suspend_action – UDD volá túto funkciu pri vstupe zariadenia do SUSPEND módu, naša aplikácia ju nevyužije.
- app_resume_action – UDD volá túto funkciu pri výstupe zariadenia zo SUSPEND módu, naša aplikácia ju nevyužije.
- app_vendor_enable – UDI volá túto funkciu, keď povolí svoje rozhranie. Ovládač, ktorý bude komunikovať s našim zariadením, zavolá funkciu SetAltInterface (host - zvolí alternatívne rozhranie). Naše zariadenie túto požiadavku pochopí ako snahu ovládača povoliť rozhranie.
- app_vendor_disable – UDI volá túto funkciu pri zastavení svojho rozhrania
- app_setup_out_received – UDI volá túto funkciu, keď host odošle SETUP OUT (kontrolný paket), ktorý je určený rozhraniu. Aplikácia v nej zistí, či host odosiela požiadavku na nastavenie LED a LCD a pokiaľ áno, tak tieto dáta prijme a spracuje (rozsvieti alebo zhasne LED, nastaví podsvietenie LCD a pod.). V opačnom prípade, kedy funkcia požiadavku nerozozná, vráti boolean hodnotu false, čím oznámi UDI, že paket nemôže spracovať. UDI sa postará o zvyšok.
- app_setup_in_received – UDI volá túto funkciu, keď host odošle SETUP IN (kontrolný paket), ktorý je určený rozhraniu. Aplikácia v nej zistí, či host požaduje dáta z ADC prevodníka. Pokiaľ áno, naplní dáta paketu hodnotou potenciometra a teplotou procesora. Podobne ako pri app_setup_out_received, funkcia vráti true, čím oznámi UDI, že paket bol spracovaný a UDI môže dáta odoslať hostovi. V opačnom prípade vráti false.
Jednotlivé prenosové módy a príklady ich použitia budú popísané v ďalšej časti tohto seriálu.
Kód aplikácie
#include <asf.h>
// Počítadlo milisekúnd
static volatile uint32_t appTicks = 0;
// Určuje, či je rozhranie povolené
static volatile bool appVendorEnabled = false;
int main(void)
{
// Skonfigurovať IRQ
irq_initialize_vectors();
cpu_irq_enable();
// Inicializovať vývojovú dosku (skonfigurovať piny)
board_init();
// Inicializovať systémové hodiny
sysclk_init();
// SysTick_Handler bude volaný každú 1 milisekundu
SysTick_Config(sysclk_get_cpu_hz() / 1000);
// Spustiť USB Device
udc_start();
// Pokiaľ zariadenie nepodporuje sledovanie stavu na VBus,
// budeme predpokladať, že zariadenie je už na USB pripojené
if (!udc_include_vbus_monitoring())
app_vbus_action(true);
while (1)
{
if (appTicks > 25)
{
appTicks = 0;
// Získať stav tlačidiel a QTouch a spustiť konverziu ADC
// pre potenciometer a teplomer
if (appVendorEnabled)
{
}
}
}
}
// Event volaný každú 1 milisekundu
void SysTick_Handler(void)
{
appTicks++;
}
// Aktivita na VBus
void app_vbus_action(bool b_high)
{
// Pripojiť sa na USB zbernicu, pokiaľ sa na VBus zistí napätie
if (b_high)
udc_attach();
else
udc_detach();
}
// Zariadenie prešlo do suspend módu
void app_suspend_action(void)
{
}
// Zariadenie vyšlo zo suspend módu
void app_resume_action(void)
{
}
// Spracovať SOF paket (pri HS používaný ako keep alive, odoslaný hostom
// každých 125 us
void app_sof_action(void)
{
}
// Rozhranie zariadenia bolo povolené
bool app_vendor_enable(void)
{
appVendorEnabled = true;
return true;
}
// Rozhranie zariadenia bolo zastavené
void app_vendor_disable(void)
{
appVendorEnabled = false;
}
// Spracovať požiadavku OUT z kontrolného paketu
bool app_setup_out_received(void)
{
return false;
}
// Spracovať požiadavku IN z kontrolného paketu
bool app_setup_in_received(void)
{
return false;
}
Naša aplikácia začne svoju prácu povolením interrupt požiadaviek, ďalej nakonfiguruje svoje GPIO piny, inicializuje systémové hodiny, ktoré my využijeme, aby sme každú 1 milisekundu zvýšili počítadlo milisekúnd. Následne sa spustia USB služby pomocou funkcie udc_start(). Tá povolí periférny obvod USB, nastaví hodiny pre USB, povolí interrupty a pod. Pred vstupom do hlavného cyklu aplikácie sa musíme uistiť, že náš procesor podporuje monitorovanie VBus. Pokiaľ by sme takúto podporu nemali, funkciu app_vbus_action by UDC nikdy nezavolal. V tomto prípade musíme predpokladať, že zariadenie ku zbernici už pripojené môže byť.
V hlavnom cykle aplikácie bude každých 25 milisekúnd prebiehať kontrola stavu tlačidiel, QTouch a prevod hodnoty potenciometra a teplomera pomocou ADC.
Ako to celé funguje?
- Procesor sa inicializuje.
- Inicializujú sa systémové hodiny, naša aplikácia bude dostávať udalosť každú 1 milisekundu, USB zase môže správne nastaviť svoje hodiny.
- Spustia sa USB služby, UDD začne monitorovať zbernicu (pokiaľ to procesor podporuje).
- Akonáhle pripojíte USB kábel k zariadeniu (ktorý je už pripojený k hostovi), procesor zistí napätie na VBus. UDD zavolá funkciu app_vbus_action(true), a naša aplikácia pomocou funkcie udc_attach() oznámi procesoru, že chce aby sa správal ako zariadenie. UDC teraz môže komunikovať s hostom.
- Host si od zariadenia vyžiada deskriptory, o niektoré sa postará UDC (deskriptor zariadenia a konfigurácie), o ostatné sa stará UDI. Pokiaľ host odošle kontrolný paket, ktorý je určený rozhraniu, UDI zavolá funkciu app_setup_out_received() alebo app_setup_in_received() v závislosti od toho, či host dáta odosiela alebo ich prijíma.
Príklady deskriptorov
V nižšie uvedenom kóde vidno, ako UDI definuje deskriptor zariadenia. Základné údaje sú napr. bDescriptorType (typ deskriptora, v tomto prípade sa jedná o deskriptor zariadenia), bcdUSB (verzia USB), bDeviceClass, bDeviceSubClass a bDeviceProtocol určujú triedu, do ktorej možno toto zariadenie zaradiť. Keďže naše zariadenie určuje triedu v deskriptore rozhrania, tieto údaje zostanú prázdne. Ďalej sa definuje VID a PID (idVendor a idProduct) a indexy textových hodnôt. Keďže sme nastavili, aby naše zariadenie malo názov „SAM3-EK“ a výrobcu „Matej Tomcik“, v deskriptore sa v políčku iManufacturer objaví hodnota 1 a v iProduct hodnota 2. Host si potom vyžiada tieto textové hodnoty pomocou textových deskriptorov, opýta sa zariadenia na text priradený k hodnote 1, zariadenie vráti „Matej Tomcik“ a pod.
usb_dev_desc_t udc_device_desc = {
.bLength = sizeof(usb_dev_desc_t),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = LE16(USB_V2_0),
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE,
.idVendor = LE16(USB_DEVICE_VENDOR_ID),
.idProduct = LE16(USB_DEVICE_PRODUCT_ID),
.bcdDevice = LE16((USB_DEVICE_MAJOR_VERSION << 8)
| USB_DEVICE_MINOR_VERSION),
#ifdef USB_DEVICE_MANUFACTURE_NAME
.iManufacturer = 1,
#else
.iManufacturer = 0, // No manufacture string
#endif
#ifdef USB_DEVICE_PRODUCT_NAME
.iProduct = 2,
#else
.iProduct = 0, // No product string
#endif
#ifdef USB_DEVICE_SERIAL_NAME
.iSerialNumber = 3,
#else
.iSerialNumber = 0, // No serial string
#endif
.bNumConfigurations = 1
};
V ďalšom príklade uvedenom pod týmto textom sa nachádza deskriptor konfigurácie pre High Speed zariadenie. Ako z prvého dielu tohto seriálu už vieme, deskriptor konfigurácie sa odosiela spolu s deskriptorom rozhrania a endpointami, ktoré sú vložené cez políčko udi_vendor.
udc_desc_t udc_desc_hs = {
.conf.bLength = sizeof(usb_conf_desc_t),
.conf.bDescriptorType = USB_DT_CONFIGURATION,
.conf.wTotalLength = LE16(sizeof(udc_desc_t)),
.conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE,
.conf.bConfigurationValue = 1,
.conf.iConfiguration = 0,
.conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR,
.conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),
.udi_vendor = UDI_VENDOR_DESC_HS,
};
V poslednom príklade vidno deskriptor rozhrania. Rozhranie je iba jedno, ale má alternatívne nastavenie, preto vidno iface0 a iface1. Keď ovládač zavolá SetAltInterface(1), zariadenie aktivuje alternatívne rozhranie (iface1).
#define UDI_VENDOR_DESC \
.iface0.bLength = sizeof(usb_iface_desc_t),\
.iface0.bDescriptorType = USB_DT_INTERFACE,\
.iface0.bInterfaceNumber = UDI_VENDOR_IFACE_NUMBER,\
.iface0.bAlternateSetting = 0,\
.iface0.bNumEndpoints = 0,\
.iface0.bInterfaceClass = VENDOR_CLASS,\
.iface0.bInterfaceSubClass = VENDOR_SUBCLASS,\
.iface0.bInterfaceProtocol = VENDOR_PROTOCOL,\
.iface0.iInterface = UDI_VENDOR_STRING_ID,\
.iface1.bLength = sizeof(usb_iface_desc_t),\
.iface1.bDescriptorType = USB_DT_INTERFACE,\
.iface1.bInterfaceNumber = UDI_VENDOR_IFACE_NUMBER,\
.iface1.bAlternateSetting = 1,\
.iface1.bNumEndpoints = UDI_VENDOR_EP_NB,\
.iface1.bInterfaceClass = VENDOR_CLASS,\
.iface1.bInterfaceSubClass = VENDOR_SUBCLASS,\
.iface1.bInterfaceProtocol = VENDOR_PROTOCOL,\
.iface1.iInterface = UDI_VENDOR_STRING_ID,\
.ep_interrupt_in.bLength = sizeof(usb_ep_desc_t),\
.ep_interrupt_in.bDescriptorType = USB_DT_ENDPOINT,\
.ep_interrupt_in.bEndpointAddress = UDI_VENDOR_EP_INTERRUPT_IN,\
.ep_interrupt_in.bmAttributes = USB_EP_TYPE_INTERRUPT,\
.ep_interrupt_in.bInterval = 1,\
.ep_interrupt_out.bLength = sizeof(usb_ep_desc_t),\
.ep_interrupt_out.bDescriptorType = USB_DT_ENDPOINT,\
.ep_interrupt_out.bEndpointAddress = UDI_VENDOR_EP_INTERRUPT_OUT,\
.ep_interrupt_out.bmAttributes = USB_EP_TYPE_INTERRUPT,\
.ep_interrupt_out.bInterval = 1,\
.ep_interrupt_in.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_INT_HS),\
.ep_interrupt_out.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_INT_HS),\
.ep_bulk_in.bLength = sizeof(usb_ep_desc_t),\
.ep_bulk_in.bDescriptorType = USB_DT_ENDPOINT,\
.ep_bulk_in.bEndpointAddress = UDI_VENDOR_EP_BULK_IN,\
.ep_bulk_in.bmAttributes = USB_EP_TYPE_BULK,\
.ep_bulk_in.bInterval = 0,\
.ep_bulk_out.bLength = sizeof(usb_ep_desc_t),\
.ep_bulk_out.bDescriptorType = USB_DT_ENDPOINT,\
.ep_bulk_out.bEndpointAddress = UDI_VENDOR_EP_BULK_OUT,\
.ep_bulk_out.bmAttributes = USB_EP_TYPE_BULK,\
.ep_bulk_out.bInterval = 0,\
.ep_bulk_in.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_BULK_HS),\
.ep_bulk_out.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_BULK_HS),\
.ep_iso_in.bLength = sizeof(usb_ep_desc_t),\
.ep_iso_in.bDescriptorType = USB_DT_ENDPOINT,\
.ep_iso_in.bEndpointAddress = UDI_VENDOR_EP_ISO_IN,\
.ep_iso_in.bmAttributes = USB_EP_TYPE_ISOCHRONOUS,\
.ep_iso_in.bInterval = 1,\
.ep_iso_out.bLength = sizeof(usb_ep_desc_t),\
.ep_iso_out.bDescriptorType = USB_DT_ENDPOINT,\
.ep_iso_out.bEndpointAddress = UDI_VENDOR_EP_ISO_OUT,\
.ep_iso_out.bmAttributes = USB_EP_TYPE_ISOCHRONOUS,\
.ep_iso_out.bInterval = 1,\
.ep_iso_in.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_ISO_HS),\
.ep_iso_out.wMaxPacketSize = LE16(UDI_VENDOR_EPS_SIZE_ISO_HS)
Pozn.: tieto deskriptory používateľ priamo nepoužíva, vytvárajú sa v UDC a UDI. Pri iných mikroprocesoroch sa postup môže a určite bude líšiť.
Na záver
Po naprogramovaní zariadenia a pripojení k počítaču