☰
MicroBlaze软核TCP服务器:FPGA千兆以太网与IPv6双栈实战
2026/9/25 4:35:21 网站建设 项目流程

拿到米联客MA703FA开发板之后,我大概花了两周才从“只会点灯”过渡到“能联网”。原因倒不是MicroBlaze难学,而是网上的教程基本都停在UART和FIFO,真正能把千兆以太网服务器跑起来、并且把IPv6一并打开的完整案例少之又少。这篇实战记录就是来补这个缺口的:我会用Vivado 2018.3 + SDK,在这块Artix-7板卡上搭建一个基于MicroBlaze软核的TCP服务器,底层走AXI Ethernet与AXI DMA,协议栈用lwIP,并重点演示IPv6双栈的开启方式与调试方法。做完之后,这个板子就从一个FPGA学习板变成了一台可以挂在交换机上的微型服务器,支持通过IPv4或IPv6地址远程访问,能做的事一下子就多了。不管是FPGA入门者、想跑软核网络协议的嵌入式工程师,还是正在做设备远程采集的DIY玩家,这篇记录都值得你从头读到尾。

1. 选型判断:MA703FA为什么适合做MicroBlaze网络服务器

1.1 板卡核心资源盘点

MA703FA在米联客的Artix-7产品线里属于“麻雀虽小五脏俱全”的型号。我手头这块的关键参数如下:

项目规格
FPGAXC7A35T-2FGG484I,逻辑单元33K,Block RAM约1800Kb,DSP48E1共90个
板载DDR3一颗DDR3,容量因批次而异,我手上是256MB
千兆PHYRealtek RTL8211FD,RGMII接口,支持10/100/1000M自适应
串口USB-UART,用于调试和日志
其他外设HDMI、SD卡、SPI Flash、LED、按键、扩展排针

这里要特别提一下扩展排针。很多资料把MA703FA的大部分IO都引到了排针上,意味着RGMII这类高速信号如果走线质量不够理想,是跑不稳千兆的。所以这个项目里要老老实实用板载RTL8211FD,千万不要为了省事自己飞线接PHY,飞线出来的高速信号光是时序和串扰就够折腾几天。板载PHY的走线是米联客画好且验证过的,MII/RGMII引脚约束也是现成的,这是能快速跑通网络的关键。

1.2 为什么选MicroBlaze软核而不是硬核

很多朋友第一反应是:要做以太网服务器,为什么不用Zynq的硬核ARM或者干脆上一块Linux开发板?这个说法没毛病,但要看场景。MZ7030、Zynq这类带硬核的芯片,优势是能跑完整Linux,性能强,可开发复杂度、成本和学习门槛也明显更高。

MicroBlaze是Xilinx的软核处理器,本质上是FPGA里用LUT和BRAM“搭”出来的CPU。选择它的核心原因有三个:

  1. 身在FPGA工程里,和自定义逻辑的交互最自然。网络协议栈、软件代码可以和Verilog/VHDL硬件模块共享同一片FPGA,不用像Zynq那样在PS和PL之间来回考虑接口。
  2. 学习价值高。搭一个包含AXI总线、DMA、中断控制器、外设IP的完整SoC,能够把计算机体系结构里“CPU怎么通过总线访问外设”这个抽象概念彻底落地。
  3. 成本低。很多入门级Artix-7板卡都能跑MicroBlaze,MA703FA属于比较经济的选择。

当然,软核的缺点也非常明显:CPU主频只有100到200MHz,跑TCP/IP协议栈时吞吐量远达不到千兆线速。软核方案从来不是为了跑满千兆,而是为了在硬件逻辑和网络功能之间找一个平衡点。

1.3 三种以太网实现路径的取舍

开始动手前,我把可能的实现路径都列了一遍:

方案特点适用场景
AXI Ethernet Lite内部带FIFO,通过AXI4-Lite直接读写,无需DMA简单、小型,百兆量级性能,适合熟悉协议栈
AXI Ethernet + AXI DMA + lwIP千兆数据通路,DMA搬运帧,CPU只处理协议栈追求性能、要跑TCP/IP的正式方案
自定义MAC + 用户逻辑直接处理帧完全自己控制,但TCP/IP栈基本没法复现只做自定义帧协议的场景

