Choď na obsah Choď na menu
 

USB mikroprocesory PIC a ich použitie 2.

http://mcu.cz/news.php?extend.624.2

V tomto díle stručně popíšu USB firmware vyvinutý Microchipem a dále se podíváme na komunikaci pomocí třídy CDC, tedy pomocí virtuálního sériového portu.

''Pozn. Veškerý software byl testován pod WinXP. Teoreticky by se měl software chovat naprosto stejně pod Win 2000. Pod jinými systémy (Win98, ME) jsem nic nezkoušel a nemůžu zaručit níže uvedené chování operačního systému.''

1. Microchip USB Firmware:
Microchip USB firmware (dále jen „FW“) je soubor funkcí napsaných v C, dodávaný včetně zdrojových kódů, určený pro zjednodušení vývoje pro USB modul v procesorech PIC18. Tento FW má několik částí a je rozdělen do několika souborů:

Já bych chtěl popsat nejdůležitější části, potřebné pro porozumění tomuto FW a pro případnou úpravu identifikace vlastního zařízení.

Nebudu zde ukazovat kompetní funkce, pro lepší přehled je nutné si projekt FW stáhnout, nainstalovat, spustita prohlížet společně s tímto článkem. Já se zaměřím na projekt CDC třídy, neboť komunikace touto třídou je popsána níže.

Začneme u funkce main:

void main(void){
  InitializeSystem();
  while(1)    {
    USBTasks();         // USB Tasks
    ProcessIO();        // See useruser.c & .h
  }//end while
}//end main


Z uvedeného vyplývá, že FW nejprve zavolá funkci pro inicializaci systému InitializeSystem(), resp. počáteční nastavení USB modulu. Tato funkce pak dále volá funkci UserInit(), která je v souboru user.c a do které můžeme vložit i vlastní inicializaci. Dále program pokračuje nekonečnou smyčkou, kdy se postupně volá funkce USBTasks() a ProcessIO(). Je tedy jasné, že celý firmware není založen na přerušení, ale pouze se postupně čtou jednotlivé flagy (příznaky) přerušení od USB a dále se vyhodnocují. Je tedy nutné pro to aby USB FW fungoval správně, vždy tyto funkce postupně volat a nedělat v našem vlastním programu nekonečné smyčky! Dále, v případě, že povolíme odskoky do vektorů přerušení, musíme mít na paměti, že v tom případě je nutné obsloužit nějakým způsobem i přerušení od USB. Funkce USBTasks() tedy obsluhuje všechny žádosti na vstup/výstup po USB. Není dobrý nápad tuto funkci nějak měnit.

Pro naše programování je nejdůležitější soubor user.c. Tento soubor má v sobě dvě hlavní dvě funkce - UserInit() a ProcessIO(). Ta první nění úplně důležitá, tam pouze ukládáme kód pro prvotní inicializaci, ale v druhé funkci práve čteme, příp. zapisujeme na USB sběrnici a dále zde máme de fakto celý vlastní program. Můžeme například připojit klávesnici v jednomu portu, ve funkci ProcessIO() můžeme vyhodnotit zmáčknutou klávesu a poslat ji po USB do PC.

V této funkci je jako první BlinkUSBStatus(). Ta jen aktualizuje stav diod na pinech RD0 a RD1 (viz. vývojová deska z minulého dílu) v závislosti na stavu USB. Podle toho, jestli je zařízení připojeno a jak s ním PC komunikuje, tyto dvě diody buďto blikají, nebo svítí, nebo nesvítí. Je možné tuto funkci vynechat v případě, že potřebujete aby funkce ProcessIO() byla co nejrychlejší. Dále zde můžete umístit vlastní funkce přesně podle toho, co potřebujete. Můžete si třeba udělat další vlastní soubor s libovolnými funkcemi a ty pak z funkce ProcessIO() volat. V části 2 je jednoduchá ukázka toho, jak může ProcessIO() vypadat.

Další soubor máme usb9.c. Tento soubor obsahuje vlastní driver firmwaru a obsahuje funkce pro obsluhu jednotlivých přerušení (resp. jejich flagů) od USB. Myslím, že zde není potřeba cokoli měnit.

V případě, že jste si nainstalovali firmware pro CDC třídu, je zde také soubor __cdc.c__, který obsahuje funkce pro vysílání a přijímání znaků přes virtuální sériový port. Vše je popsáno v další kapitole - třída CDC.

Soubor usbmap.c obsahuje namapování paměti pro jednotlivé endpointy - opět myslím, že zde není potřeba cokoliv měnit.

