Softwarová realizace USB

Milan Štohanzl, Pavel Štraus
xstoha01stud.feec.vutbr.cz, xstrau00stud.feec.vutbr.cz
projekt zveřejněn také na www.pandatron.cz a www.hw.cz

Obsah:

  1. Úvod
  2. Realizace
  3. Závěr
  4. Literatura

Úvod

Komunikaci mezi počítačem a mikrokontrolerem lze realizovat několika různými způsoby, které se od sebe liší na všech úrovních. I dnes je velmi oblíbené propojení pomocí sběrnice UART, která je obsažena téměř ve všech používaných mikrokontrolerech. Následné propojení s počítačem se realizuje propojením s konektorem COM v napěťových úrovních ± 12 V (známý jako RS232). Potřeba odlišných napěťových úrovní vyžaduje připojení napěťového převodníku označených jako MAX232 apod. Konektory COM se v poslední době z počítačů vytrácejí a na noteboocích se vyskytují pouze vyjímečně. Proto se hledají jiné cesty pro komunikaci mezi počítači a mikrokontrolery. Jednou z možných cest je komunikace přes USB.

Existují nejméně tři cesty, kterými se lze ubírat, když chceme komunikovat po sběrnici USB mezi mikrokontrolerem a počítačem. Jedním z řešení je využít mikrokontroleru s integrovaným USB rozhraním. Další cestou, podobnější původní komunikaci přes RS232, je využití převodníků UART/USB. Více se dozvíte například ZDE

Posledním řešením je to, kterým se tento projekt zabývá. Implementace USB protokolu do mikrokontroleru softwarově. Předem upozrňujeme, že celý projekt vychází z již hotového zdrojového kódu a pouze zobrazuje příklad použití a možnosti úprav originálního zdrojového kódu, který naleznete na stránkách autora: http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20%28AVR%29_eng.htm, kde jsme stáhli zip soubor, který obsahuje vše podstatné. Tento archiv je na stránkce http://www.cesko.host.sk/IgorPlugUSB_RS232/IgorPlug-USB%20(AVR)%20RS232_eng.htm. Přímo pro stažení je možné použít
http://www.cesko.host.sk/downloads/USB%20to%20RS232%20Application%20Note.zip.

Realizace

Krok 1: Test USB komunikace (ATmega 8)

Aby bylo možné vyzkoušet komunikaci mikrokontroleru s PC přes USB potřebujeme správně zapojený mikrokontroler (viz obr.1). Mikrokontroler je v této aplikaci napájen ze sběrnice USB. Dále musíme do mikrokontroleru ATmega8 nahrát soubor „usbtors232.hex“, který je obsažen v daném zip archivu ve složce: Firmware\USBtoRS232_ATmega8\AVR Studio 4 project. Nastavení při programování (propojky apod.) naleznete na obrázcích 2, 3 ,4. Nyní je vše připraveno. Po připojení USB kabelu je nutné nahrát ovladače do počítače. Tyto ovladače jsou také obsaženy v zip archivu ve složce Driver. Zde je také složka obsahující obrázky kroků instalace. Pak již stačí spustit „AVR309USBdemo.exe“ nalézající se ve složce Application\Delphi7 project. Je-li vše v pořádku, můžeme přímo nastavovat hodnoty na výstupních portech, načítat a ukládat data do paměti EEPROM nebo komunikovat s jiným zař. pomocí UART sběrnice.

Schema
Obr. 1: Schéma pro ATmega8
SetDevice
Obr. 2: Zapojení s ATmega8 funkční-signatura v pořádku
Fuse
Obr. 3: Nastaveni propojek
Programming
Obr. 4: Naprogramování ATmega8

Krok 2: Úprava firmware (ATmega 8)

