UDP komunikace na Zynq/Microblaze (lwip, Vivado, SDK)

Ahoj

momentálně si hraju s jednoduchou udp komunikací na vývojovém desce Zedboard (fpga s hw SoC Zynq, ale práce by měla být stejná jako se soft procesorem Microblazem). Používám naportovanou LwIP knihovnu a vygenerované drivery od Xilinxu.

Ze základního designu jsem si vytvořil projekt s hotovou šablonou obsahující funkční TCP echo server přes raw api. Ten jsem pak překopal na jednoduchý UDP echo server poslouchající na určitém portu . Vše funguje v pořádku.
Narazil jsem na problém, když používám desku jako klient. Jsem schopen odesílat bursty dat, ale vůbec mi nefunguje příjem - resp při přijímání udp datagramu se nevolá příslušný callback.
Wireshark mi vypisuje ICMP zprávu o nedosažitelném portu.

Tady jsou úseky kódu

#define UDP_SERVER_PORT    666 
#define UDP_CLIENT_PORT    666
#define DEST_IP_ADDR0   192
#define DEST_IP_ADDR1   168
#define DEST_IP_ADDR2   1
#define DEST_IP_ADDR3   39


void myudp_client_init(void)
{
    ip_addr_t DestIPaddr;
    err_t err;
    upcb = udp_new();
    if (upcb!=NULL)
    {
        IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
        err= udp_connect(upcb, &DestIPaddr, UDP_SERVER_PORT);
        if (err == ERR_OK)
        {
            /* Set a receive callback */
            udp_recv(upcb, udp_receive_callback, NULL);
            xil_printf("UDP client active> port %d\n\r", UDP_SERVER_PORT);
        }
    }
}

static void myudp_client_send(void)
{
    struct pbuf *p;
    static int counter = 0;
    sprintf((char*)data, "counter>%d", counter++);   //for evaluation of received datagrams
     p = pbuf_alloc(PBUF_TRANSPORT,PAYLOAD_SIZE, PBUF_POOL);
    if (p != NULL)
    {
        pbuf_take(p, (char*)data, PAYLOAD_SIZE);  //PAYLOAD_SIZE 200B to 1000B
        udp_send(upcb, p);
        pbuf_free(p);
    }
}

void udp_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
    xil_printf("client receive callback\n\r");   
    //do something
    pbuf_free(p);
}

v mainu pak jen zavolám inicializaci a ve while kontroluju stisknutý tlačítko, kde se pak volá funkce myudp_client_send().
V síťařině jsem naprostý noob, takže mi určitě něco uniká, ale zatím nevím co :confused:

Ten SoC má v sobě ARMa, do kterýho to cpeš, že? Když ti to na jednom ARMu chodilo, tak není důvod aby po přenesení na jiným ne, takže ho nejspíš někde blbě konfiguruješ (inicializuješ).

Co jsem se tak díval, tak asi to přetahuješ z ARMv7-M (Cortex M4) na ARMv7-A (Cortex A9). Určitě tam nějaký rozdíly budou, když pro to existujou i oddělený reference manuály (už jenom tím, že je to dvoujádro), takže si to budeš muset pořádně projít.

Jestli píšeš pro Microblaze tak potěš koště, s tím ti tady asi nikdo neporadí. Zynq-7000 SoC osobně neznám a vývojové prostředky od Xilinxu taky ne. Jen se mi trochu ježí srst když čtu “vygenerované drivery”…

Edit: Trochu mě to zaujalo tak jsem se malinko porozhlédl. Ty procesory spolu komunikují pomocí nějakých vlastních bridge-ů, tady je k tomu nějaká dokumentace. Nevím jak to přesně pracuje a ležet v tom fakt nebudu, ale nejsem si jistej, jestli s něčím podobným (přesměrování?) ten lwIP stack počítá, protože ten soft procesor asi nepoužívá žádný vlastní HW rozhraní, když žádný nemá, musí mu je “půjčit” ten ARM.

Už jsem to pořešil. Jak jsem psal, “síťařinu se teprv učím…” :smiley: :smiley:
Šlo v módu klienta o to, že přijímané udp pakety neměli platný source port. Utilitka na straně PC, co používám na odesílání definovaných udp/tcp paketů, defaultně vybírá jako zdrojový “volný port”. Zkrátka pokud z desky posílám udp datagram se zdrojovým portem xxx a cílovým portem yyy, tak odpověď od serveru bude mít ty porty přehozené. Já jsem měl cílový port správně, ale zdrojový byl nějkaý náhodný, co zrovna systém vybral.

Rozdíly v použití LWIP mezi platformama nejsou - je to “čisté Céčko” nezávislé na platformě. Liší se to jenom inicializací toho stacku na driver obsluhující mac vrstvu napojenou na fyzickou (nějakej phy čip s rozhráním mii/rmii/gmii/rgmii…). Ten driver je třeba napsat nebo použít od výrobce - ST má jak pro SPL tak pro HAL (ta STCube pičovina) pro jednotlivé mcučka pro uživatele připravený. To samé Xilinx…pro mě to jsou zdrojové molochy, tak jsem to jen převzal a použil podle dostupných příkladů od výrobce.
Pak je s tím práce stejná pro RAW mode. Ty vyšší (prý pohodlnější) módy, co potřebujou nějaký OS jsem nepoužíval - s RTOS mám chabé zkušenosti a nějaké programování s BSD socketama na Linuxu jsem nedělal.

Ano univerzální sběrnice AXI. V Zynqu má ten ARM ještě hardwarový bloky jako je třeba mac kontrolér. GPIO výstupy toho procesoru včetně bloků jsou natvrdo nadrátovaný na nějakej pin čipu (PS část) a nedájí se překonfigurovat jako u programovatelné logiky fpga části (PL část).
Soft procesor microblaze je vytvořenej v PL logice a defaultně k sobě tyto kontroléry nemá. Nijak mu nemůžeš nadrátovat ve volné PL logice tu hardwarovou PS část ARMu. Proto se mu musí ve volné PL části vytvořit MAC kontrolér s převodníkem na RMII (GMII v případě gigabitovýho ethernetu) nebo jeho obdoby. Vím, že existujou fpga free IP cores, co řeší čistě udp komunikaci, takže není potřeba použít lwip stack. TOhle je pro microblaze optimálnější řešení, protože ten procesor může tiká na PL části (max 200-300 MHz, zatímco ten hw ARM v Zynqu dělaj od 666MHz do 1GHz). Já ale VHDLkař nejsem, takže od toho zatím ruce držím pryč a hraju si jenom s procesorovou částí toho SoC čipu.