Soubor usbdsc.c obsahuje konfigurace pro jednotlivé endpointy. Zde si právě můžete změnit řetězce, kterými se bude procesor identifikovat v PC:

rom struct{byte bLength;byte bDscType;word string[25];}sd001={sizeof(sd001),DSC_STR,'M','i','c','r','o','c','h','i','p',' ','T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'};
rom struct{byte bLength;byte bDscType;word string[25];}sd002={sizeof(sd002),DSC_STR,'C','D','C',' ','R','S','-','2','3','2',' ','E','m','u','l','a','t','i','o','n',' ','D','e','m','o'};


V případě, že změníte délku řetězců, je zároveň nutné změnit délku řetězce word string[25].

Jinak měnit konfiguraci endpointů nedoporučuji, celý firmware by mohl přestat fungovat. To již vyžaduje hlubší znalosti USB komunikace.

Soubor usbdrv.c obsahuje funkce pro povolení/zakázání USB modulu, softwarové připojení čí odpojení a obsahuje funkce, které vrací stav USB modulu. Nemyslím si, že zde je potřeba něco měnit. Spíše je vhodné si tento soubor prostudovat, v případě že budete potřebovat zjistit stav USB modulu.

Posledním nehlavičkovým souborem je usbctrltrf.c. Zde jsou funkce pro nastavení USB modulu pro připojení na sběrnici a opět nedoporučuji cokoliv měnit.

Posledním užitečným souborem je io_cfg.h. Ten obsahujepřevážně konfiguraci jendotlivých portů resp. jejich řetězcových zástupců. Např. mLED_1 je definována jako LATD0:

#define mLED_1 LATDbits.LATD0


To je důležité v případě, že nechcete použít procesor 18F4550 ale třeba 18F2550, který neobsahuje PORTD, a v případě, že byste chtěli zkompilovat firmware pro tento procesor, je nutné právě v tomto souboru změnit konfiguraci portu D.

V případě hlubšího zájmu o úpravu firmware doporučuji prozkoumat jednotlivé, výše popsané soubory a také uživatelský návod k originální FS USB board - odkaz byl v minulém dílu.

2. Třída CDC:
Způsob komunikace pomocí CDC je asi nejjednoduší možnost výměny dat mezi PC a procesorem přes USB. Tato třída je definována jako virtuální sériový port, tzn. že nahrajeme-li firmware v konfiguraci CDC do procesoru, po připojení k PC se zobrazí jako sériový port (Communication port). Při prvním připojení je však ještě nutné nainstalovat driver, což je vlastně .inf (konfigurační) soubor (opět již dodaný Microchipem). V případě, že chceme změnit VID nebo PID v procesoru, nebo text popisující naše zařízení, který se zobrazí v ovládacích panelech, je nutné tento inf soubor upravit dle vlastních požadavků. VID a PID se upravuje v části __[DeviceList]__ a texty popisující zařízení se upravují v části String Definitions inf souboru. To, jak se mění VID a PID ve firmwaru je popsáno v kapitole výše.

Nejprve doporučují nainstalovat soubor CDC_RS232_Emulation.EXE. Pak najdeme v adresáři C:MCHPFSUSBfwCdcinfwin2k_winxp výše zmíněný .inf soubor. A dále je zde kompletní firmware (MPLAB projekt) s předdefinovanou třídou CDC. Jestliže tento projekt zkompilujeme a nahrajeme pomocí bootloaderu do PIC (viz. minulý díl), měl by se po provedení resetu procesoru zobrazit dialog vyžadující inf soubor a po zkonfigurování budeme mít v ovládacích panelech mezi porty náš nový port (pravděpodobně COM4, záleží na aktuální konfiguraci PC). Pak s ním na straně PC můžeme pracovat jako s jakýmkoliv jiným sériovým portem.

Vlastnosti CDC:

  • Celková velikost knihoven CDC po zkompilování cca 3 KB
  • Využití datové paměti cca 50 bytů (vyjma datových bufferů)
  • Maximální rychlost cca 80 KB/s
  • USB driver na straně PC zajišťuje tok dat (baud rate, parity bit, XON/XOFF and hardwarové řízení dat nemají vliv na komunikaci)
  • Nevyžaduje žádné další drivery. Konfigurační INF soubor je součástí firmwaru (platí pro Win XP, Win 2000)
  • Firmware využívá Windows driverů - usbser.sys a ccport.sys



