Jste zde

Softwarová realizace USB

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 - www, kde jsme stáhli zip soubor, který obsahuje vše podstatné. Tento archiv je na zde. Přímo pro stažení je možné použít tento odkaz.

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.

Obr. 1: Schéma pro ATmega8

Obr. 2: Zapojení s ATmega8 funkční-signatura v pořádku

Obr. 3: Nastaveni propojek

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í:

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.

Milan Štohanzl, Pavel Štraus

Odkazy

Hodnocení článku: