Příloha A – klávesnice + UART
Transkript
Příloha A – klávesnice + UART
ZÁPADOČESKÁ UNIVERZITA V PLZNI FAKULTA ELEKTROTECHNICKÁ KATEDRA ELEKTROENERGETIKY A EKOLOGIE DIPLOMOVÁ PRÁCE Softwarové vybavení kitu s procesorem LPC2148 2011 Bc. Tomáš Fried Anotace Cílem této diplomové práce je seznámit čtenáře s problematikou softwarového ovládání mikroprocesoru LPC2148 s jádrem ARM7 a vytvořit software pro vybrané periferie jako jsou GPIO, UART, SPI, PLL, časovač a systém přerušení. Dalším cílem je popis a oživení dodaného vývojového kitu nahrazující vývojový kit Keil MBC2130. Oživením vývojového kitu je myšleno vytvoření obslužného softwaru pro LED diody, maticovou klávesnici, alfanumerický a grafický displej. Poslední část je zaměřena na popis USB sběrnice, vytvoření aplikace pro mikroprocesor a vytvoření vizuálního rozhraní pro PC. Aplikace pro mikroprocesor umožňuje ovládání mikroprocesoru pomocí USB a je napsána v programovacím jazyce C. Vizuální rozhraní je napsané v programovacím jazyce C# a umožňuje ovládání periferií mikroprocesoru a přenos dat mezi mikroprocesorem a PC pomocí USB sběrnice. Klíčová slova Vývojový kit, mikroprocesor, LPC2148, ARM, UART, SPI, PLL, TIMER, alfanumerický LCD displej, grafický LCD displej, HD44780, USB, HID Annotation The purpose of this thesis is to familiarize the readers with the problem of software controlling microprocessor LPC2148 with the ARM7 core and make software for selected peripherals such as GPIO, UART, SPI, PLL, the timer and the interrupt system. Another aim is the description and liven up the recovery development kit, which is replacing the development kit Keil MBC2130. To live up the development kit means to create an operating software for the LED, matrix keypad, an alphanumeric and graphic display. The last part focuses on the description of the USB bus, develop the application for microprocessor and a visual interface for the PC. The Applications for the microprocessor allow to control the microprocessor via USB and is written in C programming language. The Visual interface is written in C # programming language and allows the control of the microprocessor peripherals, transfers data between it and PC via USB. Keywords Development kit, microprocessor, LPC2148, ARM, UART, SPI, PLL, TIMER, alphanumeric LCD display, graphic LCD display, HD44780, USB, HID PROHLÁŠENÍ Prohlašuji, že jsem tuto diplomovou práci vypracoval sám za pomoci vedoucí diplomové práce, literatury a dokumentačních materiálů, které mi byly poskytnuty. V Plzni dne ……2011 ......................................... Poděkování Děkuji paní Ing. Oldřišce Štemberové, vedoucí mojí diplomové práce, za poskytnutí rad, připomínek, literatury a také za to, že mi věnovala svůj čas. Obsah Použité zkratky a pojmy .............................................................................................. 1 1 Úvod..................................................................................................................... 2 2 Základní popis ...................................................................................................... 2 3 4 2.1. Architektura ARM .......................................................................................... 2 2.2. Vývojový kit ................................................................................................... 3 2.3. Procesor LPC2148 ........................................................................................ 4 2.4. Periferie ......................................................................................................... 4 2.4.1. GPIO ....................................................................................................... 4 2.4.2. UART ...................................................................................................... 5 2.4.3. SPI .......................................................................................................... 6 2.4.4. PLL ......................................................................................................... 7 2.4.5. Časovač .................................................................................................. 9 2.4.6. Přerušení .............................................................................................. 10 Popis oživení kitu ............................................................................................... 13 3.1. Práce s LED diodami ................................................................................... 13 3.2. Maticová klávesnice .................................................................................... 13 3.3. Alfanumerický displej ................................................................................... 15 3.4. Grafický displej ............................................................................................ 17 USB.................................................................................................................... 22 4.1. 5 USB obecně ................................................................................................ 22 4.1.1. Historie USB ......................................................................................... 22 4.1.2. Topologie sběrnice ................................................................................ 23 4.2. Typy datových přenosů ............................................................................... 24 4.3. Třídy USB zařízení ...................................................................................... 25 4.3.1. HID ........................................................................................................ 25 4.3.2. Mass storage ........................................................................................ 25 4.3.3. Printer ................................................................................................... 26 4.3.4. Audio device ......................................................................................... 27 4.3.5. Ostatní .................................................................................................. 28 LPC2148 a USB HID.......................................................................................... 28 5.1. Obecně ........................................................................................................ 28 5.2. Návrh aplikace využívající USB HID API ..................................................... 30 6 7 5.2.1. Vytvoření knihovny s API ...................................................................... 30 5.2.2. Vytvoření aplikace využívající USB HID API ......................................... 31 5.2.3. Provedené hardwarové a softwarové úpravy ........................................ 32 5.3. Obsluha USB HID API ................................................................................. 32 5.4. Popis programu ........................................................................................... 33 5.5. Připojení k PC a instalace ovladačů ............................................................ 35 Vizuální rozhraní do PC ..................................................................................... 36 6.1. Obecně ........................................................................................................ 36 6.2. Použité komponenty a knihovny .................................................................. 37 6.3. Funkce UsbLibrary ...................................................................................... 37 6.4. Funkce USBClass ....................................................................................... 38 6.5. Hlavní funkce vizuálního rozhraní................................................................ 39 6.5.1. Ovládání LED diod ................................................................................ 41 6.5.2. Ovládání tlačítek ................................................................................... 41 6.5.3. Ovládání LCD displeje .......................................................................... 42 Závěr .................................................................................................................. 44 Seznam použité literatury ......................................................................................... 45 Seznam příloh ............................................................................................................. I Příloha A – klávesnice + UART ................................................................................ I Příloha B – znaková sada HD44780 ...................................................................... IV Příloha C – alfanumerický displej + foto ................................................................. IV Příloha D – grafický displej + hardwarové úpravy ................................................. VII Příloha E – vizuální rozhraní + komunikace s vývoj. kitem ..................................... XI Příloha F – úpravy hardware ................................................................................ XIV Příloha G – obsah přiloženého CD ........................................................................ XV Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Použité zkratky a pojmy UART (Universal asynchronous receiver/transmitter) univerzální asynchronní sériová komunikace SPI (Serial peripheral interface) synchronní sériová komunikace PLL (Phase locked look) programovatelný fázový závěs TIMER časovač Interrupt přerušení LED (Light-emitting diode) luminiscenční dioda USB (Universal serial bus) univerzální sériová sběrnice hojně využívána u osobních počítačů PC (Personal computer) osobní počítač ARM architektura procesorů od firmy ARM Limited Ethernet souhrnný název pro počítačové sítě typu LAN RISC architektura mikroprocesorů s redukovanou instrukční sadou RS232 standard používající se jako komunikační rozhraní osobních počítačů a elektroniky (sériový port), umožňuje propojení dvou zařízení JTAG (Joint test action group) zařízení umožňující programování paměti a možnost krokování programu DMA (Direct memory access) přímý přístup hardwaru k paměti GPIO (General purpose input output) programovatelné vstupy a výstupy RXD (Receive data) přijatá data TXD (Transmit data) odeslaná data FIFO (First in, first out) zásobník typu první dovnitř, první ven Pclk (Peripheral device clock) frekvence taktování periférií Cclk (Core clock) frekvence taktování jádra VIC (Vectored interrupt controller) kontrolér vyhodnocující zdroj přerušení OS operační systém 1 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 1 Úvod V této diplomové práci se budu v úvodní části zabývat stručným popisem architektury ARM7, poté provedu stručný popis dodané vývojové desky a mikroprocesoru LPC2148 od firmy NXP. Dále budou podrobněji popsány softwarové principy ovládání periferií UART, SPI, PLL, TIMER a interruptový systém mikroprocesoru. Další část se bude zabývat oživením dodané vývojové desky. To obnáší napsání softwaru pro oživení LED diod, maticové klávesnice a poté 2 displeje. První displej bude alfanumerický 2x16 znaků a druhý bude grafický displej s rozlišením 128x64 bodů. Poté bude rozebrána USB komunikace, její principy, způsoby ovládání a vytvoření vzorového software pro obsluhu USB řadiče daného mikroprocesoru. V poslední části bude vytvořen program pro PC, který umožní obsluhu mikroprocesoru přes sběrnici USB a zobrazí stavy jednotlivých periferií. 2 Základní popis 2.1. Architektura ARM Technologie ARM se stala základem na světě nejpoužívanějšího 32 bitového mikroprocesoru. Dokazuje to více než 10 miliard prodaných kusů a podle [1] tak tvoří 75% trhu v této kategorii. Jeho největší výhody spočívají v jednoduchosti programování, nízké spotřebě a vynikajícím výkonu. ARM je otevřená technologie, což zajišťuje kompatibilitu s jinými obdobnými systémy. Mikroprocesory s jádrem ARM je možné používat jak v 16 bitovém módu (Thumb), tak ve 32 bitovém módu (ARM). Při použití 16 bitových instrukcí v Thumb módu lze ušetřit až 30% programové paměti s minimálním vlivem na výkon procesoru. V dnešní době jsou procesory optimalizovány pro všechny běžně užívané programovací jazyky (JavaTM, C/C++, assembler). 2 Softwarové vybavení kitu s procesorem LPC2148 Všechny mikroprocesory Bc. Tomáš Fried 2011 s jádrem ARM využívají Von Neumannovu technologii, což znamená, že data i instrukce se nacházejí v jednom adresním prostoru. Firma ARM je pouze výrobcem jádra. Ostatní přídavné periferie (Ethernet, UART, USB..), velikost programové a datové paměti už závisí na jednotlivých výrobcích mikroprocesorů. Jelikož je tedy ve všech mikroprocesorech ARM stejné jádro, znamená to, že mají mikroprocesory různých výrobců stejný instrukční soubor. Externí zařízení komunikují s jádrem po standardizované sběrnici, což znamená, že program psaný pro mikroprocesor jedné firmy bude pracovat stejně i s mikroprocesorem konkurenční firmy. Mezi výrobce mikroprocesorů s jádrem ARM patří například: Texas Instruments, Samsung, NXP a Broadcom. Jádro ARM7 je nejjednodušší používanou řadou 32 bitových RISC procesorů s jádrem ARM. Jeho hlavní výhodou je vysoký výkon s malou spotřebou a možností práce s nízkým napájecím napětím. Podporuje možnost přepnutí na 16 bitovou instrukční sadu Thumb. Standardně jsou vyráběny 0,13 μm technologií a dosahují výkonu až 130 MIPs. Tento typ jádra se používá v obrovském množství zařízení. Používají se například ve čtečkách paměťových karet, měřících přístrojích, autodiagnostických nástrojích, GPS, MP3 přehrávačích, v elektronických hračkách, jako USB kontroléry apod. ARM7 je podporován poměrně velkým množstvím vývojových nástrojů, ať už komerčních, tak volně šiřitelných. Výstupní kód je zpětně kompatibilní s jádry ARM9 a ARM11. 2.2. Vývojový kit Jedná se o vývojový kit osazený mikroprocesorem NXP LPC2148 nahrazující vývojový kit MBC2130 firmy Keil. Vývojový kit umožňuje komunikaci mikroprocesoru přes port USB, obsahuje dva konektory RS232 a konektor pro JTAG. Pro zobrazování informací lze využít 8 LED a konektory pro připojení alfanumerického nebo grafického displeje. Dále kit nabízí možnost připojení maticové klávesnice. 3 Softwarové vybavení kitu s procesorem LPC2148 2.3. Bc. Tomáš Fried 2011 Procesor LPC2148 Mikroprocesor LPC2148 od firmy NXP Semiconductors spadá do rodiny LPC2000 a je založen na 16 / 32 bitovém jádře ARM7TDMI-S. Další parametry níže. Vysoce výkonné 32 bitové RISC jádro: -ARM7TDMI-S 16bit / 32 bitové jádro s třístupňovou pipeline -max. 60MHz taktovací frekvence -THUMB optimalizace kódu ušetří až 30% místa s minimálním vlivem na výkon -rychlá odezva na zdroje přerušení LPC2148 poskytuje: 32kB RAM, 512kB rychlé paměti Flash (taktovací frekvence až 60MHz), USB 2.0 Full Speed s 8kB pamětí sdílenou přes DMA, A/D a D/A převodníky, čítače, časovače, RTC, SPI, SSP, I2C, UART, CAN a mnohem více. 2.4. Periferie 2.4.1. GPIO GPIO je označení pro General Purpose I/O, což znamená použití pinů pro vstupní nebo výstupní účely. K dispozici jsou dva různé režimy - pomalé GPIO a rychlé GPIO. Při využívání pinů tímto způsobem není nutné nastavovat registr PINSEL, jelikož je defaultně nulován. Pro přístup na pomalé (standardní) GPIO se využívají následující registry: IOPIN - určen ke čtení aktuálního stavu GPIO pinů (jen čtení). IODIR - řídící registr určující směr I/O - určuje, které piny budou vstupní a které výstupní (čtení/zápis). 4 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 IOSET – 32 bitový registr sloužící pro nastavení výstupů do log. 1. Zapsaná 1 do tohoto registru se projeví jako log. 1 na výstupu daného pinu. Pokud se zapíše 0 do tohoto registru, tak se nic nestane (čtení/nastavení). IOCLR - 32 bitový registr sloužící pro nastavení výstupů do log. 0. Zapsaná 1 do tohoto registru se projeví jako log. 0 na výstupu daného pinu. Pokud se zapíše 0 do tohoto registru, tak se nic nestane (nastavení). Ukázka zdrojového kódu pro GPIO: IODIR1= 0xFF0000; IOSET1= (1<<20)|(1<<21)|(1<<22); IOCLR1= 1<<20; if (IOPIN1 & 0x200000) { IOSET1 = 0xFF0000; } 2.4.2. // nastavení P1.16-P1.31 jako výstupní port // P1.20,P1.21 a P1.22 nastaveno na 1 // P1.20 nastaveno na 0 // je P1.21 v log. 1 ? // ano – nastav všechny výstupní na 1 UART UART je označení pro univerzální asynchronní komunikaci. Pro přepnutí z defaultně nastavených portů GPIO na UART je potřeba nastavit registr PINSEL. Přepnutí z GPIO na UART0 se provádí zapsáním 0x00000005 do registru PINSEL0 viz. [2]. Pro UART1 se zapisuje hodnota 0x00050000. Tím se docílí, že P0.0 a P0.1 (P0.8 a P0.9) se chovají jako TXD a RXD. Ukázka zdrojového kódu pro UART komunikaci: Inicializace UART0 se provede následujícím způsobem: PINSEL0 U0LCR U0DLL U0LCR = 0x00000005; = 0x00000083; = 0x00000061; = 0x00000003; /* zapnutí na P0.0 fci TXD0 a P0.1 na RXD0 */ /* 8 bitů délka slova, vypnuta parita, 1 stop bit */ /* 9600 Baud Rate při 15MHz VPB Clock */ /* Vypnutí DLAB – po nastavení přenosové rychlosti*/ Vyslání znaku na UART0: void uart_putc(char c){ while(!(U0LSR & 0x20)); U0THR = c; } // čeká, dokud není UART0 připraven na odesílání // odešle data na vysílací přídržný registr U0THR 5 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Přijetí znaku z UART0: int uart_getc(){ while (!(U0LSR & 0x01)); int tmp=U0RBR; } // čeká, dokud nebudou přijaté data připravena // vrátí hodnotu přijímacího bufferu Z funkce pro poslání znaku vyplývá funkce pro zápis řetězce znaků: void uart_puts (char *s){ while(*s) { uart_putc(*s++); } } 2.4.3. // ukazatel na řetězec znaků // odešle znak na UART0 a posune ukazatel SPI SPI je označení pro synchronní sériovou komunikaci. Rychlost hodinových pulzů může být až PCLK/8. SPI0 piny se zapínají dle [1] zapsáním hodnoty 0x5500 do registru PINSEL0. SPI1 piny se zapínají hodnotou 0xA8 do registru PINSEL1. Ukázka zdrojového kódu pro SPI komunikaci: Inicializace SPI0 se provádí následujícím způsobem: PINSEL0 = 0x5500; IODIR0 = 1<<7; IOSET0 = 1<<7; S0SPCCR = 0x0C; S0SPCR =0x00000020; //zapnutí funkce SPI na SCK0,MOSI0,MISO0,SSEL0 //nastavení CS jako výstupní pin // nastavení log 1 na CS // 1,25MHz při 15 Mhz Pclk // nastavení SPI Master Vyslání znaku na SPI0: void SPI_write(char c){ S0SPDR = c; while(!(S0SPSR & 0x80)){} //čeká, dokud není přenos hotový } 6 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Čtení znaku z SPI0: int SPI_read(){ int data; while (!(S0SPSR & 0x80)) ; //čeká na dokončení přenosu data = S0SPDR; return data; //vrátí přijatá data } 2.4.4. PLL PLL je označení pro programovatelný fázový závěs. Díky němu je možné znásobit frekvenci externího krystalu až na 60MHz, který lze použít pro taktování jádra a periferií. Výstupní frekvenci z PLL je možné dynamicky měnit a tím šetřit energii v klidových stavech. Pro nastavení PLL je potřeba vypočítat konstanty P a M. M = skutečný násobitel vychází ze vztahu (2.1). , kde (2.1) Cclk je požadovaná frekvence Ocs je frekvence oscilátoru P = programovatelný dělitel, vycházející ze vztahu (2.2), (2.2) kde Fcco je proudově řízený oscilátor, který je dán mezními frekvencemi proudového oscilátoru. Pro nastavení Cclk na 60Mhz se konstanta M při Ocs=12MHz vypočte dosazením do rovnice 1.1. Výsledná hodnota M je vyčíslena v rovnici (2.3). (2.3) Konstanta P se pro dané hodnoty vypočte dosazením do rovnice (2.4). Výsledná hodnota P může nabývat hodnot 1,2,4,8 nebo 16 a proudově řízený oscilátor Fcco musí být celé číslo. Řešením vztahu (2.4) vyjde, že Fcco musí být v rozmezí od 1,3 do 2,66 a musí být celé číslo. Výsledek je tedy jednoznačně číslo 2. 7 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 (2.4) Nastavení PLL se provádí dvěma způsoby. První a jednodušší možnost je nastavení konstant M a P do průvodce nastavení startup souboru ve vývojovém prostředí μVision. Nastavení PLL se poté provede po startu programu. Pokud je potřeba provést změnu nastavení PLL za běhu programu, je nutné použít druhý způsob nastavení. Ten se provádí za pomoci softwarové obsluhy PLL- viz příklad níže. Při softwarové obsluze PLL je nutné zapsat do registru PLLCFG konstanty P a M. Konstanty P a M se zapisují do registru ve tvaru P-1 a M-1. To zajišťuje nemožnost zapsání nulových hodnot. Poté se musí PLL povolit. Po nastavení PLL a spuštění je nutné zkontrolovat ve PLLSTATUS registru LOCK bit, který signalizuje, že je PLL pevně nastaven (uzamknut) na požadované frekvenci. Dále se provede zapnutí PLL a tím se nastaví PLL jako hlavní zdroj hodinových pulzů. Ukázka zdrojového kódu pro obsluhu PLL: PLLCFG = 0x00000024; // nastavení násobiče M a dělitele P pro získání 60MHz //M=5-1=4=00100 a P=2-1=1=01 - M + P = 0100100 = 0x24 PLLCON = 0x00000001; // povolení PLL PLLFEED = 0x000000AA; PLLFEED = 0x00000055; //update PLL registu, musí proběhnout po sobě while (!(PLLSTAT & 0x00000400)); // čeká, dokud Lock bit signalizuje uzamčení PLL na požadované frekvenci PLLCON = 0x00000003; // připojení k PLL PLLFEED = 0x000000AA; PLLFEED = 0x00000055; //update PLL registru, musí proběhnout po sobě Po nastavování PLL se většinou nastavuje i frekvence periferií Pclk. Nastavení Pclk se provádí pomocí VPB dělitele, který může mít hodnoty 1,2 nebo 4. Tedy když bude Pclk nastaveno na 60MHz a VPB dělitel se nastaví na 4, dostane se frekvence periferií 15MHz. U vývojového prostředí Keil μVision 4, je při vytvoření automatického startup souboru PLL aktivován. Cclk je nastaven na 60MHz a Pclk na 15MHz. Příkaz pro nastavení frekvence sběrnice periferií: 8 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 VPBDIV = 0x00000002; //nastavení frekvence Pclk na Cclk/2, tedy na 30.000MHz 2.4.5. Časovač LPC2148 obsahuje 2 časovače. Každý je založený na 32 bitovém čítači a 32 bitové děličce. Zdroj hodinových pulzů je z hodinových pulzů periferií, neboli z Pclk. Řídící registr časovače nám umožňuje pouze zapnout/vypnout časovač, nebo ho resetovat. Časovač lze použít ve funkci Match a Capture. Časovač ve funkci Match má 4 kanály pro nastavení shody. Do každého z nich je možné nastavit 32 bitové číslo, které dovoluje zachytit událost v případě shody s čítačem časovače. Odchycená událost může sloužit k resetu časovače, vypnutí časovače, vyvolání přerušení nebo změnu stavu odpovídajícího pinu (Match). Změna stavu odpovídajícího pinu může sloužit např. pro generování PWM. Capture funkce časovače umožňuje zachytit aktuální hodnotu čítače časovače, v případě změny hodnoty na pinu Capture. Příklad nastavení jednoduchého časovače ve funkci Match: T0PR = 0x00000000 ; //nastavení děličky na 0 - každý tick inkrementuje čítač časovače T0TCR = 0x00000002; //reset čítače a děličky T0MCR = 0x00000003; //při shodě vymaž čítač časovače a vyvolej přerušení T0MR0 = 0x1FFFFF; //nastavení časového intervalu časovače T0TCR = 0x00000001; //zapnutí časovače VICVectAddr0 = (unsigned)T0isr; //nastavení adresy pro ISR časovače VICVectCntl0 = 0x24; //bit 5 - povolení vektoru, bit 0:4 - kanál 4 pro timer VICIntEnable |= 0x00000010; //povolení přerušení Obsluha přerušení časovače: void Timer0isr (void) __irq { T0IR |= 0x00000001; VICVectAddr = 0x00000000; } // smaže match 0 interrupt flag // Prázdný zápis pro ukončení obsluhy přerušení 9 Softwarové vybavení kitu s procesorem LPC2148 2.4.6. Bc. Tomáš Fried 2011 Přerušení Pojem přerušení označuje odskok mikroprocesoru z právě vykonávané instrukce na definovanou jinou funkci. Volaná funkce nejčastěji obsluhuje zdroj, který přerušení vyvolal. Po vykonání obsluhy přerušení je řízení vráceno do místa, odkud bylo voláno a program pokračuje dále. Bez přerušení se neobejde žádná větší aplikace. Jádro ARM7 obsahuje dvě linky pro přerušení FIQ a IRQ viz. obr 2.1. V běžných aplikacích se používá standardní IRQ přerušení. Přerušení typu FIQ se používá tam, kde je potřeba velice rychle obsloužit krátkým kódem časově náročný proces. Jádro obsluhuje FIQ nejrychleji, jak je to jen možné. Aby jádro nemuselo zdlouhavě zjišťovat, od jakého zdroje IRQ přerušení nastalo, byl k jádru přidán VIC, který umožňuje velice rychle a efektivně zachytit zdroj přerušení z periferií. VIC je kontrolér vyhodnocující velice rychle zdroj přerušení a nezdržuje se tím samotný mikroprocesor. Každý zdroj přerušení je připojen na VIC s přiřazeným kanálem. Obr. 2.1 Kontrolér vektorového přerušení spojený s jádrem ARM7 [1] VIC nám umožňuje zachytit 3 druhy přerušení FIQ, Vektorový IRQ a Nevektorový IRQ. Rychlosti odezvy přerušení jsou znázorněny na obr. 2.2. Obr. 2.2 Rychlosti odezvy jednotlivých druhů přerušení [1] 10 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 FIQ přerušení Jakékoli přerušení může být nastaveno jako FIQ. Ideální je používat pouze jeden FIQ, ale v praxi je často potřeba více FIQ, což je zde také možné. Při použití více FIQ se obsluha přerušení zpomaluje a je potřeba zjišťovat, který zdroj přerušení vyvolal. Při opouštění obsluhy FIQ je nutné vymazat příznak přerušení (interrupt status flag). Pokud by se tak nestalo, tak by program stále čekal na vymazání tohoto příznaku. Mazání příznaku se provádí zapsáním log. 1 na příslušný registr. Ukázka zdrojového kódu pro obsluhu FIQ: Nastavení FIQ se provádí následujícím způsobem: PINSEL0 = 0xC0; VICIntSelect = 0x8000; VICIntEnable = 0x8000; while(1); // nastavení P0.14 na funkci EINT1 // nastavení EINT1 jako FIQ // povolení EINT1 // nekonečná smyčka Obsluha FIQ: __irq void FIQ_Handler (void) { //kód,který se má vykonat EXTINT = 0x00000002; //smazání flagu pro EINT1 } Vektorový IRQ VIC obsahuje 16 slotů pro vektorové adresování. Priorita obsluhy přerušení je dána číslem slotu, který se musí nastavit. Přiřazení nejnižšího čísla slotu zajišťuje nejvyšší prioritu obsluhy. Stejně jako u FIQ se musí zajistit, aby byl příznak přerušení vynulován. Bez toho opatření se obsluha přerušení nezavolá. Při opouštění obslužné rutiny přerušení se musí provést tzv. Dummy zápis do vektorového adresního registru. Dummy zápis signalizuje pro VIC konec přerušení a jedná se o zápis nulových hodnot. Princip vektorového přerušení spočívá v tom, že se nastaví různá priorita přerušení pro jednotlivé periferie. Každý zdroj přerušení je přímo adresován na VIC a umožňuje tak jednoduchou obsluhu přerušení ve vývojovém prostředí. 11 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Ukázka zdrojového kódu pro vektorové přerušení: Nastavení: PINSEL0 = 0xC0; // nastavení P0.14 na funkci EINT1 VICVectCntl5 = 0x00000027; //nastavení priority 5 a povolení IRQ slotu VICVectAddr5 = (unsigned)EINT_IRQ_HANDLER; //nastavení adresy do VIC slotu VICIntEnable = 0x8000; // povolení EINT1 Obsluha přerušení: void EINT_IRQ_HANDLER (void) __irq{ // kód,který se má vykonat EXTINT = 0x00000002; //smazání flagu pro EINT1 VICVectAddr = 0x00000000; //Dummy zápis pro ukončení obsluhy přerušení } Nevektorový IRQ Používá se, pokud je obsazeno na VIC 16 vektorových IRQ a minimálně jeden FIQ. Nevektorového přerušení se docílí tak, že se povolí přerušení, ale nenastaví se na FIQ, ani se nenastaví slot pro vektor. Při tomto přerušení pak program skáče na defaultní adresu přerušení, kde je nutné zjistit podle IRQ status registru, o jaký typ přerušení se jedná. Nevektorové přerušení má nejnižší prioritu obsluhy. Ukázka zdrojového kódu pro nevektorové přerušení: Nastavení: PINSEL0 = 0xC0; // nastavení P0.14 na funkci EINT1 VICDefVectAddr = (unsigned)NonVectoredIRQ; //adresa přerušení VICIntEnable = 0x8000; // povolení EINT1 Obsluha přerušení: void NonVectoredIRQ (void) __irq //obsluha všech nevektorových interruptů { if(VICIRQStatus&0x00008000) //ptáme se, jestli se jedná o EINT1 { // kód,který se má vykonat EXTINT = 0x00000002; //smazání flagu pro EINT1 } VICVectAddr = 0x00000000; } //Dummy zápis pro ukončení obsluhy přerušení 12 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 3 Popis oživení kitu 3.1. Práce s LED diodami Na dodaném vývojovém kitu je 8 LED diod připojených přes budič 74HCT244 k pinům P1.16 – P1.24. Přístup na GPIO byl podrobněji popsán v kapitole 2.4.1. Ukázka zdrojového kódu pro práci s LED diodami: Tento kód rozsvěcuje vždy jen jednu LED a posouvá se postupně až na poslední LED, poté začne od začátku. int delay; unsigned int led = 0x10000; //hodnota odpovídá LED na P1.16 IODIR1 = 0xFF0000; //nastavení P1.16 - P1.23 jako výstup while(1){ //nekonečná smyčka IOSET1 = led; //nastavení do 1 potřebný výstup IOCLR1 =~led; //nastavení do 0 všech ostatních výstupů led = led <<1; //bitový posun na další LED if(led&0x01000000) led = 0x00010000; //pokud odpovídá hodnota led P1.24, tak nastaví led na P1.16 for(delay=0;delay<20000;delay++){} //jednoduchá zpožďovací smyčka } 3.2. Maticová klávesnice Dodaná maticová klávesnice obsahuje 16 tlačítek zapojených do matice. Díky tomuto zapojení je pro obsluhu 16-ti tlačítek zapotřebí pouze 8 vodičů. Princip snímání kláves spočívá v trvalém udržování řádkových vodičů v log. 1 a postupné připojování log. 0 na sloupcové vodiče. Sloupec může být v log. 0 vždy pouze jeden. Díky tomu je možné stisk tlačítka v právě odbuzeném sloupci jednoduše zachytit na řádkových vodičích. Stisknuté tlačítko je indikováno log. 0 na příslušném řádku. Zapojení maticové klávesnice je znázorněno na obrázku č. 3.1. Více podrobností o maticových klávesnicích je v [3]. 13 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obr. 3.1 Zapojení maticové klávesnice [3]. Při oživování klávesnice bylo zapotřebí připojení rezistorů na řádkové vodiče. Tyto rezistory nejsou implementovány přímo na vývojovém kitu, takže bylo zapotřebí je přidělat mezi konektor pro klávesnici a samotnou klávesnici. Hodnota rezistorů je 4K7 [Ω] a jsou připojeny na 3,3V. Pro obsluhu tlačítek bylo využito časovače. Časovač kontroluje v zadaném intervalu aktuální stav tlačítek pomocí funkce getButton, která vrací hodnotu odpovídající zmáčknutému tlačítku. Funkce getButton postupně připojuje na sloupcové vodiče log. 0 a zjišťuje, zda došlo ke stisku tlačítka pomocí funkce getPos, která vrací pozici zmáčknutého tlačítka. Pro ochranu nechtěného vyhodnocení dvojitého zmáčknutí je pro každé tlačítko vyhrazen časový interval odpovídající hodnotě 2x interval časovače. Tato metoda ošetřuje i zakmitávání kontaktů. Ukázka zdrojového kódu pro obsluhu klávesnice: Funkce getPos zjišťuje, které z tlačítek je právě zmáčknuto. unsigned char getPos(void){ //zjišťování pozice tlačítka 1-4 pos = 0; if(!(IOPIN0&rada1)){ pos =1; } if(!(IOPIN0&rada2)){ pos =2; } Stejným způsobem je nutné se dotazovat na 3. a 4. řadu. Návratová hodnota této funkce je pos, která odpovídá 1. až 4. tlačítku v daném sloupci. 14 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Funkce getButton vrací přímo hodnotu odpovídající zmáčknutému tlačítku. Například třetímu řádku druhého sloupce odpovídá hodnota 32. Spočívá v postupném nulování všech sloupců a vyhodnocování příslušného řádku. unsigned char getButton(void){ tmp=0; IOSET0 = sloupec_maska; IOCLR0 = sloupec1; tmp = getPos(); if(tmp!=0){ tmp = tmp+10; } //zjišťování sloupce if(tmp==0){ IOSET0 = sloupec_maska; IOCLR0 = sloupec2; tmp = getPos(); if(tmp!=0){ tmp = tmp+20; } } //pokud nebylo zmáčknuto v prvním sloupci,ptám se dále //zapnutí všech sloupců //vypnutí prvního sloupce //zjištění pozice tlačítka //zapíše číslo 1 jako sloupec 1 + pozice tlačítka //vypnutí druhého sloupce //zapsání čísla sloupce + pozice tlačítka Stejným způsobem je nutné se ptát na 3. a 4. sloupec. Tato funkce poté vrací hodnotu tmp odpovídající příslušnému tlačítku. Kompletní zdrojový kód, který odesílá stisknuté klávesy na UART, je k nalezení v příloze A. 3.3. Alfanumerický displej Dodaný alfanumerický LCM16021AWSL je displej se 2x16 znaky s integrovaným řadičem HD44780. Tento řadič je velice hojně využíván a princip řízení je detailně popsán např. v datasheetu k řadiči [4] nebo [5]. Displej lze zapojit ve 4 bitovém nebo 8 bitovém módu. Znaková sada displeje je zobrazena v příloze B. Základní znakovou sadu lze rozšířit až o 8 vlastních znaků. Pro komunikaci s displejem jsem použil 8 bitový mód, jelikož jsem kladl důraz na rychlost displeje a nebyl jsem omezen počtem vodičů. Čtyřbitový mód bych použil hlavně v případě nedostatku volných vodičů, nebo pokud bych nekladl důraz na rychlost displeje. Oživení displeje nevyžadovalo žádné dodatečné úpravy hardwaru. 15 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Ukázka zdrojového kódu pro alfanumerický LCD displej: Inicializace displeje se provádí pomocí funkce: void init_lcd( void ){ LCD_DIR |= ( LCDEN | LCDRS | LCDRW | LCD_DATA_MASK ); // nastavení datových a řídících pinů na výstupy LCD_CLR |= ( LCDEN | LCDRS | LCDRW | LCD_DATA_MASK); // nulování datových a řídících pinů lcd_cmd_write(INIT); //inicializace: 8bit mód, dvouřádkový, font 5x8 lcd_clear(); //smazání displeje lcd_cmd_write(CUR0); //nastaví kurzor na začátek lcd_cmd_write(USR1); //zapnutí displeje, kurzoru a blikání lcd_putstring(0," Vyvojovy Kit"); //ukázka výpisu řetězce lcd_putstring(1," s LPC2148"); } Při zápisu na displej je doporučené kontrolovat stav „Busy“ bitu, který signalizuje zaneprázdněnost řadiče displeje. Funkce, která čeká, dokud není displej připraven je: void lcd_wait( void ) { LCD_CLR |= LCDRS; LCD_SET |= LCDRW | LCDEN; while(IOPIN0 & LCD_BUSY_FLAG); LCD_CLR |= LCDEN | LCDRW; delay(100);} //RS na 0 //RW a E na 1 //čeká, dokud displej nebude zaneprázdněn //RW a E na 0 Zápis příkazu na displej se provádí nastavením E na log.1, poté se zapíše instrukce na datovou sběrnici, generuje se časová prodleva a vynuluje se E. Funkce pro zápis příkazu tedy vypadá takto: void lcd_cmd_write (unsigned char command){ unsigned int data=0; LCD_SET = LCDEN; LCD_CLR = LCDRS; LCD_CLR = LCD_DATA_MASK; data=(command<<16); LCD_SET = data; delay(10000); LCD_CLR = LCDEN; } //nastav E na 1 //nastav RS na 0 //vynuluj datové piny //data přesuň na pozici datových pinů //nastav data na datovou sběrnici //nuluj E Funkce pro zápis dat na datovou sběrnici je funkčně stejná jako zápis příkazu, liší se jen v nastavení RS. Zápis dat se provádí následujícím způsobem: 16 Softwarové vybavení kitu s procesorem LPC2148 void lcd_data_write(unsigned char data) { unsigned int data_tmp=0; data_tmp=(data<<16); LCD_SET |= LCDEN|LCDRS; LCD_CLR = LCD_DATA_MASK; LCD_SET = data_tmp; LCD_CLR |= LCDEN|LCDRS; lcd_wait();} Bc. Tomáš Fried 2011 //posun dat na pozici datové sběrnice //nastavení E a RS na 1 //nulování datové sběrnice //nastavení dat na datovou sběrnici //nulování E a RS //čeká, dokud nebude lcd zaneprázdněno Zápis řetězce na displej se provádí pomocí funkce lcd_putchar, která vypisuje znak. void lcd_putstring( unsigned char line, char *string ){ unsigned char len = LINE_LENGTH; //maximální počet znaků na řádku lcd_gotoxy( line, 0 ); //nastaví na zvolenou řádku na pozici 0 while(*string != '\0' && len--) //dokud nebude konec řádku nebo max počet znaků na řádku { lcd_putchar( *string ); //zapíše znak, na který právě ukazuje pointer string++; } //posune na další znak } Kompletní zdrojový kód a fotografie oživeného displeje je k nalezení v příloze C. 3.4. Grafický displej Dodaný grafický displej RAYSTAR RG12864B je displej s rozlišením 128x64 bodů. Umožňuje jednotlivé body vysvítit v šedé a bílé barvě. Displej obsahuje 2 řadiče NT7108. Tento řadič je plně kompatibilní se známějším řadičem Samsung KS0108 a umožňuje vysvícení bodů zapsaných do paměti řadiče. Tento řadič neobsahuje znakovou sadu a pro vypsání textu na displej je zapotřebí ji vytvořit. Pro obsluhu displeje s rozlišením 128x64 bodů je zapotřebí dvou řadičů. Každý z nich řídí polovinu displeje o rozlišení 64x64 bodů. Každá polovina je rozdělena na 8 stránek o 64 bajtech viz obr. 3.2. 17 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obr. 3.2 Rozložení paměti displeje [6] Pro zobrazení dat v první polovině displeje je zapotřebí požadovaná data uložit do paměti prvního řadiče, pro zápis na druhou polovinu se používá druhý řadič. Volba řadiče se provádí pomocí pinů CS1 a CS2. Vývojový kit obsahuje přímo konektor pro grafický displej, jenže není vhodně navržen. Pro správnou funkci displeje a možnosti regulace kontrastu je zapotřebí mít zapojen potenciometr 10-20KΩ z pinu Vee (výstup záporného napětí z displeje) na pin V0 (nastavení kontrastu). Na vývojovém kitu je potenciometr 100K na kladné napětí (vhodné pro alfanumerický displej), takže bylo zapotřebí připájet přídavný potenciometr přímo na displej. Další úpravu bylo nutné provést na pinu CS2, který je fyzicky připojen na pin P0.26 mikroprocesoru. Tento pin je u mikroprocesoru LPC2148 rezervován pro funkci USB jakožto D+. Problém jsem vyřešil vyvedením vodiče z pinu CS2 displeje na pin P0.15 mikroprocesoru. Stejný problém je i u pinu RST displeje, který je připojen na pin P0.27, který je rezervován pro funkci USB jakožto D-, ale pro požadovaný účel resetu zde může zůstat zapojen. Oživený grafický displej s vypsáním textu, vykreslením obrázku a potřebné hardwarové úpravy jsou vidět na fotografiích v příloze D. Ukázka zdrojového kódu pro grafický displej: Inicializace displeje se provádí funkcí: void glcd_init(void){ //inicializace displeje glcd_wait(); //čeká, než bude displej připraven po zapnutí GLCD_DIR |= ( GLCD_CONTROL_MASK | GLCD_DATA_MASK ); 18 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 // nastavení datových a řídících pinů na výstupy GLCD_CLR |= ( GLCD_CONTROL_MASK | GLCD_DATA_MASK ); //vymazání datových a řídících pinů GLCD_SET = GLCD_RST; //reset na 1 glcd_write_com(GLCD_ON,CHIP1); //zapnutí chipu1 glcd_write_com(GLCD_ON,CHIP2); //zapnutí chipu2 glcd_wait(); //čeká, než bude displej připraven glcd_fill(WHITE); //vyplnění displeje bílou barvou } Zápis příkazu na displej se provádí pro každý řadič zvlášť a funkce je volána s parametrem voleného chipu. Po aktivaci požadovaného chipu se dají piny RS a RW do log.0, poté se provede zápis dat na sběrnici a provede se pulz na EN. Pulz na EN by neměl být kratší než 450nS. Pro zvýšení spolehlivosti funkce displeje je vložena funkce glcd_wait(), která zjišťuje stav „Busy“ bitu displeje a čeká, dokud není displej připraven. void glcd_write_com(char cmd,char chip){ //zápis příkazu unsigned int tmpcmd = 0; //pomocná proměnná if(chip ==0x01){ //výběr chipu GLCD_CLR |=GLCD_CS2; GLCD_SET |=GLCD_CS1; } if(chip ==0x02){ GLCD_CLR |=GLCD_CS1; GLCD_SET |=GLCD_CS2; } GLCD_CLR |=GLCD_RS|GLCD_RW; //RS a RW na 0 GLCD_DIR |= GLCD_DATA_MASK ; //nastavení datových pinů na výstupy tmpcmd = (cmd<<16); //posun dat na správnou pozici GLCD_SET = tmpcmd; //zápis dat glcd_pulse_EN(); //pulz na EN GLCD_CLR |=GLCD_DATA_MASK|GLCD_CS1|GLCD_CS2; //data a výběr chipu na 0 glcd_wait();} //čeká, než bude displej připraven Funkce pro zápis dat glcd_write_data je totožná s funkcí pro zápis příkazu glcd_write_com, rozdíl je pouze v nutnosti nastavení RS na log.1. Nastavení kurzoru na požadovanou pozici se provádí zapsáním souřadnice x na potřebný řadič a poté zapsáním stránky, tj. y souřadnice. Zápis y souřadnice se 19 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 provádí na oba řadiče, aby se zamezilo zápisu dat u každého řadiče na rozdílné řádky. Funkce pro nastavení polohy kurzoru vypadá takto: void glcd_goto_xy(int x,int y){ //nastavení kurzoru na danou pozici char actual_chip = CHIP1; //defaultní chip=chip1 char cmd; if(x > 127) x = 0; //kontrola platnosti rozsahu x a y souřadnice if(y > 63) y = 0; if(x >= 64) { //pokud je x souřadnice větší než 64, tak se zvolí zápis na chip2 x -= 64; actual_chip = CHIP2; } cmd = GLCD_SET_ADD | x; //výpočet požadované X souřadnice glcd_write_com(cmd, actual_chip); //nastavení x hodnoty na aktivní chip cmd = GLCD_SET_PAGE | (y/8); //nastavení y souřadnice stránky na oba chipy glcd_write_com(cmd, CHIP1); glcd_write_com(cmd, CHIP2); } Pro smazání celého displeje a nastavení do jedné barvy je použita funkce: void glcd_fill(char color){ //vyplnění celého displeje int i,j; //barva: černá=0xFF, bílá=0x00 for(j=0;j<8;j++){ glcd_goto_xy(0,j*8); //přesun kurzoru na nultou pozici x a postupné projetí všech stránek y for(i=0;i<64;i++){ glcd_write_data(color,i); //zápis data na první chip glcd_write_data(color,i+64); //zápis data na druhý chip } }} Vykreslení obrázku o velikosti 128x64 bodů se provádí následující funkcí: void glcd_drawImage(const unsigned char bmp[1024]){ //vykreslení obrázku 128x64 int x,y,z; y=x=z=0; while(y<64){ //dělej, dokud se nezaplní všech 8 stránek glcd_goto_xy(0,y); //nastav kurzor na stránku y a chip na chip1 for(x=0;x<64;x++){ //zápis 64 dat na danou stránku chipu1 glcd_write_data(bmp[z],x); z++; } glcd_goto_xy(64,y); //nastav kurzor na stránku y a chip na chip2 20 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 for(x=64;x<128;x++){ //zápis 64 dat na danou stránku chipu2 glcd_write_data(bmp[z],x); z++; } y+=8; //přičtení další stránky } } Pro vytvoření obrázku na displej jsem použil program Mikroelektronika mikroC [7], který obsahuje GLCD Bitmap editor. Funkce vypsání znaku na displej nejprve zjistí hodnotu požadovaného znaku, a poté ve znakové sadě vyhledá požadovaný znak a ten vypíše. Znaková sada Font8x8 začíná na ASCII znaku č.32. Každý znak tohoto fontu je složen z 8x8 bodů. Znakovou sadu je možné vytvořit např. pomocí [7], online [8] , nebo [9]. Funkce pro výpis znaku z definované znakové sady na požadovanou pozici aktuální stránky vypadá následovně: void glcd_write_char(int c,int pos) //vypsání znaku na displej { int index = (c-32)*8; //dekadická hodnota znaku z ASCII tabulky,začátek na poz.32 int x; for(x=0;x<8;x++){ //každý znak má 8 bajtů glcd_write_data(Font8x8[index],pos); //zápis daného znaku ze znakové sady index++; pos++; } } Výpis řetězce využívá předchozí funkci glcd_write_char, navíc nastavuje počáteční polohu, odkud se řetězec začne vypisovat. void glcd_putstring( int x,int y, char *string ) //zápis řetězce na displej { int pos = x; unsigned char len = 128/8; //maximální počet znaků na řádku glcd_goto_xy(64,y*8); //nastavení chipu2 na první x pozici glcd_goto_xy(x,y*8); //nastavení chipu1 na pozici x while(*string != '\0' && len--) //dokud nebude konec řádku nebo max počet znaků na řádku { glcd_write_char(*string,pos); //zápis daného znaku 21 Softwarové vybavení kitu s procesorem LPC2148 string++; pos+=8; Bc. Tomáš Fried 2011 //posune na další znak } } Kompletní zdrojový kód a fotografie oživeného displeje je k nalezení v příloze D. 4 USB 4.1. USB obecně Označení USB je Universal Serial Bus, tedy v českém překladu univerzální sériová sběrnice. Tato sběrnice v dnešní době nahrazuje takřka většinu dříve používaných způsobů připojení k PC (RS232,paralelní port, PS/2, apod.). USB se masově rozšířilo kvůli vlastnostem, které pro uživatele znamenaly jednoduché použití a pro výrobce levnou a rychlou implementaci do zařízení. Mezi tyto vlastnosti patří především možnost připojení zařízení bez nutnosti vypnutí PC i zařízení, možnost napájení zařízení přímo ze sběrnice, možnost připojení více zařízení na jednu sběrnici a v neposlední řadě i samotná rychlost sběrnice. USB konektor je dnes k nalezení v každém osobním počítači. Do průmyslových systémů se ale kvůli některým negativním vlastnostem nedostala. Patří mezi ně např. nemožnost galvanického oddělení, omezení maximální vzdálenosti zařízení od počítače a topologie sběrnice. 4.1.1. Historie USB Sběrnice USB vznikla jako reakce na potřebu zavedení jednoduchého rozhraní, které je rychlé, nenáročné z hlediska uživatele a kde lze dosáhnout snadné realizace připojení většího počtu zařízení. Roku 1996 byl zveřejněn standard USB 1.0. V této době nebylo USB rozhraní podporováno operačními systémy a stávalo se, že některá zařízení připojená k jedné sběrnici společně nepracovala správně. V roce 1998 nahradil původní verzi USB 1.0 nový mnohem propracovanější standard USB 1.1. Ten byl již podporován operačními systémy a díky tomu se začal 22 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 rozšiřovat počet periferií připojovaných k USB. S verzí USB 1.1 vznikly také přenosné USB Flash disky. V této verzi byly definovány dva typy rozhraní s různou přenosovou rychlostí a typem použitého kabelu. Prvním typem jsou zařízení s nízkou rychlostí komunikace a menším množstvím přenášených dat označovaná jako Low Speed (dále jen LS). USB 1.1 LS dosahuje přenosové rychlosti 1,5 Mbit/s a lze použít dvoudrát bez stínění do délky 3m. Zařízení tohoto typu jsou levnější na výrobu a patří mezi ně např. klávesnice, počítačové myši a joysticky. Druhým typem jsou plnohodnotná zařízení označovaná jako Full Speed (dále jen FS). USB 1.1 FS dosahuje přenosové rychlosti do 12 Mbit/s. Tato zařízení jsou určena pro přenos dat, jako je kompresované video, digitální zvuk apod. Používá se kroucený dvoudrát se stíněním a jeho maximální délka je okolo 5 m. Kvůli stále rostoucím požadavkům na objem přenášených dat byla v roce 2000 zveřejněna verze USB 2.0, která rozšiřuje standard o vysokorychlostní zařízení High Speed (dále jen HS). Přenosová rychlost HS je do 480 Mbit/s. Byly přidány další 2 vodiče pro možnost napájení zařízení (VBUS a GND). V roce 2008 byla zveřejněna zatím poslední verze USB 3.0 označovaná jako Super Speed. Ta umožňuje přenosové rychlosti až do 5 Gbit/s. Oproti verzi USB 2.0 přibyly další 4 vodiče, dohromady má tedy 8 vodičů. Zařízení s USB 2.0 je plně kompatibilní s USB 3.0 a lze jej zapojit do konektoru s USB 3.0. Opačně ale zařízení kompatibilní nejsou a nové zařízení s USB 3.0 konektorem nelze zapojit do konektoru s USB 2.0. 4.1.2. Topologie sběrnice Topologie sběrnice má vrstvenou hvězdicovou strukturu, jak je zobrazeno na obr. 4.1. Sběrnice obsahuje jedno řídící zařízení zvané kořenový rozbočovač (Root hub). Ke kořenovému rozbočovači jsou připojeny další rozbočovače nebo koncové zařízení. Střed každé hvězdice je tvořen rozbočovačem (dále jen hub). Specifikace USB 2.0[12] povoluje maximálně sedm úrovní včetně kořenového hubu. Počet úrovní vychází z maximální dovolené hodnoty pro zpoždění signálu pro jednotlivé úseky sběrnice a maximální dobou odezvy zařízení k hostitelskému počítači. Každý hub musí po připojení zařízení automaticky rozpoznat, zda se jedná o Low Speed, Full Speed, nebo High Speed režim USB. Hub rozpozná typ zařízení podle toho, zda je datová linka D+ nebo D- vyzdvižena. V případě vyzdvižení linky D- se jedná o Low 23 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Speed zařízení, v případě D+ se jedná o Full Speed zařízení. Rozpoznání mezi Full Speed a High Speed se řeší softwarově. Obr. 4.1 Topologie sběrnice [10] 4.2. Typy datových přenosů Řídící přenosy (Control Transfers) – Jsou používány pro konfiguraci zařízení po jeho připojení. Mohou být použity k dalším speciálním účelům, jako např. řízení dalších komunikačních kanálů a koncových bodů. Izochronní přenosy (Isochronous Data Transfers) – Tento typ přenosu zabírá předem domluvené množství přenosového pásma a má předem smluvené zpoždění. Používá se pro přenos souvislých dat, která je zapotřebí přenést a zpracovat v reálném čase. Typickým příkladem může být přenos hlasu, kdy zpoždění není možné. Chyby se při tomto typu přenosu neopravují. Nárazové přenosy (Bulk Data Transfers) – Nárazové přenosy většinou přenášejí velké množství dat a požadavky na přenos nejsou pravidelné. Přenos dat vyžaduje detekci chyb, ale není časově kritický. Využívá se maximální možná volná kapacita sběrnice. Tento druh přenosu má tedy nízkou prioritu. 24 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Typickým příkladem může být přenos dat do tiskárny nebo ze scanneru. Přerušovací přenosy (Interrupt Data Transfers) - Systém se periodicky dotazuje zařízení. Předem je dána délka trvání přenosu. Detailněji jsou typy datových přenosů popsány v [11] a [12]. 4.3. Třídy USB zařízení Zařízení, která sdílejí mnoho atributů, nebo vyžadují podobné služby, jsou seskupena do jednotlivých tříd. Jednotlivé třídy definují, jakým způsobem budou data přenášena. Třídy usnadňují vývoj ovladačů zařízení a firmware ve standardizované formě. Operační systém Windows a mnohé jiné operační systémy již defaultně obsahují ovladače pro běžné třídy USB. Pokud je třída daného zařízení podporována operačním systémem, nemusí být požadován ovladač pro instalaci. Příkladem může být třída HID. 4.3.1. HID HID (Human Interface Device) je jednou z nejvíce podporovaných tříd operačními systémy. Tato třída využívá přerušovací přenosy. Druh tohoto přenosu je využíván takřka u všech polohovacích zařízení a klávesnic. Díky využití HID třídy není zapotřebí na hostitelské ani na straně zařízení vyvíjet vlastní složitý ovladač pro dané zařízení. 4.3.2. Mass storage Jedná se o třídu pro komunikaci s externím zařízením sloužícím pro ukládání dat. Nejčastěji se jedná o pevné disky, USB Flash disky, paměťové karty, MP3 přehrávače a mobilní telefony. Dalším typem podporovaných zařízení jsou např.: CD/DVD mechaniky nebo FDD mechaniky. Tato třída využívá nejčastěji nárazové přenosy, kde je zapotřebí přenést velké množství dat s nižší prioritou. Může ale také využívat kombinaci řídících, přerušovacích a nárazových přenosů. Třída USB Mass storage obsahuje několik podtříd viz.tab.4.1. Deskriptor pro USB Mass storage obsahuje proměnnou bInterfaceSubClass, kterou je zapotřebí nastavit na hodnotu viz.tab.4.1. Tato hodnota nespecifikuje daný typ zařízení, ale definuje příkazy pro přenos dat. Další hodnota, kterou je zapotřebí nastavit, je bInterfaceProtocol. Tato 25 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 hodnota specifikuje, jaké typy přenosů bude zařízení používat. Některá zařízení potřebují nastavit ještě classSpecificDescriptors. Detailní rozbor dané problematiky by byl nad rámec této práce a je k nalezení v [13]. Podtřída Specifikace Popis typicky RBC 01h Flash disky MMC-5 02h (ATAPI) externí disky 03h QIC-157 zastaralý - nepoužívá se 04h UFI specifikuje připojení FFD do USB 05h SFF-8070i zastaralý - nepoužívá se 06h SCSI připojení SCSI 07h LSD FS před připojením na SCSI 08h IEEE 1667 zabezpečené připojení 09h Rezervovány FEh Tab. 4.1 Podtřídy USB Mass Storage 4.3.3. Printer Třída Printer je používána zejména tiskárnami. Tiskárny využívají pro přenos dat především nárazové přenosy. Tisk stránky je zobrazen na obr. 4.2. Tiskárny používají dva různé typy příkazů. Jedním je přenos dat a druhým je ovládání USB nebo tiskárny. Tisk dat na tiskárnu spočívá v doručení dat na Bulk Out koncový bod. Odeslaná data mohou mít formu PostScript, HP PCL, nebo nějaký jiný PDL (Page Definition Language). Tiskárna poté může pravidelně odpovídat na Bulk In koncovém bodě a signalizovat tak svůj stav. Tiskárny podporují tři různé způsoby připojení. Jednosměrné, obousměrné a IEEE 1284.4 rozhraní. 26 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obr. 4.2 Přenos mezi hostem a zařízením při tisku stránky Jednosměrné připojení podporuje pouze odesílání dat do tiskárny přes Bulk Out koncový bod. Data o stavu zařízení jsou získávána z defaultní roury příkazem GET_PORT_STATUS. Obousměrné připojení podporuje odesílání dat do tiskárny přes Bulk Out koncový bod a příjem stavových a ostatních informací přes Bulk In koncový bod. Připojení přes IEEE 1284.4 je plně kompatibilní s obousměrným připojením, navíc budou data předávána pomocí protokolu IEEE 1284.4. Tento typ čeká na finálové schválení [14]. 4.3.4. Audio device Třída Audio obsahuje veškeré funkce, které mohou spolupracovat s USB kompatibilními audio datovými toky. Do této třídy patří funkce, které zajišťují: · Převod mezi analogovým a digitálním audio signálem · Převod mezi USB kompatibilním audio tokem do jiného USB kompatibilního audio toku · Funkce analogového audia ovládané přes USB 27 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Třída Audio je dále rozdělena do tří podtříd: · AudioControl (AC) – ovládání a konfigurace audio zařízení · AudioStreaming (AS) – přenos audio toku z nebo do zařízení · MIDIStreaming (MS) – přenos MIDI toku z nebo do zařízení Každé audio zařízení používá jedno AC rozhraní a může mít několik AS a MS rozhraní. Veškeré audio operace využívají izochronní přenosy. 4.3.5. Ostatní Mezi další specifikované třídy podle [14] patří například: - Imaging – pro přenos dat ze scanneru do PC - Video – pro přenos dat z video zařízení - Wireless Controller – pro bezdrátové zařízení - Personal Healthcare – pro lékařskou techniku 5 LPC2148 a USB HID 5.1. Obecně Při vytváření aplikace do LPC2148 s využitím HID API (Application Programming Interface) není zapotřebí kompletní znalosti USB komunikace. V této práci se zabývám pouze nezbytnými informacemi pro vývojáře využívající hotové API. Detailní popis USB komunikace je nad rámec této práce a nevešel by se ani do samostatné diplomové práce. Detailní popis je k nalezení např. v [12]. 28 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obr. 5.1 Příklad využití API v softwaru Princip využití HID API je zobrazen na obr. 5.1. Samotné API zprostředkovává kompletně USB komunikaci a vývojář jej obsluhuje pouze zvnějšku. K dispozici jsou například metody jako USB_Init(),USB_Connect() apod. Po připojení USB zařízení k hostitelskému PC nastává proces enumerace. Při enumeraci je nejprve hostitel informován od rozbočovače, ke kterému je zařízení připojeno, o změně stavu na portu. Hostitel poté počká určitou dobu na ustálení napájecího napětí a vyšle signál reset. Připojené zařízení se dostane do stavu obecného připojení a hostitel je schopen komunikovat se zařízením na adrese 0 pomocí řídící brány 0. Hostitel poté zjistí informace o připojeném zařízení přečtením deskriptoru a přidělí zařízení unikátní adresu v rámci sběrnice. Zařízení se tak dostane do stavu, kdy je adresovatelné a hostitel s ním komunikuje pouze na přidělené adrese. Dále hostitel přečte všechny konfigurace zařízení a zařízení přejde do zkonfigurovaného stavu. V tomto stavu může zařízení využívat více komunikačních bran najednou. Po procesu enumerace začne operační systém v hostitelském zařízení vyhledávat ovladače pro připojené zařízení. Ovladače zvolí na základě VendorID (identifikátor výrobce) a ProductID (identifikátor produktu), dále jen VID a PID. VID označuje unikátní číslo dodavatele zařízení a při vývoji vlastního zařízení je nutné požádat USB organizaci o přidělení unikátního VID za poplatek. Poplatek za VID se 29 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 pohybuje okolo 1500$. PID je identifikační číslo produktu daného dodavatele zařízení. K jednomu VID je možné přiřadit několik PID. 5.2. Návrh aplikace využívající USB HID API Při oživování USB komunikace na procesoru LPC2148 jsem použil USB HID API od firmy NXP [15], dále jen API. API vychází z originálu od firmy Keil. Použité API je poskytováno bez záruky funkčnosti a je možné ho bezplatně šířit dále. Při vytváření vlastní aplikace je nejprve nutné vytvořit samostatnou knihovnu s API a tu poté vložit do vlastního projektu. 5.2.1. Vytvoření knihovny s API Vytvoření knihovny s API pro zařízení typu HID jsem provedl ve vývojovém prostředí μVision 4 od firmy Keil. Nejprve je nutné stáhnout API ze stránek NXP [15]. Ve složce HID Firmware_Library je umístěn projekt LPC2148 Firmware, který obsahuje požadované API. Hlavním konfiguračním souborem celého API je usbcfg.h, ve kterém je možné nastavit veškeré vlastnosti spojené s USB. Pro základní funkčnost API je nutné v souboru usbcfg.h nastavit počet přijímaných (Report Bytes In) a odesílaných bajtů (Report Bytes Out) směrem k PC. Dalším důležitým parametrem je interval přijímání a odesílání bajtů. Interval lze nastavit odlišný pro přijímání a odesílání bajtů a nastavuje se v rozmezí od 1-32 mS v mocninách čísla 2. Dále je zde možné nastavit například VID a PID zařízení. Soubor usbcfg.h je možné upravovat v textovém režimu, nebo v Configuration Wizardu. Pro komunikaci s vizuálním rozhraním jsem v usbcfg.h nastavil 18 vstupních a 18 výstupních bajtů. Interval jsem nastavil pro vstupní i výstupní data stejný, a to 32 mS. Ostatní možnosti jako například VID, PID nebo způsob napájení USB jsem nechal na defaultních hodnotách. V souboru usbdesc.c jsem změnil USB_STRING_DESCRIPTOR_TYPE, který popisuje název zařízení zobrazovaný po připojení v PC. Nastavil jsem text: „Vývojový kit s LPC2148“ a upravil velikost deskriptoru. 30 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Použité API od NXP je vytvořené jako vzor pro odesílání a přijímání jednoho bajtu. Ve vizuálním rozhraní se bude přijímat a odesílat 18 bajtů a je tedy nutné v souboru hiduser.c v metodě HID_SetReport nastavit kopírování všech přijatých dat na koncové bráně do OutReportu (výstupní buffer s přijatými daty). Kopírování všech přijatých dat se provede zapsáním: memcpy(OutReport, EP0Buf,USB_HID_REPORT_OUT); kde OutReport je výstupní buffer s přijatými daty EP0Buf je buffer s přijatými daty z daného koncového bodu USB_HID_REPORT_OUT je počet přijímaných bajtů. Pro základní obousměrnou USB komunikaci v režimu HID není zapotřebí nastavovat další parametry. Veškeré nastavení komunikace a deskriptor je nastaven defaultně v rámci použitého API. Po uložení jsem musel v Options for target (možnostech pro cílové zařízení) v kolonce Output (výstup) zaškrtnout políčko Create Library (vytvořit knihovnu). Poté jsem nechal projekt zkompilovat (Build target) a ve složce Obj se vytvořila požadovaná knihovna HID.lib. Detailní postup a popis je v souboru AN10736.pdf v [11]. 5.2.2. Vytvoření aplikace využívající USB HID API Při vytváření nového projektu, který využívá USB HID API, jsem importoval knihovnu HID.lib do projektu. Poté jsem importoval usb_api.h, ve kterém jsem změnil hodnotu u USB_HID_REPORT_IN a USB_HID_REPORT_OUT na hodnoty odpovídající počtu odesílaných a přijímaných bajtů. V mém případě jsem tedy nastavil obě hodnoty na 18 bajtů. Pro možnost ovládání periferií jsem do projektu importoval ještě soubory potřebné pro alfanumerický displej a soubory pro maticovou klávesnici (viz. kapitola 3). Grafický displej není možné použít bez hardwarových oprav vývojového kitu (viz. níže). 31 Softwarové vybavení kitu s procesorem LPC2148 5.2.3. Bc. Tomáš Fried 2011 Provedené hardwarové a softwarové úpravy Dodaný vývojový kit obsahuje konektor pro připojení USB kabelu. Ovšem vývody z konektoru nevedou na správné piny procesoru. Datové signály D+ a D- jsou fyzicky připojeny na jiné piny procesoru, než by měly být. Na procesoru jsou pro D+ a Drezervovány piny P0.26 a P0.27. Na vývojovém kitu jsou k těmto pinům připojeny signály RST a CS2 pro grafický displej. Z tohoto důvodu není možné bez hardwarové opravy použít grafický displej zároveň s USB komunikací. Problém s datovými signály D+ a D- jsem vyřešil vyvedením drátové propojky z konektoru pro grafický displej na jumpery povolující D+ a D-. Při oživování USB komunikace a alfanumerického displeje jsem narazil na další chyby návrhu vývojového kitu. Některé piny vyvedené na konektor k alfanumerickému displeji jsou využívány USB sběrnicí a není tedy možné displej zapojit přímo na konektor určený k tomuto účelu. Jedná se o piny DB7 a EN u alfanumerického displeje. Na pin DB7 je přiveden signál VBUS, který se po enumeraci zařízení chová jako výstup signalizující napájení sběrnice. Pin EN je připojen na UP_LED, který se chová jako výstup signalizující stav USB zařízení. Tyto piny jsem tedy vyvedl drátovou propojkou na neobsazené piny (P0.0 a P0.1). Tato změna si vyžádala i úpravu softwaru pro alfanumerický displej. Provedená změna obsluhy LCD je k vidění v kompletním zdrojovém kódu na přiloženém CD. Piny DB7 a EN využívá i grafický displej a při jeho oživování by bylo nutné řešit stejný problém. 5.3. Obsluha USB HID API Při obsluze HID API je nutné nejprve USB komunikaci inicializovat. To se provádí zavoláním funkce USB_Init(GetInReport,SetOutReport); Tento příkaz provede reset USB zařízení a nastaví adresu 0. Jak bylo zmíněno v kap. 5.1, při procesu enumerace umí zařízení komunikovat pouze na adrese 0 koncové brány 0. Funkce USB_Init obsahuje 2 důležité parametry, které odkazují API na funkce, ke kterým může přistupovat. API poté přistupuje k funkci GetInReport a SetOutReport. Funkce GetInReport je volána v nastaveném intervalu a nastavují se zde data odesílaná k hostitelskému zařízení. Funkce SetOutReport je volána ve stejném časovém intervalu a jsou v ní přijímána data od hostitele. 32 Softwarové vybavení kitu s procesorem LPC2148 5.4. Bc. Tomáš Fried 2011 Popis programu V hlavní části programu jsem nejprve provedl počáteční nastavení LED diod, inicializaci alfanumerického displeje a inicializaci maticové klávesnice. init_led(); //nastavení jako výstup, zpočátku zhasnuté init_keybrd(); //nastavení potřebných vstupů a výstupů a zapnutí časovače init_lcd(); //inicializace alfanumerického displeje Po počáteční inicializaci použitých periferií jsem provedl inicializaci USB komunikace. Ta se provádí následujícím způsobem: USB_Init(GetInReport,SetOutReport); //inicializace USB Jakmile proběhne inicializace všech zařízení, tak se na LCD vypíše text „Vyvojovy kit s LPC2148“. Poté je umístěna nekonečná smyčka a program tedy skáče pouze do obsluhy časovače a obsluhy USB. Do PC je odesíláno 18 bajtů. Počet 18 bajtů jsem zvolil z důvodu ukázky funkčnosti komunikace. V aplikaci zapisuji pouze na 4 bajty, ostatní bajty nesou hodnotu 0x00. Dva bajty výstupního bufferu jsem použil na signalizaci zmáčknutí tlačítka INT1 a libovolného tlačítka na maticové klávesnici. Odesílaná data do PC se nastavují ve funkci GetInReport, kde do prvního bajtu pole InReport zapisuji informaci o stisku tlačítka INT1. Druhý a třetí bajt výstupního bufferu jsem naplnil hodnotami 0xF0 a 0x0F a nenesou žádnou užitečnou informaci. Třetí bajt výstupního bufferu obsahuje kód stisknuté klávesy na maticové klávesnici. void GetInReport (void) { //odesílání dat do PC, provádí se každý interval if ((IOPIN0 & PBINT) == 0) { // kontrola INT1 tlačítka InReport[0] = 0x01; //INT1 stisknuto } else { InReport[0] = 0x00; //INT1 nestisknuto } InReport[1]=0x0F; //neslouží k ničemu InReport[2]=0xF0; //neslouží k ničemu InReport[3]=but; } //odesílá aktuálně zmáčknuté tlačítko na maticové klávesnici 33 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Aplikace je nastavena přijímat 18 bajtů od hostitelského PC. Příjem dat se provádí ve funkci SetOutReport, kde je pole OutReport obsahující přijatá data. Nultý bajt vstupního bufferu jsem použil pro odeslání příkazu. Ten určuje, jaká periferie bude ovládána. Bajt 1 – 16 vstupního bufferu slouží pro přenos dat na alfanumerický displej. Každý bajt obsahuje jeden přenášený znak a celkově se tedy přijímá text pro celý řádek. V posledním bajtu je posílána hodnota pro nastavení LED diod. Funkce pro příjem dat s některými vybranými příkazy: void SetOutReport (void) { int i; switch(OutReport[0]){ //vyhodnocení příkazu case 0x01:{ // inicializace - zhasnutí LED diod, smazání LCD IOCLR1 = LEDMSK; lcd_clear(); break; } case 0x02:{ //nastavení příslušné hodnoty na LED diody IOCLR1 = LEDMSK; IOSET1 = (OutReport[17] << 16); break; } case 0x03:{ //smazání LCD displeje lcd_clear(); break; } case 0x04:{ //zápis na LCD řádek 1 EnableKeyboardTimer(FALSE); //vypnutí časovače maticové klávesnice for( i=1;i<17;i++){ //kopírování potřebných dat text[i-1]=OutReport[i]; } lcd_putstring(0,text); //zapsání textu na displej EnableKeyboardTimer(TRUE); //zapnutí časovače maticové klávesnice break; } case 0x05:{ //zápis na LCD řádek 1 EnableKeyboardTimer(FALSE); //vypnutí časovače maticové klávesnice for( i=1;i<17;i++){ kopírování potřebných dat text[i-1]=OutReport[i]; } lcd_putstring(1,text); //zapsání textu na displej EnableKeyboardTimer(TRUE); 34 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 //zapnutí časovače maticové klávesnice break; } } Obdobným způsobem je realizováno i zobrazení aktuálně stisknutého tlačítka jak v PC, tak na maticové klávesnici připojené k procesoru. Definoval jsem pro ně příkazy 0x06 a 0x07, kde vizuální rozhraní identifikuje stisknuté tlačítko a to poté vypíše na alfanumerický displej obdobně jako v příkazu 0x04 a 0x05. Kompletní μVision projekt je k nalezení na přiloženém CD. 5.5. Připojení k PC a instalace ovladačů Jakmile se aplikace nahraje do LPC2148, je možné vývojový kit připojit k USB sběrnici. Po připojení nastává již popisovaný proces enumerace. Po procesu enumerace začne operační systém v hostitelském zařízení vyhledávat ovladače pro připojené zařízení. Ovladače zvolí na základě VID a PID. Zařízení typu HID jsou operačními systémy hojně podporovány a není tedy zapotřebí instalovat nebo vyvíjet vlastní ovladač. Na obr. 5.2 je vidět nalezení vývojového kitu v operačním systému Windows XP. Obr. 5.2 Proces instalace univerzálních ovladačů po připojení vývojového kitu k PC Po automatické instalaci ovladačů pro zařízení typu HID je zařízení plně připraveno k použití viz obr. 5.3. 35 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obr. 5.3 Informace o připojeném zařízení V této fázi je na alfanumerickém displeji vypsán text: „VYVOJOVY KIT S LPC2148“ a procesor čeká na data z hostitelské aplikace. 6 Vizuální rozhraní do PC 6.1. Obecně Vizuální rozhraní umožňující ovládání vývojového kitu s LPC2148 jsem vytvořil ve vývojovém prostředí Microsoft Visual Studio 2008 v programovacím jazyce C#. Vizuální rozhraní je spustitelná aplikace v OS Microsoft Windows i jiných platformách s nainstalovaným .NET Frameworkem verze minimálně 2.0. .NET Framework je v základní instalaci operačního systému Windows XP a ve všech novějších verzích OS Windows. Aplikaci jsem vyvíjel a testoval na OS Windows XP a nebyla testována na jiných platformách, jako je například Linux. Důvod, proč jsem aplikaci netestoval na jiných platformách, je takový, že nemám k dispozici jiné platformy a vizuální rozhraní je určené prioritně pro OS Windows. Pro starší OS Windows je .NET Framework ke stažení na [16]. Kompletní zdrojový kód a spustitelná aplikace je k nalezení na přiloženém CD. 36 Softwarové vybavení kitu s procesorem LPC2148 6.2. Bc. Tomáš Fried 2011 Použité komponenty a knihovny Při vývoji aplikace jsem vyzkoušel několik variant přístupu k USB HID zařízení, ale jako nejvhodnější řešení se ukázalo použití UsbLibrary [17]. UsbLibrary obsahuje HID komponentu umožňující přístup k definovanému USB zařízení pomocí VID a PID. Z tohoto zařízení je poté možné číst data nebo provádět zápis dat do zařízení. UsbLibrary je určena pro programovací jazyk C# a je licencována CPOL 1.02 [18]. To umožňuje její volné stažení, používání, úpravy a je možné ji dále distribuovat. Dále jsem použil knihovnu USBClass [19] umožňující čtení informací o připojeném zařízení ze systému. Tato knihovna je taktéž licencována pomocí licence CPOL 1.02 [18]. 6.3. Funkce UsbLibrary Při vytváření aplikace s pomocí UsbLibrary jsem použil níže popsané události, které UsbLibrary zajišťuje. usb_OnSpecifiedDeviceArrived - nastane po připojení specifikovaného zařízení usb_OnSpecifiedDeviceRemoved - nastane při odpojení specifikovaného zařízení usb_OnDataRecieved - nastane každý interval příjmu dat usb_OnDataSend - nastane každý interval odesílání dat Pro správnou funkci UsbLibrary je nejprve nutné UsbLibrary importovat do projektu jako referenci, poté vložit HID komponentu v design režimu a softwarově jí nastavit VID a PID. Po nastavení VID a PID se zkontroluje, jestli je specifikované zařízení připojeno. Nastavení VID a PID se provádí zápisem do příslušných textových vstupů ve vizuálním rozhraní, kde jsou defaultně nastavené hodnoty pro API vývojového kitu. UsbLibrary také zprostředkovává odeslání dat k definovanému zařízení. Základní nastavení UsbLibrary: this.usb.ProductId= Int32.Parse(this.tb_PID.Text,System.Globalization.NumberStyles.HexNumber); this.usb.VendorId = Int32.Parse(this.tb_VID.Text, System.Globalization.NumberStyles.HexNumber); 37 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 this.usb.CheckDevicePresent(); Odeslání dat pomocí UsbLibrary: private void send(byte[] data) //odeslání pole bajtů na USB sběrnici { if (this.usb.SpecifiedDevice != null) { //pokud je zařízení připojeno this.usb.SpecifiedDevice.SendData(data); //odešlou se data na USB sběrnici } else { //signalice neúspěchu statusBar_status.ForeColor = Color.Red; //nastavení červené barvy písma status baru statusBar_status.Image = Image.FromFile("red.png"); //zapnutí červeného indikátoru statusBar_status.Text = "Zařízení není připojeno. Připojte jej!"; //vypsání textu do status baru } } 6.4. Funkce USBClass USBClass jsem použil pro zjištění systémových informací o připojeném HID zařízení. Informace o zařízení zjišťuji ve chvíli, kdy je specifikované zařízení připojené, tedy když nastává událost usb_OnSpecifiedDeviceArrived() z UsbLibrary. Pomocí USBClass je poté možné zjistit, jakou třídu ovladačů připojené zařízení využívá, jakého je standardu a jaký má název (definovaný v kap. 5.2.1). Ukázka vyčtení informací o připojeném zařízení: if(USBClass.GetUSBDevice(uint.Parse(tb_VID.Text,System.Globalization.NumberStyles.Allo wHexSpecifier),uint.Parse(tb_PID.Text,System.Globalization.NumberStyles.AllowHexSpecifi er),ref USBDeviceProperties, false)) { lb_class.Text = "Použitá třída: " + USBDeviceProperties.DeviceClass; lb_deviceType.Text = "Typ zařízení: " + USBDeviceProperties.DeviceDescription; lb_productName.Text = "Název zařízení: " + USBDeviceProperties.DeviceLocation;} 38 Softwarové vybavení kitu s procesorem LPC2148 6.5. Bc. Tomáš Fried 2011 Hlavní funkce vizuálního rozhraní Výsledné vizuální rozhraní je ukázáno na obr. č. 6.1. Pokud není vývojový kit připojen, nelze stisknout žádné tlačítko kromě tlačítka připojit. Fota aplikace před připojením a po odpojení vývojového kitu jsou v příloze E. Jakmile se stiskne tlačítko připojit, zavolá se základní nastavení UsbLibrary viz. kap. 6.3. Po připojení zařízení se v části označené jako DATA IN začnou zobrazovat přijatá data a umožní se používání všech dostupných tlačítek v aplikaci. Přijatá data se zobrazují okamžitě po připojení, jelikož v HID API pro procesor je nastaven interval odesílání dat každých 32mS. Jako indikace úspěšného připojení vývojového kitu se po připojení odešle text: „Vyvojovy kit spojen s PC“ na alfanumerický displej. Jako další indikátor připojeného zařízení se ve spodní části aplikace zobrazí zelené kolečko s nápisem: „Zařízení s LPC2148 připojeno!“. Obr. 6.1 – Běh vizuálního rozhraní Událost volaná po připojení specifikovaného zařízení: private void usb_OnSpecifiedDeviceArrived(object sender, EventArgs e) //událost při připojení specifikovaného USB zařízení { try 39 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 { if(USBClass.GetUSBDevice(uint.Parse(tb_VID.Text,System.Globalization.NumberStyles.Allo wHexSpecifier),uint.Parse(tb_PID.Text,System.Globalization.NumberStyles.AllowHexSpecifi er), ref USBDeviceProperties, false)) { //Vyčtení systémových informací o připojeném zařízení lb_class.Text = "Použitá třída: " + USBDeviceProperties.DeviceClass; lb_deviceType.Text = "Typ zařízení: " + USBDeviceProperties.DeviceDescription; lb_productName.Text= "Název zařízení: " + USBDeviceProperties.DeviceLocation; } statusBar_status.Text = "Zařízení s LPC2148 připojeno!"; //Zápis do status baru statusBar_status.ForeColor = Color.Black; //Nastavení barvy písma statusBar_status.Image = Image.FromFile("green.png"); //Nastavení zeleného indikátoru enableAll(); //povolení možnosti mačkání na tlačítka a checkboxy dataOut[cmd] = init; //data na odeslání -inicializační příkaz -vypne LED,smaže LCD send(dataOut); //odešle inicializaci sendTextToLCD(" Vyvojovy kit", lcdLine1); //zapíše text na 1. řádek sendTextToLCD(" spojen s PC", lcdLine2); //zapíše text na 2. Řádek string rec_data = null; foreach (byte myData in dataOut) { //vypíše odeslaná data do listboxu DataOut ve formátu hex if (myData.ToString("X").Length == 1) { rec_data += "0"; //zajištění stejného výstupního formátu dvou znaků } rec_data += myData.ToString("X") + " "; } this.lb_OUT.Items.Insert(0, rec_data); //vložení do lisboxu na nejvyšší pozici } catch (Exception ex) { MessageBox.Show(ex.ToString()); //odchycení výjimky } } Zachycení výjimek jsem provedl v každé funkci stejným způsobem a nebudou zde dále vypisovány. Jakmile proběhne událost při připojení specifikovaného zařízení, je možné ovládat vývojový kit pomocí vizuálního rozhraní. Vizuální rozhraní jsem rozdělil na jednotlivé části ovládající danou periferii. 40 Softwarové vybavení kitu s procesorem LPC2148 6.5.1. Bc. Tomáš Fried 2011 Ovládání LED diod LED diody je možné ovládat zaškrtnutím příslušného zaškrtávacího políčka. Jakmile se změní stav na jakémkoli zaškrtávacím políčku, zavolá se funkce chb_led_CheckedChanged(). Tato funkce poté zjistí, na jakém zaškrtávacím políčku nastala změna a vyhodnotí se. Aktuální stav LED je v posledním odesílaném bajtu, od kterého nový stav buď odečítá, nebo ke kterému se přičítá. Funkce pro obsluhu LED diod: private void chb_led_CheckedChanged(object sender, EventArgs e) { CheckBox chb = sender as CheckBox; //odesílatel je checkBox LEDvalue= Convert.ToByte(Math.Pow(2, Convert.ToDouble(chb.Text.Substring(3, 1)))); //vyhodnotím podle textu odesílatele if (chb.Checked) { dataOut[18] += LEDvalue; //pokud zaškrtnuto, přičti hodnotu } else { dataOut[18] -= LEDvalue; //pokud ne, tak odečti } dataOut[cmd] = led; //nastavení příkazu pro ovládání LED send(dataOut); //odeslání dat } 6.5.2. Ovládání tlačítek Při stisku tlačítka na maticové klávesnici se odešle hodnota odpovídající příslušnému tlačítku do hostitelské aplikace. Ta poté vyhodnotí přijatá data, zmáčkne příslušné tlačítko v aplikaci, vypíše informaci o stisknutém tlačítku na spodní lištu vizuálního rozhraní a odešle na alfanumerický displej vývojového kitu text „Stisknuto: KB“ a text s příslušným tlačítkem. Fotka tohoto stavu je v příloze E. Stejným způsobem je obsloužen stisk tlačítka INT1, které je umístěné na vývojovém kitu. INT1 pouze využívá vlastní přenosový bajt pro signalizaci stisku. Vizuální rozhraní také umožňuje stisk tlačítka přímo v aplikaci. Jakmile dojde ke stisku jakéhokoli tlačítka na klávesnici ve vizuálním rozhraní, vypíše se na 41 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 alfanumerický displej vývojového kitu text „Stisknuto: PC“ a text s příslušným tlačítkem. Úryvek obsluhy stisknutého tlačítka na maticové klávesnici vývojového kitu: foreach (var btn in gb_buttons.Controls) { //pro každý element v group boxu tlačítek Button but = btn as Button; if (args.data[4] != 0 && args.data[4]<17) { //pokud jsou přijatá data na pozici tlačítek ve správném rozmezí if (but.Name == "btn_" + args.data[4]){ but.Enabled = false; //zmáčkne příslušné tlačítko count++; if (count == 1){ //pokud je to poprvé pošli jeho název na LCD sendTextToLCD("tlacitko:" + but.Text.ToString(), buttonClickDevice); //odešle text na displej + příkaz signalizující stisk tlačítka na maticové kláv. } showButtonInfo(args.data[4]); //vypsání informace o stisknutém tlač. ve status baru } } else { //není stisknuté žádné tlačítko if (but.Name.Substring(0, 4) == "btn_") { but.Enabled = true; //není zmáčknuté žádné tlačítko count = 0; //nastavení počáteční hodnoty statusBar_info.Text = null; //žádný text do status baru } } } Obsluha stisknutého tlačítka ve vizuálním rozhraní: private void keyboard_Click(object sender, EventArgs e) { Button btn = sender as Button; //odesílatel je tlačítko sendTextToLCD("tlacitko:" + btn.Text.ToString(), buttonClickHost); //odešle text na displej + příkaz signalizující stisk tlačítka v PC } 6.5.3. Ovládání LCD displeje Ovládání LCD displeje nabízí možnosti zápisu textu na jednotlivé řádky, na oba řádky najednou a smazání displeje. Textové pole pro jednotlivé řádky je v aplikaci omezené na počet 16 znaků. 42 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Obsluha tlačítka pro nastavení 1. řádky: private void btnSetLine1_Click(object sender, EventArgs e) { sendTextToLCD(tb_line1.Text, lcdLine1); //odešle text z textboxu pro první řádek a příkaz pro 1 řádek LCD } Nastavení textu na druhý řádek se provádí obdobným způsobem. Při nastavení textu na oba řádky se provede nastavení první řádky, poté nastavení druhé řádky. Obsluha tlačítka pro smazání LCD: private void btnClearLCD_Click(object sender, EventArgs e) { dataOut[cmd] = lcdClear; //nastavení příkazu smaž LCD do výstupních dat send(dataOut); //odeslání dat tb_line1.Text = null; //smazání textového pole pro 1. řádek tb_line2.Text = null; //smazání textového pole pro 2. řádek } Funkce sendTextToLCD převádí data z textového vstupu na jednotlivé ASCII znaky, které ukládá na jednotlivé pozice odesílaných dat. Dále nastavuje příkaz, díky kterému procesor například pozná, na jaký řádek má požadovaný text zapsat. private void sendTextToLCD(string text,byte com) //parametr textový řetězec a příkaz { System.Text.Encoding ascii = System.Text.Encoding.ASCII; Byte[] encodedBytes = ascii.GetBytes(text); //překódovaný textový řetězec do ASCII znaků dataOut[cmd] = com; //nastavení příkazu na pozici pro příkaz for (int i = 0; i < 16 ; i++) //provádí se pro 16 znaků { if (i < encodedBytes.Length) { dataOut[i + 2] = encodedBytes[i]; //zápis znaku na odpovídající pozici výstupních dat } else { //pokud je text kratší než 16 znaků, je doplněn mezerami dataOut[i + 2] = Convert.ToByte(' '); } } send(dataOut); } //odeslání dat 43 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 7 Závěr V této diplomové práci jsem se zabýval problematikou softwarové obsluhy vývojového kitu s výkonným 32bitovým mikroprocesorem LPC2148 s jádrem ARM7. Vytvořil jsem popis technologie ARM, popis dodaného vývojového kitu a poté jsem provedl detailní popis softwarové obsluhy vybraných periferií. Pro všechny popisované periferie jsem vytvořil samostatné projekty a uložil funkční zdrojové kódy psané v jazyce C na přiložené CD. Tyto zdrojové kódy objasnily principy softwarového ovládání periferií mikroprocesoru LPC2148. V další části práce jsem se zabýval oživením dodaného vývojového kitu. Vytvořil jsem obslužné programy pro všechny požadované periferie. Nejprve jsem vytvořil vzorovou aplikaci pro práci s LED diodami, poté aplikaci pro ovládání maticové klávesnice s odesíláním stisknuté klávesy na sériový port a dále jsem vytvořil obslužné programy pro alfanumerický a grafický displej. Fota a zdrojové kódy pro obsluhu těchto periferií jsou k nalezení v přílohách níže. Poslední částí této práce bylo vytvoření aplikace obsluhující USB komunikaci do mikroprocesoru a do hostitelského PC. Popsal jsem obecné informace o USB jako je historie, topologie sběrnice, režimy přenosu dat, třídy zařízení apod. Poté jsem detailně popsal režim HID a vytvořil aplikaci pro mikroprocesor, umožňující kompletní ovládání LED, maticové klávesnice a LCD displeje. Dále jsem vytvořil vizuální rozhraní pro PC v programovacím jazyce C#. Vizuální rozhraní umožňuje ovládání periferií vývojového kitu a přenos dat pomocí USB sběrnice. Aplikace pro mikroprocesor a pro PC jsem detailně popsal a okomentoval. Fota vizuálního rozhraní jsou v příloze E. Při vytváření softwarové obsluhy jsem u některých periferií narazil na problémy chybného návrhu vývojového kitu. Ty způsobily nutnost použití drátových propojek a znemožnily použití grafického displeje v kombinaci s USB. Soupis nalezených chyb vývojového kitu jsem umístil do přílohy F a bylo by vhodné tyto hardwarové chyby opravit. Po opravení těchto chyb by bylo vhodné do vizuálního rozhraní přidat ovládání grafického displeje. 44 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 Seznam použité literatury [1] ARM : The Architecture For The Digital World [online]. 2010 [cit. 2010-12-02]. ARM. Dostupné z WWW: <www.arm.com>. [2] LPC214x User Manual [online]. Rev. 3. [s.l.] : NXP B.V., 4.10.2010 [cit.2010-12-02].Dostupné z <http://www.nxp.com/documents/user_manual/UM10139.pdf>. WWW: [3] DUDÁČEK, Karel. Maticové snímání klávesnice [online]. 2010 [cit. 2011-04-18]. Klavesnice. Dostupné z WWW: <http://home.zcu.cz/~dudacek/PZ/klavesnice.pdf>. [4] SparkFun Electronics [online]. 1998 [cit. 2011-04-18]. HD44780. Dostupné z WWW: <http://www.sparkfun.com/datasheets/LCD/HD44780.pdf>. [5] Elektronika, bastlení, návody [online]. 2007 [cit. 2011-04-18]. Ovládání znakových LCD s řadičem HD44780. Dostupné z WWW: <http://elektronika.kvalitne.cz/ATMEL/necoteorie/LCDmatice.html>. [6] Elektronika, bastlení, návody [online]. 2006 [cit. 2011-04-18]. Ovládání grafických LCD s řadičem KS0108. Dostupné z WWW: <http://elektronika.kvalitne.cz/ATMEL/necoteorie/LCDmatKS0108.html>. [7] Mikroelektronika [online]. 1998 [cit. 2011-04-18]. MikroC PRO for AVR. Dostupné z WWW: <http://www.mikroe.com/eng/products/view/228/mikroc-pro-for-avr/>. [8] This is Dincer Aydin's Home Page [online]. 2001 [cit. 2011-04-18]. Bitmap Calculator for KS0108. Dostupné z WWW: <http://www.dinceraydin.com/lcd/gfxcalc.htm>. [9] Free software downloads [online]. 2007 [cit. 2011-04-18]. GLCD Font Creator. Dostupné z WWW: <http://download.cnet.com/GLCD-Font-Creator/3000-2190_410719330.html>. [10] HW.cz | Vše o elektronice a programování [online]. 2005 [cit. 2011-04-18]. USB 2.0 - díl 1. Dostupné z WWW: <http://hw.cz/Rozhrani/ART1232-USB-2.0---dil1.html>. [11] NXP Semiconductors [online]. 2008 [cit. 2011-04-18]. AN10736. Dostupné z WWW: <http://www.nxp.com/documents/application_note/AN10736.pdf>. [12] Universal Serial Bus [online]. 2000 [cit. 2011-04-18]. USB 2.0 Specification. Dostupné z WWW: <http://www.usb.org/developers/docs/>. [13] Universal Serial Bus [online]. 2010 [cit. 2011-04-18]. Mass_Storage_Specification_Overview. Dostupné z WWW: <http://www.usb.org/developers/devclass_docs/Mass_Storage_Specification_Overvi ew_v1.4_2-19-2010.pdf>. 45 Softwarové vybavení kitu s procesorem LPC2148 Bc. Tomáš Fried 2011 [14] Universal Serial Bus [online]. 2000 [cit. 2011-04-18]. Device Class Definition for Printing Devices. Dostupné z WWW: <http://www.usb.org/developers/devclass_docs/usbprint11a021811.pdf>. [15] Universal Serial Bus [online]. 2009 [cit. 2011-04-18]. USB Class Codes. Dostupné z WWW: <http://www.usb.org/developers/defined_class>. [16] NXP Semiconductors [online]. 2008 [cit. 2011-04-18]. AN10736. Dostupné z WWW: <http://ics.nxp.com/support/documents/microcontrollers/zip/an10736.zip>. [17] Stahuj.cz - Svět software [online]. 2010 [cit. 2011-04-18]. .NET Framework. Dostupné z WWW: <http://www.stahuj.centrum.cz/vyvojove_nastroje/ostatni/netframework/>. [18] CodeProject - Your Development Resource [online]. 2007 [cit. 2011-04-18]. A USB HID Component for C#. Dostupné z WWW: <http://www.codeproject.com/KB/cs/USB_HID.aspx>. [19] CodeProject - Your Development Resource [online]. 2011 [cit. 2011-04-18]. CPOL : Code Project Open License. Dostupné z WWW: <http://www.codeproject.com/info/cpol10.aspx>. [20] CodeProject - Your Development Resource [online]. 2010 [cit. 2011-04-18]. A USB Library to Detect USB Devices. Dostupné z WWW: <http://www.codeproject.com/KB/system/AUSBClassLibrary.aspx>. 46 Seznam příloh A Obsluha maticové klávesnice + UART B Znaková sada HD44780 C Obsluha alfanumerického displeje + foto D Fotky oživeného grafického displeje + fota hardwarových úprav E Fotky vizuálního rozhraní a komunikujícího vývojového kitu F Soupis úprav hardware G Obsah přiloženého CD Přílohy Příloha A – klávesnice + UART #include <LPC21xx.H> #define sloupec1 (1<<2) #define sloupec2 (1<<3) #define sloupec3 (1<<4) #define sloupec4 (1<<5) #define rada1 (1<<6) #define rada2 (1<<7) #define rada3 (1<<10) #define rada4 (1<<11) #define sloupec_maska (sloupec1|sloupec2|sloupec3|sloupec4) unsigned char pos; unsigned char tmp; unsigned char but; unsigned char lastState; void Timer0isr(void)__irq; PLL_init(void){ PLLCFG = 0x00000024; // nastavení násobiče M a dělitele P pro získáni 60MHz //M=5=00100 a P=2=01 - M + P = 0100100 = 0x24 PLLCON = 0x00000001; // povolení PLL PLLFEED = 0x000000AA; PLLFEED = 0x00000055; //update PLL registru, musí proběhnout po sobě while (!(PLLSTAT & 0x00000400)); // testuj Lock bit, jestli je již PLL uzamčen na požadované frekvenci PLLCON = 0x00000003; // připojeni k PLL PLLFEED = 0x000000AA; PLLFEED = 0x00000055; //update PLL registru, musí proběhnout po sobě VPBDIV = 0x00000004; //nastavení frekvence Pclk na Cclk/4, tedy 15.000MHz } Timer_init(void){ T0PR = 0x00000002 ; //nastavení děličky na 0 - každý tick inkrementuje čítač časovače T0TCR = 0x00000002; //reset čítače a děličky I T0MCR = 0x00000003; //při shodě vymaž čítač časovače a vyvolej přerušení T0MR0 = 0x08FFFF; //nastavení časového intervalu časovače T0TCR = 0x00000001; //zapnutí časovače VICVectAddr0 = (unsigned)Timer0isr; //nastavení adresy pro ISR časovače VICVectCntl0 = 0x24; //bit 5 - povolení vektoru, bit 0:4 - kanál 4 pro timer VICIntEnable |= 0x00000010; //povolení přerušení } unsigned char getPos(void){ //zjišťování pozice tlačítka 1-4 pos = 0; if(!(IOPIN0&rada1)){ pos =1;} if(!(IOPIN0&rada2)){ pos =2;} if(!(IOPIN0&rada3)){ pos =3;} if(!(IOPIN0&rada4)){ pos =4;} return pos;} unsigned char getButton(void){ //zjišťování sloupce tmp=0; IOSET0 = sloupec_maska; //zapnutí všech sloupců IOCLR0 = sloupec1; //vypnutí prvního sloupce tmp = getPos(); //zjištění pozice tlačítka if(tmp!=0){ tmp = tmp+10; } //zapíše číslo 1 jako sloupec 1 + pozice tlačítka if(tmp==0){ //pokud nebylo zmáčknuto v prvním sloupci,ptám se dále IOSET0 = sloupec_maska; IOCLR0 = sloupec2; //vypnuti druhého sloupce tmp = getPos(); if(tmp!=0){ tmp = tmp+20; } //zapsání čísla sloupce + pozice tlačítka } if(tmp==0){ //pokud nebylo zmáčknuto v předešlých sloupcích,ptám se dále IOSET0 = sloupec_maska; IOCLR0 = sloupec3; tmp = getPos(); if(tmp!=0){ tmp = tmp+30;} } if(tmp==0){ IOSET0 = sloupec_maska; IOCLR0 = sloupec4; tmp = getPos(); if(tmp!=0){ tmp = tmp+40; } } return tmp; //vrátí číslo označující sloupec a řádek } void Uart_putc(char c){ //zápis znaku na UART while(!(U0LSR & 0x20)); // čeká, dokud není UART0 připraven na odesílání U0THR = c; // odešle data na vysílací přídržný registr U0THR II } Uart_init(void){ PINSEL0 |= 0x00000005; /* zapnutí na P0.0 fci TXD0 a P0.1 na RXD0 */ U0LCR = 0x00000083; /* 8 bitů délka slova, vypnutá parita, 1 stop bit */ U0DLL = 0x00000061; /* 9600 Baud Rate při 15MHz VPB Clock */ U0LCR = 0x00000003; } /* Vypnutí DLAB - po nastavení přenosové rychlosti*/ int main(void){ but =0; lastState = 0; PLL_init(); //inicializace PLL Uart_init(); //inicializace UART Timer_init(); //inicializace Timeru IODIR0 = sloupec_maska; //nastavení sloupců jako výstup while(1);} //nekonečná smyčka void Timer0isr (void) __irq { //obsluha přerušení but = getButton(); //vrátí aktuálně stisknuté tlačítko if(lastState==but){ //zamezení nechtěného dvojstisku lastState=0; } else{ if(but!=0){ char tmp; switch(but){ //vyhodnocení zmáčknutého tlačítka case 11: tmp ='1'; break; case 12: tmp ='4'; break; case 13: tmp ='7'; break; case 14: tmp ='*'; break; case 21: tmp ='2'; break; case 22: tmp ='5'; break; case 23: tmp ='8'; break; case 24: tmp ='0'; break; case 31: tmp ='3'; break; case 32: tmp ='6'; break; case 33: tmp ='9'; break; case 34: tmp ='#'; break; case 41: tmp ='A'; break; case 42: tmp ='B'; break; case 43: tmp ='C'; break; case 44: tmp ='D'; break; } Uart_putc(tmp); //odeslání na uart } lastState = but; } T0IR |= 0x00000001; // smaž match 0 int. flag VICVectAddr = 0x00000000; // Dummy zápis pro ukončení přerušení } III Příloha B – znaková sada HD44780 Příloha C – alfanumerický displej + foto Zdrojový kód: //LCD.h #define LINE_LENGTH 16 #define LCD_DIR IODIR0 //vstup/výstup LCD pinu #define LCD_SET IOSET0 //nastavení 1 na LCD piny #define LCD_CLR IOCLR0 //nastavení 0 na LCD piny #define LCDRS (1 << 29) //RS na P0.29 #define LCDRW (1 << 30) //R/W na P0.30 #define LCDEN (1 << 31) //E na P0.31 #define LCD_D0 (1 << 16) //D0 na P0.16 #define LCD_D1 (1 << 17) //D0 na P0.17 #define LCD_D2 (1 << 18) //D0 na P0.18 #define LCD_D3 (1 << 19) //D0 na P0.19 #define LCD_D4 (1 << 20) //D0 na P0.20 #define LCD_D5 (1 << 21) //D0 na P0.21 #define LCD_D6 (1 << 22) //D0 na P0.22 #define LCD_D7 (1 << 23) //D0 na P0.23 #define LCD_DATA_MASK (LCD_D0 | LCD_D1 | LCD_D2 | LCD_D3 | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7) //maska pro data #define LCD_CONTROL_MASK 0xE0000000 //maska pro RS,RW a E piny #define LCD_BUSY_FLAG LCD_D7 //pin s flagem - displej zaneprázdněn #define CLR 0x01 //instrukce pro smazání displeje #define INIT 0x38 //instrukce pro inicializaci: 8bit mód, dvouřádkový, font 5x8 #define CUR0 0x02 //instrukce pro nastavení kurzoru na řádek0 pozice0 #define USR1 0x0F //instrukce pro zapnutí displeje,zapnutí kurzoru,blikání kurzoru IV //LCD.c int lcd_gotoxy( unsigned int line, unsigned int pos){ //jdi na pozici int err = 0; if( (line > 1) && (pos > 15) ) //zjištění platného rozsahu počtu řádků a délky řádku { err = -1; } //pokud je mimo rozsah, vrátí -1 else { switch(line){ case 0:{ lcd_cmd_write ( 0x80 + pos); //instrukce naadresování první řádky - adresa 0x00 + 7bit na 1 => 0x80 delay(500); break; } case 1:{ lcd_cmd_write( 0xC0 + pos); //instrukce naadresování druhé řádky - adresa 0x40 + 7bit na 1 => 0xC0 delay(500); break; } } } return err;} void lcd_putchar(int c){ lcd_data_write(c); } //zapíše hodnotu na datovou sběrnici void lcd_clear(void) { lcd_cmd_write(CLR); } //smazání displeje void init_lcd( void ){ //inicializace LCD LCD_DIR |= ( LCDEN | LCDRS | LCDRW | LCD_DATA_MASK ); // nastaveni datových a řídících pinů na výstupy LCD_CLR |= ( LCDEN | LCDRS | LCDRW | LCD_DATA_MASK); // nulování datových a řídících pinu lcd_cmd_write(INIT); //inicializace: 8bit mód, dvouřádkový, font 5x8 lcd_clear(); //smazání displeje lcd_cmd_write(CUR0); //nastaví kurzor na začátek lcd_cmd_write(USR1); //zapnutí displeje, kurzoru a blikání lcd_putstring(0," Vyvojovy Kit"); lcd_putstring(1," s LPC2148"); } void lcd_putstring( unsigned char line, char *string ){ unsigned char len = LINE_LENGTH; //maximální počet znaků na řádku lcd_gotoxy( line, 0 ); //nastaví na zvolenou řádku na pozici 0 while(*string != '\0' && len--) //dokud nebude konec řádku nebo max počet znaků na řádku { lcd_putchar( *string ); //zapíše znak, na který právě ukazuje pointer string++; } //posune na další znak } void lcd_data_write(unsigned char data) { unsigned int data_tmp=0; data_tmp=(data<<16); LCD_SET |= LCDEN|LCDRS; LCD_CLR = LCD_DATA_MASK; //zápis dat //posun dat na pozici datové sběrnice //nastavení E a RS na 1 //nulování datové sběrnice V LCD_SET = data_tmp; LCD_CLR |= LCDEN|LCDRS; lcd_wait();} //nastavení dat na datovou sběrnici //nulování E a RS //čeká, dokud nebude lcd zaneprázdněný void lcd_cmd_write (unsigned char command){ //zápis příkazu unsigned int data=0; LCD_SET = LCDEN; //nastav E na 1 LCD_CLR = LCDRS; //nastav RS na 0 LCD_CLR = LCD_DATA_MASK; //vynuluj datové piny data=(command<<16); //data přesun na pozici datových pinů LCD_SET = data; //nastav data na datovou sběrnici delay(10000); LCD_CLR = LCDEN; //nuluj E } void lcd_wait( void ) { LCD_CLR |= LCDRS; LCD_SET |= LCDRW | LCDEN; while(IOPIN0 & LCD_BUSY_FLAG); LCD_CLR |= LCDEN | LCDRW; delay(100);} //čeká, dokud není displej připraven //RS na 0 //RW a E na 1 //čeká, než displej nebude zaneprázdněn //RW a E na 0 Foto oživeného alfanumerického displeje: VI Příloha D – grafický displej + hardwarové úpravy Zdrojový kód: //LCD.h #define GLCD_DIR IODIR0 //vstup/výstup LCD pinů #define GLCD_SET IOSET0 //nastavení 1 na LCD piny #define GLCD_CLR IOCLR0 //nastavení 0 na LCD piny #define GLCD_D0 (1 << 16) //D0 na P0.16 #define GLCD_D1 (1 << 17) //D1 na P0.17 #define GLCD_D2 (1 << 18) //D2 na P0.18 #define GLCD_D3 (1 << 19) //D3 na P0.19 #define GLCD_D4 (1 << 20) //D4 na P0.20 #define GLCD_D5 (1 << 21) //D5 na P0.21 #define GLCD_D6 (1 << 22) //D6 na P0.22 #define GLCD_D7 (1 << 23) //D7 na P0.23 #define GLCD_RS (1 << 29) //RS na P0.29 #define GLCD_RW (1 << 30) //R/W na P0.30 #define GLCD_EN (1 << 31) //E na P0.31 #define GLCD_CS1 (1 << 15) //CS1 na P0.15 – drátová propojka z původního P0.26 – viz. příloha G #define GLCD_CS2 (1 << 25) //CS2 na P0.25 #define GLCD_RST (1 << 27) //RST na P0.27 #define GLCD_DATA_MASK (GLCD_D0 | GLCD_D1 | GLCD_D2 | GLCD_D3 | GLCD_D4 | GLCD_D5 | GLCD_D6 | GLCD_D7) //maska pro data #define GLCD_CONTROL_MASK (GLCD_RS|GLCD_RW|GLCD_EN|GLCD_RST|GLCD_CS1|GLCD_CS2) //maska pro RS,RW a E piny LCD_CS1|LCD_CS2| #define GLCD_BUSY_FLAG GLCD_D7 //pin s flagem - displej zaneprázdněn #define GLCD_ON 0x3F //definice konstant #define GLCD_OFF 0x3E #define GLCD_SET_ADD 0x40 #define GLCD_SET_PAGE 0xB8 #define GLCD_DISP_START 0xC0 #define CHIP1 0x01 #define CHIP2 0x02 #define BOTHCHIPS 0x03 #define BLACK 0xFF #define WHITE 0x00 void init_glcd(void); void glcd_goto_xy(int x,int y); void glcd_drawImage(const unsigned char bmp[1024]); void glcd_putstring( int x,int y, char *string ); void glcd_fill(char color); void glcd_put_pixel(int x,int y,char color); //LCD.c void glcd_wait( void ) //čekání na připravenost displeje { GLCD_CLR |= GLCD_RS; //RS na 0 GLCD_SET |= GLCD_RW | GLCD_EN; //RW a E na 1 while(IOPIN0 & GLCD_BUSY_FLAG); //čeká, až displej nebude zaneprázdněn GLCD_CLR |= GLCD_EN | GLCD_RW; //RW a E na 0 } VII void glcd_pulse_EN(void){ //pulz na EN GLCD_SET |=GLCD_EN; //pulz na EN delay(10); GLCD_CLR |=GLCD_EN; delay(10);} void glcd_write_data(char dat,int pos){ //zápis dat unsigned int tmpdat = 0; //pomocná proměnná if(pos<64){ //volba aktivního chipu podle pozice GLCD_CLR |=GLCD_CS2; GLCD_SET |=GLCD_CS1; } else{ GLCD_CLR |=GLCD_CS1; GLCD_SET |=GLCD_CS2; } GLCD_CLR |=GLCD_RW; //RW na 0 GLCD_SET |= GLCD_RS; //RS na 1 GLCD_DIR |= GLCD_DATA_MASK ; //nastavení datových pinů na výstupy tmpdat = (dat<<16); //posun dat na správnou pozici GLCD_SET = tmpdat; //zápis dat glcd_pulse_EN(); //pulz na EN GLCD_CLR |=GLCD_DATA_MASK|GLCD_CS1|GLCD_CS2; //data a výběr chipu na 0 glcd_wait(); //čekání, než bude displej připraven } void glcd_write_com(char cmd,char chip){ //zápis příkazu unsigned int tmpcmd = 0; //pomocná proměnná if(chip ==0x01){ //výběr chipu GLCD_CLR |=GLCD_CS2; GLCD_SET |=GLCD_CS1; } if(chip ==0x02){ GLCD_CLR |=GLCD_CS1; GLCD_SET |=GLCD_CS2; } GLCD_CLR |= GLCD_RS|GLCD_RW; //RS a RW na 0 GLCD_DIR |= GLCD_DATA_MASK ; //nastavení datových pinu na výstupy tmpcmd = (cmd<<16); //posun dat na správnou pozici GLCD_SET = tmpcmd; //zápis dat glcd_pulse_EN(); //pulz na EN GLCD_CLR |=GLCD_DATA_MASK|GLCD_CS1|GLCD_CS2; //data a výběr chipu na 0 glcd_wait(); //čekání, než bude displej připraven } void glcd_goto_xy(int x,int y){ //nastavení kurzoru na danou pozici char actual_chip = CHIP1; //defaultní chip=chip1 char cmd; if(x > 127) x = 0; //kontrola platnosti rozsahu x a y souřadnice if(y > 63) y = 0; if(x >= 64) { //pokud je x souřadnice větší než 64, tak se zvolí zápis na chip2 x -= 64; actual_chip = CHIP2; VIII } cmd = GLCD_SET_ADD | x; glcd_write_com(cmd, actual_chip); cmd = GLCD_SET_PAGE | (y/8); glcd_write_com(cmd, CHIP1); glcd_write_com(cmd, CHIP2); //výpočet požadované X souřadnice //nastavení x hodnoty na aktivní chip //nastavení y souřadnice stránky na oba chipy } void glcd_fill(char color){ //vyplnění celého displeje int i,j; for(j=0;j<8;j++){ glcd_goto_xy(0,j*8); //přesun kurzoru na nultou pozici x a postupné projetí všech stránek y for(i=0;i<64;i++){ glcd_write_data(color,i); //zápis data na první chip glcd_write_data(color,i+64); //zápis data na druhý chip } } } void glcd_drawImage(const unsigned char bmp[1024]){ //vykreslení obrázku 128x64 int x,y,z; y=x=z=0; while(y<64){ //dělej, dokud se nezaplní všech 8 stránek glcd_goto_xy(0,y); //nastav kurzor na stránku y a chip na chip1 for(x=0;x<64;x++){ //zápis 64 dat na danou stránku chipu1 glcd_write_data(bmp[z],x); z++; } glcd_goto_xy(64,y); //nastav kurzor na stránku y a chip na chip2 for(x=64;x<128;x++){ //zápis 64 dat na danou stránku chipu2 glcd_write_data(bmp[z],x); z++; } y+=8; //přičtení další stránky } } void glcd_put_pixel(int x,int y,char color){ //vykreslení jednoho bodu na danou pozici int tmp = y%8; //zjištění Y pozice pixelu char tmpp = 1<<tmp; //pomocná proměnná - 1 na pozici Y glcd_goto_xy(x,y); //nastavení kurzoru na x a y souřadnici if(color == BLACK){ glcd_write_data(tmpp,x); //zápis černého pixelu } else{ glcd_write_data(~tmpp,x); //zápis bílého pixelu } } void glcd_write_char(int c,int pos) //vypsání znaku na displej { int index = (c-32)*8; //dekadická hodnota znaku z ASCII tabulky,začátek na poz.32 int x; for(x=0;x<8;x++){ //každý znak má 8 bajtů IX glcd_write_data(Font8x8[index],pos); index++; pos++; //zápis daného znaku ze znakové sady } } void glcd_putstring( int x,int y, char *string ) //zápis řetězce na displej { int pos = x; unsigned char len = 128/8; //maximální počet znaků na řádku glcd_goto_xy(64,y*8); //nastavení chipu2 na první x pozici glcd_goto_xy(x,y*8); //nastavení chipu1 na pozici x while(*string != '\0' && len--) //dokud nebude konec řádku nebo max počet znaků na řádku { glcd_write_char(*string,pos); //zápis daného znaku string++; //posune na další znak pos+=8; } } void glcd_init(void){ //inicializace displeje glcd_wait(); //čeká, než bude displej připraven po zapnutí GLCD_DIR |= ( GLCD_CONTROL_MASK | GLCD_DATA_MASK ); // nastavení datových a řídicích pinů na výstupy GLCD_CLR |= ( GLCD_CONTROL_MASK | GLCD_DATA_MASK ); //vymazání datových a řídících pinů GLCD_SET = GLCD_RST; //reset na 1 glcd_write_com(GLCD_ON,CHIP1); //zapnutí chipu1 glcd_write_com(GLCD_ON,CHIP2); //zapnutí chipu2 glcd_wait(); //čekání, než bude displej připraven glcd_fill(WHITE); //vyplnění displeje na bílou barvu } Fota oživeného grafického displeje: Vykreslení obrázku: X Vypsání textu: HW úpravy: Příloha E – vizuální rozhraní + komunikace s vývoj. kitem Hostitelská aplikace po startu: XI Hostitelská aplikace po připojení USB zařízení: Hostitelská aplikace po odpojení zařízení: XII Vývojový kit po připojení s hostitelskou aplikací: Alfanumerický displej po stisku tlačítka na maticové klávesnici: Alfanumerický displej po stisku tlačítka ve vizuálním rozhraní: XIII Příloha F – úpravy hardware Grafický displej Na vývojovém kitu chybí potenciometr 10-20KΩ pro nastavení kontrastu grafického displeje. Ten se musí zapojit z pinu Vee na pin V0. Navržené řešení na vývojovém kitu s jedním potenciometrem není možné pro grafický displej použít. USB Některé piny, které jsou u LPC2148 rezervovány pro USB komunikaci jsou na vývojovém kitu použity pro jiné účely. Jedná se o piny D+, D-, VBUS a UP_LED. Tyto signály jsou přivedeny na konektory pro alfanumerický a grafický displej a tím zamezují jejich správnou funkčnost. Z toho vyplývá nemožnost použití jak displejů, tak USB komunikace bez přídavných drátových propojek. Pro snadné používání vývojového kitu by bylo vhodné tyto hardwarové problémy opravit. Pin D+ je přiveden na pin P0.26, který využívá konektor pro grafický displej jako pin CS2. Pin D- je přiveden na pin P0.27, který využívá konektor pro grafický displej jako pin RST. Pin VBUS je přiveden na pin DB7 alfanumerického i grafického displeje. VBUS se po enumeraci zařízení chová jako výstup signalizující napájení sběrnice. Pin UP_LED je přiveden na pin EN alfanumerického i grafického displeje. UP_LED se chová jako výstup signalizující stav připojeného zařízení. XIV Příloha G – obsah přiloženého CD Složka Soubor Info datasheets insiders-ARM-book.pdf datasheets datasheets datasheets datasheets datasheets datasheets periferie/LEDS periferie/UART periferie/SPI periferie/PLL periferie/TIMER lpc2141_42_44_46_48.pdf UM10139.pdf AN10736.pdf datasheet LCD 2x16.pdf HD44780.pdf rg12864b-biw-v.pdf uVision4 projekt uVision4 projekt uVision4 projekt uVision4 projekt uVision4 projekt periferie/klavesnice periferie/2x16 LCD periferie/GLCD vizuální rozhraní/Aplikace vizuální rozhraní/zdrojový kód LPC2148 Firmware LPC2148 Firmware/HEX uVision4 projekt uVision4 projekt uVision4 projekt UsbApp.exe manuál k použití mikroprocesorů s jádrem ARM podrobný popis LPC2141,2142,2144,2146 a 2148 podrobný popis registrů LPC2148 popis API pro HID class datasheet k alfanumerickému displeji datasheet k řadiči HD44780 datasheet ke grafickému displeji projekt obsluhující LED diody projekt obsluhující UART projekt obsluhující SPI projekt obsluhující PLL projekt obsluhující časovač projekt obsluhující maticovou klávesnici a UART projekt obsluhující alfanumerický displej projekt obsluhující grafický displej spustitelná aplikace vizuálního rozhraní Visual Studio 2008 projekt uVision4 projekt usbHid.hex diplomová práce FRIED.doc diplomová práce FRIED.pdf kompletní projekt vizuálního rozhraní projekt obsluhující HID API samotný hex soubor pro LPC2148 diplomová práce v doc formátu diplomová práce v pdf formátu XV
Podobné dokumenty
multiagentní systémy nail106 - Department of Theoretical Computer
• V mnoha situacích je intencionální postoj jednodušší než
alternativy.
• Z hlediska informatiky je to abstrakce za účelem zvládnutí
složitosti problému.
• Pro mnoho informatiků je programování pro...
No Title
PTA26/ADC2_SE15/ULPI_DATA4/MII0_TXD3/FB_
PTA27/ADC2_SE14/ULPI_DATA5/MII0_CRS/FB_A
PTA28/ADC2_SE13/ULPI_DATA6/MII0_TXER/FB_
PTA29/ADC2_SE12/ULPI_DATA7/MII0_COL/FB_A
PTB0/ADC0_SE8/ADC1_SE8/ADC2_SE8/A...
9x0-0202x0 Výdejní terminál 485 gLCD
od verze Stravné 4.50 (platí jen pro terminály ve variantě Audio) se používá hlasový výstup mužským nebo ženským
hlasem pomocí vestavěných reproduktorů (například: „oběd“, „neobjednáno“, „již vyzve...