Když otevřeme projekt pro AVR studio obsažený v zip archivu dojde k několika chybám a soubor nelze otevřít nebo nelze zkompilovat. Proto jsme založili nový projekt a zdrojový soubor překopírovali. Dále jsme použili autorův soubor definující procesor. (.include“m8def.inc“), který musí být zkopírovaný do složky s projektem. Nyní při kompilaci dochází k jedné nebo více chyb:

	error: Operand(s) out of range in 'ldi r21,0x8005'  (Vkládáme 16-ti bitové slovo do 8-bitového registru...)
ldi bitcount,CRC16poly (Chybný řádek nahradíme...) ldi bitcount,LOW(CRC16poly) (Takhle je to správně...)
Tím překladači přesně definujeme aby použil dolních osm bitů. Nastane-li tento problém i na jiných místech, postupujeme stejně.

Krok 3: Úprava firmware pro inc. soubor AVR studia

Prozatím jsme používali: .include“m8def.inc“, tedy definiční soubor, který vytvořil autor. Chceme-li použít definiční soubor, který obsahuje AVR studio, nahradíme uvozovky ostrými závorkami(.include<m8def.inc>). V tuto chvíli jež nepotřebujeme mít u projektu přiložený soubor atm8def.inc (můžeme jej smazat). Při spuštění kompilace dojde k chybám:

error: Invalid redefinition of 'UCR'
error: Invalid redefinition of 'USR'
error: Invalid redefinition of 'E2END'
Chybové přiřazení:
	.equ	E2END=127
Nahradíme názvy, které je AVR Studio ochotné přijmout, tedy například:
	.equ	EEEND=127
Také musíme zaměnit všechna slova E2END v programu na EEEND.
Ostatní chybové přiřazení:
	.equ	UCR=UCSRB
	.equ	USR=UCSRA

můžeme smazat a všechna slova UCR nahradíme v rámci zdrojového souboru slovem UCSRB a slova USR nahradíme UCSRA. Nyní lze program zkompilovat a nahrát do mikrokontroleru. Vše by mělo fungovat stejně jako v kroku 1.

Krok 4: Program „AVR309USBdemo.exe“

Po spuštění aplikace se zobrazí následující prostředí:

Program
Obr. 5: AVR309USBdemo.exe

Po připojení USB výstraha Device not present!!! zmizí a je možné v prostředí pracovat. Na počátku je vhodné nastavit si port a to pomocí Select data port. K výběru jsou zde 3 porty. Pro daný port je možné další nastavení a to pomocí CheckBoxů. První CheckBox je nazván Data port Out/pullup. Jedná se o nastavení pull-up rezistorů na daném pinu. Druhý CheckBox Data port Direction slouží pro nastavení DDR. Pokud je zatrhnutý, je daný pin nastaven jako výstupní. Pokud jej ponecháme nezatrhnutý, je daný pin nastaven jako vstupní. Třetí CheckBox slouží pro nastavení hodnoty na pinu. Poslední CheckBox je pojmenován LED ON/OFF a funkce se nám nepodařila zjistit.
Dále zařízení obsahuje komunikaci pomocí RS232, které jsme také ověřili. Pomocí SpinEditu jsme nastavili přenosovou rychlost. Po spuštění je přednastavena hodnota 57600 Baud. Pomocí ComboBoxu jsme postupně nastavili počet bitů (lze volit 5-8 bitů v rámci), zabezpečení těchto bitů pomocí paritního bitu a počet stop bitů (volba 0-2 bity). Dále jsme pomocí HyperTerminálu (v prostředí Windows) na připojeném COMu nastavili stejné parametry přenosu, jako v programu AVR309USBdemo.exe. Program zachtával komunikaci do textového pole.
Poslední ověření bylo provedeno na zápisu a čtení do/z paměti EEPROM. Pomocí SpinEditu jsme nastavili velikost paměti a přečetli jsme stav pomocí tlačítka EEPROM read. Do připravené tabulky se načetli hodnoty. Poté jsme provedli změnu přímo v daných buňkách a uložili jsme změnu pomocí tlačítka EEPROM write. Při změně hodnot a opětovného vyvolání dat z paměti se zobrazili námi uložené hodnoty.
Dále je program připraven pro příjem IR kódu. Tento příjem z naší strany nebyl ověřen.

Zdrojový kód

Je také součástí staženého archivu. V adresáři Application\Delphi7 project je vše potřebné. Samotný program je psán v Delphi a využívá knihovnu AVR309.dll. Veškeré funkce z této knihovny jsou popsány v html stránce v adresáři DLL\Doc\AVR309_DLL_help.htm. Funkce je možné také použít v C++ a Visual Basicu. Knihovna obsahuje 20 funkcí a tyto funkce vždy vrací následující hodnoty:

 0- NO_ERROR
 1- DEVICE_NOT_PRESENT
 2- NO_DATA_AVAILABLE
 3- INVALID_BAUDRATE
 4- OVERRUN_ERROR
 5- INVALID_DATABITS
 6- INVALID_PARITY
 7- INVALID_STOPBITS
Příklad funkce pro čtení z paměti EEPROM uvedené v html stránce:
function DoEEPROMRead(Address:byte;var DataInByte:byte):integer;
    //Function reads byte from given address of microcontroller data EEPROM.
Parameters
   Address
        [in] Byte which bits represents address of internal EEPROM (valid address range: 0 to 127).
   DataInByte
        [out] Value from EEPROM.

Return values
    If the function succeeds, the return value is NO_ERROR.
    If the function fails, the return value is DEVICE_NOT_PRESENT (device is disconnected).

V delphi je tato funkce volaná pomocí stisku na tlačítko:

procedure TMainForm.EEPROMReadButtonClick(Sender: TObject);
var
  i:integer;
  DataByte:byte;
begin
  EEPROMStringGrid.Col:=1;//Bereme v uvahu druhy sloupec
  for i:=0 to EEPROMStringGrid.RowCount-1 do //cyklus od 0 do hodnoty na SpinEditu-1
    begin
      if DoEEPROMRead(i,DataByte)=0 then //Funkce vrací pouze hodnotu NO_ERROR=0 nebo DEVICE_NOT_PRESENT=1 
        begin //Funkce DoEEPROMRead proběhla bez chyby
          EEPROMStringGrid.Cells[1,i]:=IntToStr(DataByte);//Na první sloupec i-tý řádek je zapsána hodnota z EEPROM
          EEPROMStringGrid.Row:=i;
        end
      else//Funkce DoEEPROMRead proběhla s chybou
        begin
          raise Exception.Create('Unable to read from EEPROM!'+#13+#10+'(maybe device is not present)');
        end;
    end;
end;

Pokud chceme vidět samotnou funkci, jak je zapsaná, je možné ji otevřít opět v Delphi (nebo pomocí poznámkového bloku). Program samotné knihovny je umístěn v adresáři DLL\Delphi7 project\AVR309.dpr. Funkce DoEEPROMRead vypadá následovně:

//function DoEEPROMRead(Address:word; var DataInByte:byte):integer;  stdcall export;
//V Delphi použijeme pouze :integer;

function DoEEPROMRead(Address:word; var DataInByte:byte):integer;
//;read EEPROM from given address
  begin
    if WaitForSingleObject(SerializationEvent,SerializationEventTimeout)=WAIT_TIMEOUT then
      begin
        ShowThreadErrorMessage;
        Result:=DEVICE_NOT_PRESENT;
        Exit;
      end;
    Result:=DEVICE_NOT_PRESENT;
    OutLength:=1;
    if not SendToDriver(FNCNumberDoEEPROMRead,Address,0,OutputData,OutLength) then
      begin
        SetEvent(SerializationEvent);
        Exit;
      end;
    DataInByte:=OutputData[0];
    Result:=NO_ERROR;
    SetEvent(SerializationEvent);
  end;

V archivu je tedy možné nalézt vše potřebné pro úpravu zdrojových kódů a přidání dalších funkcí. Je možné upravit grafické prostředí AVR309USBdemo, nevyužité funkce mohou být odstraněny a nové přidány relativně jednoduchou cestou.

Krok 5: Úprava firmware pro jiný mikrokontroler řady AVR (v našem případě pro ATmega16)

Komunikace s USB sběrnicí je zajištěna pomocí pinu PB1(OC1A), PB0(ICP) a PD2 (INT0). Alternativní funkce na portu B nejsou využity a proto lze připojit USB sběrnici na jiný mikrokontroler vždy na piny PB0 a PB1. Na portu D je využita alternativní funkce externího přerušení INT0. Proto při změně mikrokontroleru je potřeba najít pin INT0 a připojit signál na něj. Program je napsaný tak, že většina nastavení bitů je přenosná mezi kontrolery. Jediný problém (námi odhalený) by mohl nastat u registru MCUCR, kde je přiřazena hodnota 0x0f. Zde je potřeba zajistit citlivost přerušení INT0 na vzestupnou hranu. Toho lze dosáhnout následujícím:
Původní:

ldi	temp0,0x0f ;INT0 - respond to leading edge
out	MCUCR,temp0
Nahrazeno:
ldi	temp0,(1<<ISC01)|(1<<ISC00) ;INT0 - respond to leading edge
out	MCUCR,temp0

Nakonec stačí změnit .include<m8def.inc> na .include<mxxdef.inc> a program znovu zkompilovat. V našem případě jsme zkoušeli program na mikrokontroleru ATmega16 a vše fungovalo bez nejmenších problémů.

Krok 6: Změna firmware pro jiný krystal

Chceme-li vytvořit aplikaci, která vyžaduje, aby mikrokontroler pracoval na jiném kmitočtu, je nutné upravit i zdrojový kód USB komunikace. (USB komunikace vyžaduje dostatečnou rychlost a proto je dobré pokoušet se připojit krystaly s vyšším rezonančním kmitočtem, než 12 MHz). V projektu lze nalézt několik míst citlivých na časování. Různá zpoždění jsou zajištěna pozdržením jádra procesoru nop instrukcí nebo odečítáním. Například u obsluhy přerušení nalezneme:

ldi	temp0,3		 ;counter of duration log0	
ldi	temp1,2		 ;counter of duration log1

kde konstanty 3 a 2 zajišťují počet čekacích cyklů. Je potřeba je upravit úměrně ke změně frekvence krystalu. Podobných míst v programu je hned několik (v komentáři jsou vždy uvedena keyword wait nebo duration). Během řešení tohoto projektu jsme různě zkoušeli upravovat tato místa, ale zprovoznit komunikaci s krystalem 16 MHz se nám nepodařilo.

Závěr

Komunikace pomocí USB mezi mikrokontrolerem a počítačem je možná mnoha způsoby. V projektu jsme se zaměřili na softwarovou implementaci USB, která již byla naprogramována a je známá pod názvem IgorPlug-USB. Na webových stránkách autora jsme stáhli kompletní projekt pro mikrokontroler ATmega8 a ověřili jsme funkčnost, která proběhla bez jakýchkoliv problémů. Dále jsme upravili tento projekt pro mikrokontroler ATmega16 se stejným krystalem jako u ATmega8 a to 12 MHz, kdy jsme dosáhli stejných výsledků. Po úspěšném předělání na obvod ATmega16 jsme se pokusili upravit frekvenci krystalu na 16 MHz. Tento krok se nám ale nepodařil, protože v programu je použito mnoho zpoždovacích smyček. Proto by bylo nutné přepočítat časově tyto smyčky a upravit je pro rychlejší krystal. Tento krok je nutný, aby byly dodrženy časové posloupnosti protokolu USB.

Literatura

[1] Češko,I http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
[2] Češko,I http://www.cesko.host.sk/downloads/USB%20to%20RS232%20Application%20Note.zip
Soubory staženy 6.4.2010