我最终选择的是第二套:AXI Ethernet(全功能版本)+ AXI DMA + lwIP协议栈。这是Xilinx官方支持和维护最成熟的一条路线,SDK里甚至直接提供了lwIP的模板工程,省去大量从零移植的体力活。

2. Vivado硬件工程搭建:MicroBlaze与RGMII时钟的联动关系

2.1 Block Design的IP清单与数据通路

打开Vivado 2018.3,新建工程后先创建一个Block Design。这个设计里需要放到Block Design里的IP如下:

MicroBlaze (100MHz) ├── AXI Interconnect │ ├── AXI DMA │ │ └── AXI Ethernet (RGMII 1G) │ ├── AXI UartLite │ ├── AXI Timer │ ├── AXI GPIO │ ├── AXI Intc │ └── DDR3控制器 或 BRAM控制器 └── LMB总线 -> 本地存储器

数据通路的逻辑是:以太网PHY收到的RMII/RGMII信号进入AXI Ethernet核,转为AXI-Stream流,再由AXI DMA搬运到内存(DDR3或BRAM),MicroBlaze跑lwIP协议栈对内存中的帧做处理;发送方向则完全反过来。

2.2 时钟设计:100MHz、125MHz、200MHz各管什么

这是整个硬件工程里最容易翻车的地方。MA703FA的MicroBlaze系统里至少需要三路时钟:

  • CPU和大部分AXI外设时钟:100MHz,给MicroBlaze、AXI Interconnect、AXI DMA、AXI UartLite等使用。
  • AXI Ethernet的GTX时钟:125MHz,用于RGMII接口的125MHz发送时钟。千兆以太网的RGMII模式,收发时钟都是125MHz,数据在时钟上下沿都采样。
  • IDELAYCTRL参考时钟:200MHz。AXI Ethernet在RGMII模式下需要IDELAYCTRL来控制RX路径上的延时,这个200MHz参考时钟必须连上。很多朋友做完硬件发现收不到数据或者丢包严重,往往是忘了给idelay_ctrl_refclk接时钟。

我在Block Design里用了一个Clocking Wizard,输出三路时钟:clk_out1(100MHz)、clk_out2(125MHz)、clk_out3(200MHz)。其中125MHz给axi_ethernet_0/gtx_clk,200MHz给axi_ethernet_0/idelay_ctrl_refclk,100MHz给MicroBlaze和AXI外设。

还要注意复位逻辑。AXI Ethernet的phy_rst_n是输出引脚,接到RTL8211FD的复位脚。这个复位信号在Block Design里通过AXI GPIO控制会更灵活,但如果你不想用GPIO,也可以直接把phy_rst_n引出去。我习惯用GPIO控制,这样软件里可以随时给PHY做硬复位。

2.3 AXI DMA、中断与PHY复位的连接

AXI DMA在这里承担数据搬运工作,它的mm2s_introut和s2mm_introut两个中断要连接到AXI Intc的不同输入通道。MicroBlaze的interrupt信号接AXI Intc的输出。除此之外,UartLite、Timer的中断也要一并接进来。这里有个经验:中断引脚顺序会决定SDK里XPAR_AXI_INTC_0_..._VEC_ID的编号,连线时尽量按固定顺序排好,不然查问题的时候脑子容易乱。

PHY复位建议用AXI GPIO(比如gpio0)输出控制。MA703FA板上有PHY复位引脚,Low有效,软件里先拉低至少10ms再释放,确保PHY完成上电初始化。我踩过坑:上电后立刻访问PHY寄存器,经常读到不确定的值,就是因为PHY还没完成内部自检。

2.4 引脚约束与上板前检查清单

引脚约束来自MA703FA的原理图。RGMII接口在Block Design里作为外部端口引出后,需要逐个约束到FPGA引脚,并设置IO电平标准。典型的约束片段如下:

set_property PACKAGE_PIN T23 [get_ports {rgmii_txd[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {rgmii_txd[0]}] # 其余rgmii_txd、rgmii_rxd、rgmii_tx_ctl、rgmii_rx_ctl、rgmii_rxc、rgmii_txc # mdio、mdc、phy_rst_n等信号同理

注意,RGMII信号的电平标准要看板卡PHY侧的供电,MA703FA的PHY侧通常是3.3V或2.5V。盲目照抄别人的约束很可能烧PHY或者跑不稳。生成比特流并下载后,上板前先检查三件事:

  1. PHY复位引脚电平是否正常,链路Link灯是否点亮。
  2. 用调试工具或串口打印读MDIO寄存器,确认CPU能通过MDIO访问到PHY。
  3. 插上网线,看PHY是否协商上千兆。如果PHY只协商成100M,优先怀疑125MHz时钟或者RGMII延时配置。

3. SDK工程:lwIP协议栈的双栈配置与TCP服务器骨架

3.1 创建BSP时选择lwIP版本和IPv6选项

硬件导出后打开SDK,新建一个Application Project,选择Empty Application。在Board Support Package设置里,重点是给BSP添加lwIP库。

Vivado 2018.3的SDK里通常提供两个lwIP版本:lwip141和lwip202。建议选lwip202,它对IPv6的支持要完整得多。lwIP 1.4.1虽然也能开IPv6,但很多细节和后续更新都不如2.0.x。

BSP界面里有一个“ipv6”的配置项,把它勾上。如果在界面里找不到这项,也别慌,后面直接改lwipopts.h也行。改完BSP后点重新生成,再右键应用工程选择到新BSP上。

3.2 lwipopts.h里的关键开关

打开BSP包里的lwipopts.h,这是整个lwIP协议栈的配置总闸。针对双栈服务器,我一般会确认以下几个宏:

#define LWIP_IPV6 1 // 开启IPv6 #define LWIP_IPV4 1 // 保留IPv4,组成双栈 #define LWIP_ICMP6 1 // IPv6 ICMP,ping6要用 #define LWIP_ND6 1 // IPv6邻居发现 #define LWIP_SOCKET 1 // 使用socket API #define LWIP_NETCONN 1 // 使用netconn API(socket底层依赖) #define NO_SYS 0 // 使用操作系统/线程,Xilinx lwIP示例依赖它

内存方面,IPv6的PCB和ND表项比IPv4占更多RAM。MEM_SIZE、MEMP_NUM_TCP_PCB、MEMP_NUM_NETBUF这些参数不能沿用单栈的默认值。我在MA703FA上的配置是MEM_SIZE 4*1024*1024,MEMP_NUM_TCP_PCB 16,MEMP_NUM_ND6_QUEUE 10。如果板子只有BRAM没有DDR3,内存紧张时优先保证TCP_PCB和PBUF,socket数量可以少开一些。

一个重要的提醒:修改lwipopts.h后,需要在工程上执行Clean,再重新编译。很多时候改了配置没生效,就是BSP库没有重新编译导致的。

3.3 用socket API写出可同时监听v4/v6的服务器

lwIP的示例工程自带一种模板化的TCP服务器框架,我用socket API重写了一遍。下面是一个只监听IPv6的TCP服务线程骨架,IPv4的写法完全对称:

#include "xil_printf.h" #include "lwip/init.h" #include "lwip/sockets.h" #include "lwip/netif.h" #include "netif/xadapter.h" static struct netif netif_static; static unsigned char mac_address[] = {0x00, 0x0A, 0x35, 0x00, 0x01, 0x02}; void tcp6_server_thread(void *arg) { int listen_sock = lwip_socket(AF_INET6, SOCK_STREAM, 0); if (listen_sock < 0) { xil_printf("IPv6 socket create failed\r\n"); return; } struct sockaddr_in6 server6; memset(&server6, 0, sizeof(server6)); server6.sin6_family = AF_INET6; server6.sin6_port = htons(8080); server6.sin6_addr = in6addr_any; // 监听所有IPv6地址 if (lwip_bind(listen_sock, (struct sockaddr *)&server6, sizeof(server6)) < 0) { xil_printf("IPv6 bind failed\r\n"); lwip_close(listen_sock); return; } lwip_listen(listen_sock, 5); xil_printf("IPv6 TCP server listening on port 8080\r\n"); while (1) { struct sockaddr_in6 client6; socklen_t client_len = sizeof(client6); int client_sock = lwip_accept(listen_sock, (struct sockaddr *)&client6, &client_len); if (client_sock < 0) { continue; } // 收发数据... char recv_buf[256]; int len = lwip_recv(client_sock, recv_buf, sizeof(recv_buf), 0); if (len > 0) { lwip_send(client_sock, recv_buf, len, 0); } lwip_close(client_sock); } }

在主函数里初始化lwIP,注册网络接口,然后启动tcpip线程和服务器线程:

#include "lwip/tcpip.h" #include "lwip/dhcp.h" #include "xparameters.h" void start_application(void) { sys_thread_new("tcp6_server", tcp6_server_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } int main(void) { struct netif *netif; ip_addr_t ipaddr, netmask, gw; lwip_init(); IP4_ADDR(&ipaddr, 192, 168, 1, 20); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 1, 1); netif = xemac_add(&netif_static, &ipaddr, &netmask, &gw, mac_address, 0); if (!netif) { xil_printf("xemac_add failed\r\n"); return -1; } netif_set_default(netif); netif_set_up(netif); // 这里还会创建IPv6地址,见下一节 start_application(); while (1) { sys_check_timeouts(); } return 0; }

3.4 主机端快速验证:ping、nc、curl

板子烧录后,插上网线,在PC上先测试IPv4连通性:

ping 192.168.1.20 nc 192.168.1.20 8080

能通说明IP层和TCP层工作正常。对于IPv6,先用下一节的方法给板子配上地址,然后在Linux主机上测试:

ping6 -I eth0 fe80::xxxx nc -6 fe80::xxxx%eth0 8080 curl -6 "http://[2001:db8::1]:8080/"

注意:在Linux上ping link-local地址,必须指定网卡,用%eth0后缀或者在ping命令里加-I,这是很多人第一次测IPv6最容易卡住的地方。

4. IPv6地址从无到有:link-local、SLAAC与静态地址

4.1 为什么网口都通了却拿不到IPv6地址

很多人在IPv4通了之后,开始折腾IPv6,结果发现板子只有一个IPv4地址,IPv6地址完全消失。这里要理解IPv6地址不是“插上网线就有”的,即便lwIP打开了IPv6编译选项,也还需要一个“邻居发现”的过程。

在IPv6网络中,设备会先自动生成一个link-local地址(fe80::/10),这个地址不需要路由器,也不需要DHCP,任何接口只要启用IPv6就会生成。但真正能跨网段访问的全局单播地址,则需要通过三种方式之一获得:

  1. SLAAC(无状态自动配置):设备发起路由器请求RS,路由器回复RA报文,设备根据RA里的前缀自己生成IPv6地址。
  2. DHCPv6:有状态的地址分配。
  3. 静态配置:手工指定IPv6地址。

lwIP 2.0.x对SLAAC有基础实现,但Xilinx的BSP默认并不保证启用。多数情况下,板子插上去只有link-local地址,没有全局地址,原因就是没有路由器在发RA,或者lwIP的自动配置开关没打开。很多家用路由器默认关闭IPv6,或者刷了精简版固件后把IPv6功能砍掉了,这种情况下板子自然“拿不到”全局地址。

4.2 代码里手工创建link-local与全局IPv6地址

最简单的调试方式是不依赖路由器,直接在代码里手工配置IPv6地址。注册网络接口后,继续调用lwIP的IPv6相关API:

#include "lwip/ip6_addr.h" #include "lwip/netif.h" // 在xemac_add之后调用 netif_create_ip6_linklocal_address(netif, 1); netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID); // 手工添加一个全局单播地址,比如2001:db8::1/64 ip6_addr_t ip6addr; IP6_ADDR(&ip6addr, 0x2001, 0x0db8, 0, 0x0001); s8_t idx = 1; err_t err = netif_add_ip6_address(netif, &ip6addr, &idx); if (err == ERR_OK) { netif_ip6_addr_set_state(netif, idx, IP6_ADDR_VALID); }

这段代码里,netif_create_ip6_linklocal_address会根据MAC地址自动生成fe80::开头的link-local地址;netif_add_ip6_address负责添加全局地址。如果BSP里的lwIP版本API略有差异,以实际头文件为准,但思路是通用的:先有地址,再把地址状态置为VALID,协议栈才会真正使用它。

如果想走SLAAC自动获取,可以在lwipopts.h中打开LWIP_IPV6_AUTOCONFIG,然后确保网络环境中有路由器定期发送RA报文。实测下来,家用路由器开IPv6后,板子过几秒就能拿到2001:开头的全局地址。

4.3 真机联调:Linux和Windows下的IPv6测试命令

常见的主机侧调试命令如下,建议收藏:

Linux侧:

ip -6 addr show # 查看本机IPv6地址 ip -6 route show # 查看IPv6路由表 ping6 -I eth0 fe80::xxxx # ping开发板link-local地址 nc -6 -v 2001:db8::1 8080 # IPv6 TCP连接测试

Windows侧:

netsh interface ipv6 show prefixpolicies ping -6 fe80::xxxx%12

Windows上ping link-local地址后要加%接口索引,可以用netsh interface ipv6 show address查到开发板所连网卡对应的索引。热搜里经常看到有人问“netsh interface ipv6 show prefixpolicies”是干什么的,这个命令本质上是查看IPv6前缀优先级的策略表,做双栈路由选择时确实很关键。

4.4 双栈socket的注意点

如果服务器需要同时支持IPv4和IPv6,最稳妥的做法并不是依赖所谓的“IPv4-mapped IPv6地址”,而是直接开两个socket、两个监听线程:一个用AF_INET监听IPv4,一个用AF_INET6监听IPv6。这样做的好处是逻辑清晰,不依赖lwIP是否编译了IPv4映射IPv6的选项。

实测中,我遇到过只开一个AF_INET6socket,结果IPv4客户端始终连不上来的情况。后来直接在main里启动两个线程,各自监听8080端口的v4和v6流量,问题立刻消失。如果你对端口资源不敏感,双线程双监听是最省心的方案。

5. 千兆吞吐实测与一连串故障的排查过程

5.1 实测数据:MicroBlaze的带宽上限

MicroBlaze跑TCP服务器的性能,受CPU主频、内存带宽、lwIP配置、DMA模式等因素影响很大。我基于MA703FA的默认配置(CPU 100MHz,DDR3内存,AXI DMA简单模式),用iperf做过一轮简单测试:

测试项实测结果
TCP发送(板子到PC)约40 ~ 70 Mbps
TCP接收(PC到板子)约35 ~ 65 Mbps
UDP发送约80 ~ 120 Mbps

这个数据比很多人预期的“千兆”低不少,但这就是软核方案的现实。MicroBlaze本质上是一个通用处理器,跑协议栈需要大量内存拷贝和中断处理,不可能像硬核ARM或ASIC那样满速转发。性能优化方向后面会讲。

5.2 故障一:Link灯不亮,MDIO读不到PHY

这是排查链路的第一关。如果插上网线后PHY的Link灯完全不亮,首先要确认的是MDIO能不能访问PHY寄存器。

排错顺序如下:

  1. 检查PHY复位是否释放。很多板子的PHY复位信号低有效,如果GPIO没有输出高电平,PHY一直处于复位状态。
  2. 检查MDC频率是否太高。MDIO最高支持2.5MHz左右,有些设计里直接把100MHz的时钟接到了MDC上,导致读取失败。
  3. 用串口打印PHY ID寄存器。RTL8211FD的PHY ID可以通过MDIO读取,能读出正确的ID值,说明MDIO物理链路是通的。

如果MDIO能读通,但Link灯还是不亮,再检查RGMII的125MHz时钟和PHY的供电。

5.3 故障二:能Link但ping不通

Link灯亮了,说明物理层没问题,问题出在MAC层或IP层。常见的排查链路如下:

  1. 看串口日志里lwIP是否打印了xemac_add成功的信息。如果xemac_add返回空指针,多半是内存不足或MAC地址没有正确传入。
  2. 确认MAC地址没有和局域网里的其他设备冲突。MicroBlaze这类软核开发板经常被人用默认MAC地址,比如00:0a:35:00:01:02,如果你手头有多块板子,全用同一个MAC就会出各种诡异问题。
  3. 在PC上抓包,开发板ping PC,看有没有ARP请求发出。如果板上没有发出ARP,通常是lwIP初始化时序不对,或者网络接口没有正确netif_set_up。
  4. 检查中断连接。AXI DMA的接收中断如果没有接到AXI Intc,板子收不到数据,自然ping不通。

这类问题最费时间的往往是中断。Vivado里连线看起来没问题,但SDK里的XPAR宏和实际连接顺序不一致时,中断处理的回调函数地址就会错位。我建议在出问题时,先把中断全部打印出来:中断号、回调地址、触发状态,逐一核对。

5.4 故障三:IPv6地址一直不出现

IPv6地址不出现,不要急着改代码,先分清楚是“地址压根没生成”还是“地址生成了却不可达”:

  1. 如果netif的IPv6地址列表是空的,检查LWIP_IPV6是否真的被编译进去。BSP设置界面勾选后有时候并不会重新生成lwip库,必须手动改lwipopts.h并clean编译。
  2. 如果link-local地址存在,但没有全局地址,说明SLAAC没有生效。要么打开LWIP_IPV6_AUTOCONFIG,要么手工加全局地址。
  3. 如果地址存在但ping不通,检查路由器和交换机是否开启了IPv6转发。很多设备的IPv6默认不开,需要在管理页面里把IPv6功能打开。
  4. 在PC上用ip -6 neigh查看邻居缓存,如果开发板的MAC没有出现在邻居表里,说明邻居发现报文没有到达PC。这时查交换机的IPv6组播组成员配置,很多老交换机对IPv6组播报文支持不完整,会直接丢弃。

5.5 性能优化方向

如果你对吞吐量有更高要求,可以从以下几个方向入手:

  • 提高MicroBlaze主频。MA703FA上的XC7A35T在-2速度等级下跑到125MHz甚至150MHz完全可行,适当加快CPU会让TCP/IP协议栈的处理速度明显提升。
  • 打开MicroBlaze的I-Cache和D-Cache。对lwIP这类大量数据搬运的负载,Cache命中率上来了性能提升非常明显。
  • 使用AXI DMA的Scatter Gather模式。SG模式能减少CPU介入描述符管理的次数,吞吐量一般能提升10%到30%。
  • 增大lwIP的TCP发送和接收窗口,比如TCP_WND设为65535,TCP_MSS保持1460,配合更大的TCP_SND_BUF可以减少丢包和重传。
  • 换用裸机下的raw API代替socket API。socket API方便,但每一层封装都有代价。如果项目不复杂,用raw API的tcp_write+tcp_output能省下不少CPU周期。

6. 固化到板载Flash:MMI、ELF与BIT合并生成MCS

6.1 MMI文件的作用

项目调试通过后,总不能每次上电都开着Vivado重新下载比特流。MicroBlaze和Zynq不一样,它是纯FPGA逻辑,上电后需要从配置Flash把比特流加载到FPGA里,处理器运行的程序则要放到启动镜像中。

问题在于:MicroBlaze的ELF程序是独立编译出来的,而FPGA比特流只是硬件逻辑的映射。想让板子上电后自动运行软件,就必须把ELF文件合并到比特流里去。Xilinx的方案就是利用MMI文件来完成这一步。

MMI(Memory Map Information)文件记录了FPGA内BRAM或者存储器的地址映射信息,描述了ELF里的数据段应该放到哪个物理地址。Vivado综合之后,工程目录下会生成一个以工程名命名的.mmi文件。这个文件是后面updatemem命令的输入,没有它,工具不知道ELF的内容该合并到比特流的什么位置。

6.2 两条命令完成合并与转换

在Vivado的Tcl Console里,先确认当前打开的工程,然后执行:

updatemem -meminfo system.mmi -data test_app.elf -bit system.bit \ -proc system_i/microblaze_0 -out system_merged.bit

参数说明:

  • -meminfo指定Vivado生成的MMI文件路径。
  • -data指定SDK编译出来的ELF文件路径。
  • -bit指定未合并的原始比特流文件路径。
  • -proc指定工程里的MicroBlaze实例名,比如system_i/microblaze_0。如果设计里有多个MicroBlaze,这个参数不能省。
  • -out指定合并后的比特流名称。

合并完成后,再把合并比特流转换成MCS格式,才能烧写到SPI Flash里。以常见的SPI x4模式、板载W25Q64为例:

write_cfgmem -format mcs -interface spix4 -size 64 \ -loadbit "up 0x0 system_merged.bit" -file system_merged.mcs

-size的单位是Mb,W25Q64对应64。如果板载Flash容量不同,根据实际型号调整。生成MCS之后,这一步会产生一个.prm文件和一个.mcs文件,烧写时选MCS文件即可。

6.3 烧写与上电自启动验证

烧写Flash的路径是:菜单栏Flow -> Open Hardware Manager -> 右键目标FPGA设备 -> Add Configuration Memory Device。在弹出的窗口里选择对应的SPI Flash型号,然后加载编译好的MCS文件,点击Program。

等待烧写完成,断电重新上电。如果一切正常,串口会在启动后打印出lwIP的初始化日志以及服务器监听信息,IPv4和IPv6地址都能被主机ping通。至此,这块MA703FA就不再是吃灰学习板,而是一台上电自启、v4/v6可用的微型网络服务器了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询