Funkce firmwaru pro komunikaci:

  • putrsUSBUSART - pošle do PC null-terminated string z programové paměti
  • putsUSBUSART - pošle do PC null-terminated string z datové paměti
  • mUSBUSARTTxRom - pošle do PC string známé velikosti z programové paměti
  • mUSBUSARTTxRam - pošle do PC string známé velikosti z datové paměti
  • getsUSBUSART - převezme (přečte) string z USB USART bufferu procesoru
  • mUSBUSARTIsTxTrfReady - vrací hodnotu v závislosti na připravenosti vysílací jendnotky
  • mCDCGetRxLength - vrací hodnotu rovnou velikosti řetězce naposledy převzatého z USB USART bufferu procesoru



Detailní popis včetně příkladů je popsán v AN956 - viz link. Programováním sériového portu na straně PC se v tomto článku nebudu zabývat. To je vždy závislé na použité programové platformě a odkazy na toto téma lze jistě najít i v češtině bez problémů na internetu. Popíšu zde jednoduché příklady pro komunikaci - přijímání a vysílání znaků v procesoru.

Příklad odeslání znaků do PC:

void example_1(void){
  if(mUSBUSARTIsTxTrfReady()) putrsUSBUSART("Hello World.");
}//end example_1


Tato funkce odešle do PC řetězec “Hello World.”. Nejprve je potřebazjistit, jestli je pocesor schopný vysílat do PC. To nám umožňuje funkce mUSBUSARTIsTxTrfReady, která vrací hodnotu BOOL. Pozor Tato funkce je blokovací a měla by být použita tak, jak je uvedeno v příkladu výše. V žádném případě nepoužívejte while(!mUSBUSARTIsTxTrfReady()). To by mohlo za určitých podmínek vést k zablokování procesoru!

Příklad čtení znaků z USB USART bufferu - znaků přijatých z PC:

void example_2(void){
  if(getsUSBUSART(input_buffer, 20){
    // Do something
  }//end if
}//end example_2


Tato funkce kopíruje do pole input_buffer 20 znaků z USB USART bufferu. Maximální velikost přijatých znaků je rovna velikosti příslušného endpointu, což je zpravidla 64 bytů (konstanta CDC_BULK_OUT_EP_SIZE). Funkce vrací buď počet bytů kopírovaných do input_bufer nebo 0, když žádný znak nebyl v USB USART bufferu (žádný znak nebyl zkopírován).

Demo aplikace
Níže uvádím demo (použité na deske USB PICDEV popsané v minulém díle), které funguje tak, že přijme z PC znak. Jestliže je tento znak roven číslu 5, pak procesor pošle zpět do PC zprávu „Cislo 5 bylo prijato procesorem“ a rozsvítí diodu na pinu RD4. Jestliže má přijatý znak jakoukoliv jinou hodnotu než 5 (ASCII), pošle procesor zpět do PC řetězec „Cislo 5 nebylo prijato“ a zhasne diodu na pinu RD4.

K ukázce komunikace použiji program terminál z knihy „Měření, řízení a regulace pomocí PC“ od Burkharda Kainky. Doufám, že se na mě za to nebude zlobit.

Do funkce UserInit přidáme inicializaci portu pro RD4 :
 


Pro příjem znaků použijeme pole input_buffer, které je součástí CDC dema (soubor user.c). V souboru user.c - viz. popis firmwaru v první kapitole - upravíme funkci Exercise_Example následovně:
 



Jednoduchá funkce funguje následovně:

  • Načte se přijatý znak do input_buffer (v případě, že žádný znak nebyl přijat, funkce skončí)
  • Porovná se, jestli je přijatý znak roven 5
  • Jestliže ano, rozsvítí se dioda o odešle se řetězec 1 (po kompilaci je umístěn v ROM)
  • Jestliže ne, zhasne dioda o odešle se řetězec 2
  • Funkce skončí a vrátí řízení zpět do funkce main



Na straně PC pak vypadá komunikace následovně:
 



V textovém poli „Text senden“ jsem postupně zapisoval znaky. Po každém zapsaném znaku jsem v poli „Text empfangen“ dostal postupně řetězce (bylo/nebylo přijato číslo 5).

Kompletní demo projekt včetně programu RS232 Terminal je ke stažení v sekci odkazů.

A to je vlastně vše, co potřebujete vědět pro komunikaci po USB pomocí třídy CDC. Jak jsem sliboval na začátku, vše by mělo být zvládnutelné bez znalosti USB specifikací a dalších podrobností.

Na závěr bych chtěl říci, že původně jsem myslel, že napíšu ještě další díl, zabývající se vlastním typem komunikace bez použití CDC, tedy bez použití virtuálního sériového portu. Ovšem vzhledem k ohlasům na minulý díl již další díl pravděpodobně psát nebudu. Kdyby měl přesto někdo zájem o tento typ komunikace, ať se mi ozve a já mu poskytnu užitečné odkazy.

Důležité odkazy: