Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2017:microblaze-lwip

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revize Předchozí verze
Následující verze
Předchozí verze
2017:microblaze-lwip [2018/01/14 14:49]
Tomáš Svoboda
2017:microblaze-lwip [2018/01/14 20:43] (aktuální)
Tomáš Svoboda
Řádek 12: Řádek 12:
  
 ====== Úvod ====== ====== Úvod ======
-Cílem tohoto projektu je implementovat lwIP stack na 32bitový soft procesor Microblaze. lwIP stack je volně dostupný TCP/IP stack, který v sobě zahrnuje podporu mnoha protokolů - IP (jak IPv4, tak IPv6), TCP, UDP, apod., tak i klientů jako DHCP či DNS, volitelně pak HTTP či TFTP server. V rámci tohoto projektu je pozornost zaměřena především na protokol UDP. Samotný lwIP stack vyžaduje minimální nároky, mj. je dostupná i light verze, ​velká část ​potřebné paměti je dána velikostí odesílacího,​ resp. přijímacího bufferu. ​+Cílem tohoto projektu je implementovat lwIP stack na 32bitový soft procesor Microblaze. lwIP stack je volně dostupný TCP/IP stack, který v sobě zahrnuje podporu mnoha protokolů - IP (jak IPv4, tak IPv6), TCP, UDP, apod., tak i klientů jako DHCP či DNS, volitelně pak HTTP či TFTP server. V rámci tohoto projektu je pozornost zaměřena především na protokol UDP. Samotný lwIP stack vyžaduje minimální nároky, mj. je dostupná i light verze, ​otázka ​potřebné paměti je dána velikostí odesílacího,​ resp. přijímacího bufferu. ​
  
-Microblaze je 32bitový ​ soft procesors RISC instrukční sadou, dostupný jako IP jádro pro FPGA Xilinx (vč. rodiny Zynq, která má i hardwarový ARM procesor). Je vytvořen za použití prostředků samotné struktury FPGA. Z hlediska konfigurace jsou možnosti poměrně bohaté - velikosti instrukční a datové cache, lokální paměť, násobičky,​ děličky, breakpointy,​ apod. Pro potřeby tohoto projektu není většina bloků využita - především pro úsporu samotných FPGA prostředků. ​+[[https://​www.xilinx.com/​products/​design-tools/​microblaze.html|Microblaze]] je 32bitový ​ soft procesors RISC instrukční sadou, dostupný jako IP jádro pro FPGA Xilinx (vč. rodiny Zynq, která má i hardwarový ARM procesor). Je vytvořen za použití prostředků samotné struktury FPGA. Z hlediska konfigurace jsou možnosti poměrně bohaté - velikosti instrukční a datové cache, lokální paměť, násobičky,​ děličky, breakpointy,​ apod. Pro potřeby tohoto projektu není většina bloků využita - především pro úsporu samotných FPGA prostředků. ​
  
-V rámci řešení se předpokládá odesílání dat z paměti typu BRAM do počítače skrze protokol UDP. V počítači pak otestovat příjem pomocí programu Wireshark nebo zápis do *.txt/*.csv souboru za využití skriptovacího jazyka Python. Data uložená v paměti BRAM budou představovat fiktivní data, která budou v pozdějším využití (mimo tento projekt) nahrazena ​samotnými ​vzorky získanými z A/D převodníku.+V rámci řešení se předpokládá odesílání dat z paměti typu [[https://​www.xilinx.com/​products/​intellectual-property/​block_ram.html|BRAM]] do počítače skrze protokol UDP. V počítači pak otestovat příjem pomocí programu Wireshark nebo zápis do *.txt/*.csv souboru za využití skriptovacího jazyka Python. Data uložená v paměti BRAM budou představovat fiktivní data, která budou v pozdějším využití (mimo tento projekt) nahrazena ​skutečnými ​vzorky získanými z A/D převodníku. ​
  
 V rámci řešení je tedy nutno: V rámci řešení je tedy nutno:
Řádek 44: Řádek 44:
   ​   ​
 ====== Realizace ====== ====== Realizace ======
-Na obrázku 2 je znázorněna realizace. Základ tvoří samotná vývojová deska osazená obvodem FPGA. Na obvodu ja realizován samotný procesor, Bloková RAM (BRAM), patřičné ​kontroly ​pro přístup k paměti a MAC jádro (Medium Access Controller). V rámci procesoru jsou pak mj. využity především knihovny pro samotný lwIP stack, SPI komunikaci a UART, případně obsluha GPIO. Z externí obvodů dostupných na desce je využita DDR paměť (vyžaduje lwIP stack), převodník USB/UART - využito pro ladící výstupy, obvod fyzické vrstvy Ethernetu (rozhraní RGMII) a Flash paměť. Ve Flash paměti je uložena jedinečná MAC adresy v OTP registru, paměť používá SPI rozhraní. Posledním článkem je počítač - zde je spuštěn Python skript, který přijímá jednotlivé UDP datagramny, separuje jednotlivé vzorky a ukládá je do souboru typu CSV (data oddělená čárkou). ​+Na obrázku 2 je znázorněna realizace. Základ tvoří samotná vývojová deska osazená obvodem FPGA. Na obvodu ja realizován samotný procesor, Bloková RAM (BRAM), patřičné ​bloky pro přístup k paměti a MAC jádro (Medium Access Controller). V rámci procesoru jsou pak mj. využity především knihovny pro samotný lwIP stack, SPI komunikaci a UART, případně obsluha GPIO. Z externí obvodů dostupných na desce je využita DDR paměť (vyžaduje lwIP stack), převodník USB/UART - využito pro ladící výstupy, obvod fyzické vrstvy Ethernetu (rozhraní RGMII) a Flash paměť. Ve Flash paměti je uložena jedinečná MAC adresy v OTP registru, paměť používá SPI rozhraní. Posledním článkem je počítač - zde je spuštěn Python skript, který přijímá jednotlivé UDP datagramny, separuje jednotlivé vzorky a ukládá je do souboru typu CSV (data oddělená čárkou). ​
  
 {{ :​2017:​lwip_stack:​impelemntace_mpoa(1).png?​700 |}} {{ :​2017:​lwip_stack:​impelemntace_mpoa(1).png?​700 |}}
 **Obr.2** Blokové znázornění realizace **Obr.2** Blokové znázornění realizace
 +
 +Programování samotného procesoru probíhá v jazyce C (lze i C++) v prostředí SDK, není tak nutno zasahovat do popisu ve VHDL. V rámci VHDL je vytvořen pouze tzv, HDL wrapper -"​black box", který má patřičné vstupy a výstupy. ​
   ​   ​
 ==== Generovaná data pro paměť ==== ==== Generovaná data pro paměť ====
-Následujícím kódem je pomocí Matlabu vygenerováno celkem 200 000 vzorků data, data představují v tomto případě sinusovku (v absolutní hodnotě). Šířka dat je 32 bitů, což odpovídá nastavení šířce paměti BRAM (taktéž 32 bitů). Parametr radix na prvním řádku udává v jakém vyjádření data jsou, v tomto případě se jedná o desítkovou soustavu. Formát souboru je typu *.coe, jeho struktura je dána. Primárně slouží pro uložení koeficientů ​pro realizaci digitálních filtrů, nicméně ho lze použít i pro tyto účely. Takto vytvořený soubor lze již přímo použít v rámci vývojového prostředí Vivado.+Následujícím kódem je pomocí Matlabu vygenerováno celkem 200 000 vzorků data, data představují v tomto případě sinusovku (v absolutní hodnotě). Šířka dat je 32 bitů, což odpovídá nastavení šířce paměti BRAM (taktéž 32 bitů). Parametr radix na prvním řádku udává v jakém vyjádření data jsou, v tomto případě se jedná o desítkovou soustavu. Formát souboru je typu *.coe, jeho struktura je dána. Primárně slouží pro uložení koeficientů ​při realizaci digitálních filtrů, nicméně ho lze použít i pro tyto účely. Takto vytvořený soubor lze již přímo použít v rámci vývojového prostředí Vivado.
 <​code>​ <​code>​
 header1 = '​memory_initialization_radix=10;';​ header1 = '​memory_initialization_radix=10;';​
Řádek 108: Řádek 110:
 === Inicializace rozhraní=== === Inicializace rozhraní===
  
-V rámci funkce **eth_init()** je vyčtena MAC adresa, nastaveny patřičné IP adresy (pokud se nevyužije DHCP), inicializován lwIP stack, přiřazení rozhraní pro obsluhu MAC jádrem (obstarává FPGA), zprovozněno patřičné rozhraní, a konečně, pokud je využit DHCP) získána IP adresa desky, maska a adresa síťového rozhraní (gateway). V případě DHCP se pokouší získat IP adresa, pokud je po vypršení času adresa nulová (=adresu se nepodařilo získat) je nastavena adresa defaultní. Funkce pro DHCP jsou překládány pouze v případě, že je DHCP využit (podmíněný překlad).+V rámci funkce **eth_init()** je vyčtena MAC adresa, nastaveny patřičné IP adresy (pokud se nevyužije DHCP), inicializován lwIP stack, přiřazení rozhraní pro obsluhu MAC jádrem (obstarává FPGA), zprovozněno patřičné rozhraní, a konečně, ​(pokud je využit DHCP) získána IP adresa desky, maska a adresa síťového rozhraní (gateway). V případě DHCP se pokouší získat IP adresa, pokud je po vypršení času adresa nulová (=adresu se nepodařilo získat) je nastavena adresa defaultní. Funkce pro DHCP jsou překládány pouze v případě, že je DHCP využit (podmíněný překlad).
  
 <code c> <code c>
Řádek 170: Řádek 172:
  
 ==== Čtení z paměti, plnění bufferu a odesílání dat ==== ==== Čtení z paměti, plnění bufferu a odesílání dat ====
-Pro odeslání dat je vytvořena funkce **udp_transfer()**,​ ta je aktuálně volána z hlavní smyčky ve funkci main po stisku tlačítka. Funkce je blokující,​ tzn. že se vrací zpět to funkce main po odeslání všech dat z paměti. V cílové aplikaci bude ve funkci main pouze pouze konfigurace A/D převodníky ​(bez jeho další obsluhy) a zasílání dat, v tomto případě není třeba vykonávat po dobu odesílání jiné instrukce. ​+Pro odeslání dat je vytvořena funkce **udp_transfer()**,​ ta je aktuálně volána z hlavní smyčky ve funkci main po stisku tlačítka. Funkce je blokující,​ tzn. že se vrací zpět to funkce main po odeslání všech dat z paměti. V cílové aplikaci bude ve funkci main pouze pouze konfigurace A/D převodníku ​(bez jeho další obsluhy) a zasílání dat, v tomto případě není třeba vykonávat po dobu odesílání jiné instrukce. Přístup do BRAM zajišťuje [[https://​www.xilinx.com/​products/​intellectual-property/​axi_bram_if_ctlr.html|AXI BRAM Controller]].
  
 <code c> <code c>
Řádek 228: Řádek 230:
 Data z BRAM jsou při odesílání postupně rozdělena do bloků velikosti 1024 Bytů, pokud má slovo v paměti šířku 32 bitů, je tedy naráz odesláno 256 vzorků. Teoreticky lze však může být blok velký až 65 507 Bytů nebo i větší při použití JumboFramu (lwIP jej podporuje). Jelikož je UDP nespolehlivý protokol, je třeba volit kompromis mezi přijatelnou ztrátou a zbytečnou režií při malém užitečném obsahu v rámci. ​ Data z BRAM jsou při odesílání postupně rozdělena do bloků velikosti 1024 Bytů, pokud má slovo v paměti šířku 32 bitů, je tedy naráz odesláno 256 vzorků. Teoreticky lze však může být blok velký až 65 507 Bytů nebo i větší při použití JumboFramu (lwIP jej podporuje). Jelikož je UDP nespolehlivý protokol, je třeba volit kompromis mezi přijatelnou ztrátou a zbytečnou režií při malém užitečném obsahu v rámci. ​
  
-Parametr XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR udává první dostupnou přístupnou adresu. Při ladění však bylo zjištěno, že první vzorek je až na druhé pozici v paměti, proto. Funkce postupně ukládá do bufferu buffer_send jednotlivé "​vzorky"​ z paměti, v okamžiku dosažení nastavených počtu vzorků v jednom paketu (SAMPLES_IN_PACKET) je alokován ​bufferu ​lwipu stacku a data jsou předána k odeslání. V případě, že poslední paket není zcela naplněn, zůstávají na posledních pozicích předešlá data, to je řešeno už snadno v aplikaci na PC. +Parametr XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR udává první dostupnou přístupnou adresu. Při ladění však bylo zjištěno, že první vzorek je až na druhé pozici v paměti, proto za zaveden "​offset"​. Funkce postupně ukládá do bufferu buffer_send jednotlivé "​vzorky"​ z paměti, v okamžiku dosažení nastavených počtu vzorků v jednom paketu (SAMPLES_IN_PACKET) je alokován ​buffer ​lwipu stacku a data jsou předána k odeslání. V případě, že poslední paket není zcela naplněn, zůstávají na posledních pozicích předešlá data, to je řešeno už snadno v aplikaci na PC. 
  
 Oproti klasické aplikaci, kde jsou data odesílána kontinuálně (například konvertor) nebo je známa pozice posledního uloženého vzorku ve formě ukazatele, je v této aplikaci odeslána pevný počet vzorků. V cílové aplikaci pak bude ukazatel na poslední uložený vzorek znám. ​ Oproti klasické aplikaci, kde jsou data odesílána kontinuálně (například konvertor) nebo je známa pozice posledního uloženého vzorku ve formě ukazatele, je v této aplikaci odeslána pevný počet vzorků. V cílové aplikaci pak bude ukazatel na poslední uložený vzorek znám. ​
Řádek 242: Řádek 244:
 Příklad možných nastavení v rámci BSP: Příklad možných nastavení v rámci BSP:
  
-{{ :​2017:​lwip_stack:​bsp_lwip.png?​600 |}}+{{ :​2017:​lwip_stack:​bsp_lwip.png?​800 |}}
  
-**Obr. 3** Možná ​nastavená ​lwIP stacku v rámci BSP+**Obr. 3** Možná ​nastavení ​lwIP stacku v rámci BSP
  
  
Řádek 251: Řádek 253:
 Funkčnost zasílání dat přes protokol UDP byla ověřena jak aplikací Wireshark, tak i pomocí skriptu napsaném v jazyce Python. ​ Funkčnost zasílání dat přes protokol UDP byla ověřena jak aplikací Wireshark, tak i pomocí skriptu napsaném v jazyce Python. ​
  
-{{ :​2017:​lwip_stack:​wireshark_output.png?​1000 |}} +Na obrázku ​jsou zobrazeny detailní informace o prvním přijatém paketu (v prvním paketu lze najít k porovnání očekávaná data). Konkrétně:​
-**Obr. 4** Zachycené pakety programem Wireshark +
- +
-Na obrázku ​jsou zobrazeny detailní informace o prvním přijatém paketu (v prvním paketu lze najít k porovnání očekávaná data). Konkrétně:​+
   * Délka rámce 1066 B, z toho délka UDP datagramu 1032 B, a z toho užitečných dat 1024 B. Hodnota 1024 B správně představuje celkem 256 32bitových vzorků.   * Délka rámce 1066 B, z toho délka UDP datagramu 1032 B, a z toho užitečných dat 1024 B. Hodnota 1024 B správně představuje celkem 256 32bitových vzorků.
   * Adresa TCP portu 50000   * Adresa TCP portu 50000
Řádek 261: Řádek 260:
   * první data tvoří skutečně první vzorky uložené v paměti (134930, ...) - Little endian.   * první data tvoří skutečně první vzorky uložené v paměti (134930, ...) - Little endian.
  
 +{{ :​2017:​lwip_stack:​wireshark_output.png?​1000 |}}
 +**Obr. 4** Zachycené pakety programem Wireshark
  
-Pro Python skript je použito prostředí Spyder (dnes Anaconda). Jedná se o skriptovací jazyk, není zde standardní kompilace, tak, jak je tomu například u C++ nebo C#. K vykonávání programu je třeba tzv. interpret. Existuje i možnost vytvořit spustitelný soubor, stejně tak je možné vytvořit patřičné GUI. 
-Využita je knihovna Socket (podporuje UDP i TCP). Skript čte ve smyčce přijímací buffer. Funkce socket vrací data jako tzv. bytearray, je tedy nutno vždy seskupit 4 B pro 32bitovou proměnou integer. Data jsou ukládána do CSV souboru společně s "​pořadovým"​ číslem vzorků - lze nehradit například časem. 
  
 +Pro Python skript je použito prostředí Spyder (dnes Anaconda). Jedná se o skriptovací jazyk, není zde standardní kompilace, tak, jak je tomu například u C++ nebo C#. K vykonávání programu je třeba tzv. interpret. Existuje i možnost jak vytvořit spustitelný soubor, stejně tak je možné vytvořit patřičné GUI.
 +Využita je knihovna Socket (podporuje UDP i TCP). Skript čte ve smyčce přijímací buffer. Funkce socket vrací data jako tzv. bytearray, je tedy nutno vždy seskupit 4 B pro 32bitovou proměnou integer. Data jsou ukládána do CSV souboru společně s "​pořadovým"​ číslem vzorku - lze nahradit například časem. Skript končí po vypršení timeoutu, kdy již nejsou zasílána další data.
 +
 +<code python>
 +import socket
 +import csv
 +import struct
 +
 +
 +host="​0.0.0.0"​
 +port = 50000
 +samples = 200000
 +
 +csvf = '​test.csv'​
 +
 +s = socket.socket(socket.AF_INET,​socket.SOCK_DGRAM)
 +s.bind((host,​port))
 +
 +addr = (host,port)
 +buf=10000000
 +array=[]
 +
 +sample=1;
 +with open(csvf, '​w',​ newline='',​ encoding='​ascii'​) as csv_handle:
 +    csv_writer = csv.writer(csv_handle,​ delimiter=','​)
 +    data,addr = s.recvfrom(buf)
 +    try:
 +        while(data):​
 +            length=(len(data))
 +            x=0
 +            for i in range(0,​length//​4):​
 +              value=struct.unpack("​I",​ bytearray(data[x:​x+4]))
 +              array.append(value)
 +              data_list=[x for xs in array for x in xs]
 +              data_list.append(sample)
 +              sample=sample+1
 +              array=[]
 +              csv_writer.writerow(data_list)
 +              x=x+4
 +              s.settimeout(5)
 +              if (sample==samples+1):​
 +                  break;
 +            data,addr = s.recvfrom(buf)
 +    except (socket.timeout,​KeyboardInterrupt,​ SystemExit):​
 +        print ("​Operation completed"​)
 +        raise
 +</​code>​
 ------- -------
  
Řádek 279: Řádek 325:
 Byť se v rámci internetu nepodařilo nalézt vhodné inspirativní kódy s využitím TCP nebo UDP, ukázalo se použití lwIP stacku, po seznámení s jeho knihovnami, jako poměrně jednoduché. Po stránce hardwarové nakonec nebylo zapotřebí řešit speciální konfiguraci obvodu fyzické vrstvy, pokud se spokojíme s rychlostí 100Mbit (nutno nastavit v rámci konfigurace BSP).  Byť se v rámci internetu nepodařilo nalézt vhodné inspirativní kódy s využitím TCP nebo UDP, ukázalo se použití lwIP stacku, po seznámení s jeho knihovnami, jako poměrně jednoduché. Po stránce hardwarové nakonec nebylo zapotřebí řešit speciální konfiguraci obvodu fyzické vrstvy, pokud se spokojíme s rychlostí 100Mbit (nutno nastavit v rámci konfigurace BSP). 
  
-V rámci další práce se počítá s využitím RTOS (Free RTOS) a implementací protokolu TCP namísto protokolu UDP, případně zvýšení ​rychlsoti ​na 1Gbit, bude-li to třeba.+V rámci další práce se počítá s využitím RTOS (Free RTOS) a implementací protokolu TCP namísto protokolu UDP, případně zvýšení ​rychlosti ​na 1Gbit, bude-li to třeba. Počítáno je rovněž s rozšířením aplikace v Pythonu - větší možnosti konfigurace a GUI.
  
 Použitá vývojová prostředí:​ Spyder (Python), Vivado, SDK Eclipse (C), Matlab Použitá vývojová prostředí:​ Spyder (Python), Vivado, SDK Eclipse (C), Matlab
Řádek 292: Řádek 338:
 ====== Reference ====== ====== Reference ======
 [1] lwIP Stack dokumentace:​ http://​www.nongnu.org/​lwip/​2_0_x/​group__udp__raw.html [1] lwIP Stack dokumentace:​ http://​www.nongnu.org/​lwip/​2_0_x/​group__udp__raw.html
- 
  
 [2] UDP komunikace v Pythonu: https://​wiki.python.org/​moin/​UdpCommunication [2] UDP komunikace v Pythonu: https://​wiki.python.org/​moin/​UdpCommunication
2017/microblaze-lwip.1515937776.txt.gz · Poslední úprava: 2018/01/14 14:49 autor: Tomáš Svoboda