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

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...

Více

No Title

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...

Více

No Title

No Title SQM4_K70_MODULE

Více

9x0-0202x0 Výdejní terminál 485 gLCD

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...

Více