Zedboard+Vivado环境下PL数据经以太网传输至PC方案咨询
Hey Upasana, great to hear you’ve already nailed the PL-to-PS data reading and terminal output—you’re halfway there! Here’s a practical, step-by-step breakdown to get those 32-bit values sent over Ethernet to your PC:
方案1:PS端运行Linux系统(最便捷,推荐)
Zedboard plays nicely with Linux (Petalinux or pre-built images), and standard socket programming makes this straightforward.
Step 1: Configure Ethernet on Linux
- Build or flash a Linux image for your Zedboard (Petalinux is ideal for custom setups). Ensure the Ethernet driver is enabled (it’s usually on by default).
- Boot the board, then set a static IP on the same subnet as your PC. For example:
Set your PC’s IP to something likeifconfig eth0 192.168.1.10 netmask 255.255.255.0192.168.1.20and confirm connectivity with aping 192.168.1.20from the Zedboard.
Step 2: Write a C Program to Read & Send Data
You’ll need to map the PL’s physical register address to user space, then send the data over TCP:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdint.h> #define REG_PHYS_ADDR 0x43c00000 #define REG_SIZE 4 // 32-bit register int main() { // Map PL register to user space int mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd < 0) { perror("Failed to open /dev/mem"); return -1; } volatile uint32_t *reg_ptr = mmap(NULL, REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, REG_PHYS_ADDR); if (reg_ptr == MAP_FAILED) { perror("MMAP failed"); close(mem_fd); return -1; } // Create TCP socket int sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd < 0) { perror("Socket creation failed"); return -1; } struct sockaddr_in pc_addr; pc_addr.sin_family = AF_INET; pc_addr.sin_port = htons(8080); // Pick any unused port pc_addr.sin_addr.s_addr = inet_addr("192.168.1.20"); // Your PC's IP // Connect to PC if (connect(sock_fd, (struct sockaddr *)&pc_addr, sizeof(pc_addr)) < 0) { perror("Connection to PC failed"); return -1; } // Loop to read and send data while(1) { uint32_t value = *reg_ptr; printf("Sending value: %u\n", value); send(sock_fd, &value, sizeof(value), 0); sleep(1); // Adjust interval as needed } // Cleanup (you'll never reach this, but good practice) munmap((void*)reg_ptr, REG_SIZE); close(mem_fd); close(sock_fd); return 0; }
- Cross-compile this code using Petalinux’s toolchain or Xilinx SDK, then transfer it to the Zedboard (via
scpor SD card).
Step 3: PC-side Receiver
Use a simple Python script to listen for incoming data:
import socket HOST = '0.0.0.0' # Listen on all interfaces PORT = 8080 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: print(f"Connected to Zedboard at {addr}") while True: data = conn.recv(4) if not data: break # Zynq is little-endian; adjust if your system uses big-endian value = int.from_bytes(data, byteorder='little') print(f"Received value: {value}")
Run the PC script first, then execute the program on the Zedboard—you’ll start seeing values pop up!
方案2:PS端裸机运行(Xilinx LWIP Library)
If you don’t want Linux, use Xilinx’s LWIP stack for bare-metal Ethernet communication:
Step 1: Configure Hardware in Vivado
- Enable the PS’s Ethernet0 interface and confirm MIO pin mappings (Zedboard’s Ethernet pins are pre-configured by default).
- Generate the bitstream and export the hardware design to Xilinx SDK.
Step 2: Set Up SDK Project
- Create a bare-metal application project, then add the LWIP library to your project.
- Modify
lwipopts.hto set your Zedboard’s IP, subnet mask, and gateway (match your PC’s subnet).
Step 3: Bare-Metal Code Example
Directly access the PL register and send data over TCP:
#include "xil_printf.h" #include "lwip/tcp.h" #include "stdint.h" #define REG_ADDR ((volatile uint32_t *)0x43c00000) #define PC_IP "192.168.1.20" #define PC_PORT 8080 static err_t tcp_send_callback(void *arg, struct tcp_pcb *pcb, err_t err) { (void)arg; (void)err; return ERR_OK; } void send_pl_data(void) { struct tcp_pcb *pcb; err_t err; ip_addr_t pc_ip; // Initialize TCP connection pcb = tcp_new(); if (!pcb) { xil_printf("Failed to create TCP PCB\n"); return; } IP4_ADDR(&pc_ip, 192, 168, 1, 20); err = tcp_connect(pcb, &pc_ip, PC_PORT, tcp_send_callback); if (err != ERR_OK) { xil_printf("TCP connect failed: %d\n", err); return; } // Loop to read and send data while(1) { uint32_t value = *REG_ADDR; xil_printf("Sending: %u\n", value); tcp_write(pcb, &value, sizeof(value), TCP_WRITE_FLAG_COPY); tcp_output(pcb); sleep(1); } } int main() { lwip_init(); send_pl_data(); return 0; }
- Reference Xilinx’s LWIP example projects to handle timers and network stack initialization properly—bare-metal requires a bit more setup for LWIP to run smoothly.
Quick Tips
- Byte Order: Zynq uses little-endian format. Most PCs do too, but if you see garbled values, use
ntohl()(for network-to-host byte order) in your receiver code. - Reliability: Use TCP for guaranteed delivery, or UDP if you prioritize speed over perfect reliability.
- Debugging: If Ethernet fails, first ping between the Zedboard and PC. On Linux, check
ifconfig eth0to confirm the interface is up. On bare-metal, use SDK’s debug console to check network initialization logs.
内容的提问来源于stack exchange,提问作者upasana




