赞
踩
本文以基于米联客MA703FA开发板的MicroBlaze LWIP千兆以太网例程为例,详细介绍在外部DDR3内存中运行的MicroBlaze程序的固化方法。
FPGA型号:XC7A35TFGG484-2
首先打开Vivado工程,进入Block Design,添加AXI Quad SPI IP核:
点击Run Connection Automation,连接AXI LITE总线,并导出SPI引脚:
再次点击Run Connection Automation,连接Quad SPI的时钟:
双击Quad SPI IP核,进入配置界面。将Mode设置为Quad(四线),Slave Device设为Micron(SPI Flash的品牌)。注意下面要勾选Enable STARTUP Primitive。
点击Run Synthesis,开始综合:
综合完毕,选择Open Synthesized Design:
点击Schematic:
显示引脚配置面板:
配置SPI Flash的4线I/O引脚:
配置SPI Flash的片选引脚:
注意:SPI Flash的时钟引脚不用配置。
确保xdc文件里面已经配置好SPI 4线模式:
- set_property CFGBVS VCCO [current_design]
- set_property CONFIG_VOLTAGE 3.3 [current_design]
- set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
- set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
- set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
- set_property BITSTREAM.CONFIG.SPI_FALL_EDGE Yes [current_design]
配置完毕后,点击Generate Bitstream,产生bit文件:
生成失败,提示LUT资源不够。这是因为以太网工程比较大,加入了Quad SPI之后,XC7A35T里面的LUT资源不够了。
考虑到我们程序里面只用到了定时器中断,其他五个中断都没有用到,所以我们可以只保留定时器中断,其余的全部删除。
回到Block Design里面,我们把AXI Interrupt Controller上挂接的Concat删掉,把定时器的interrupt中断引脚接到AXI Interrupt Controller的intr上面去。连线后,上面还是显示的是intr[5:0],不用管,待会儿综合完毕,它会自动变成intr[0:0]。
修改前,定时器的中断号是2,现在变成了0。
特别注意的是,千万别把MicroBlaze的M_AXI_IP(Peripheral AXI Instruction Interface)删了,否则后面程序固化进去会因为没有指令线而无法运行!
修改完成后保存,再次点击Generate Bitstream,这下就可以成功生成bit文件了:
此时占用的LUT个数为19546:
导出design_1_wrapper.xsa文件:
这个时候,不要急忙打开Vitis工程(C语言工程),否则进去之后会看到Includes里面是乱七八糟的。本来项目在F盘里面,结果Includes里面什么盘的引用都有!
这里面E盘那个路径是笔者几天前的工程文件夹的位置了,如果不管的话,程序里面#include <xparameters.h>引用的就是以前文件夹里面的头文件,里面的参数都是错误的,跟当前工程毫无关系!
尤其是我们刚才改了定时器的中断号,由2改成了0,如果xparameters.h文件包含错了,那么程序固化后定时器中断就无法触发,sys_now()函数就会一直为0,导致lwip无法正常工作,比如ping不通IPv6本地链路地址。还有,ARP、TCP的一些功能也会出现故障。等于说while (1)里面的sys_check_timeouts函数完全失效了!
先把Vitis工程里面的.metadata文件夹删了:
这下就可以打开Vitis软件了,进入工程目录,点击菜单栏里面的File -> Import...命令,导入原有的工程:
导入完成后,更新一下Platform工程绑定的xsa文件(因为我们刚才修改了Vivado工程,所以xsa文件已经变了):
注意一下,下面这个路径不要选错了,要看仔细:
Build一下Platform工程:
我们将lwip工程完全修改到DDR3内存里面运行:
(如果点开菜单没有Generate Linker Script选项,再重新多点开几下菜单,就会出现)
修改完之后,记得Build一下:
把Vivado里面的bit文件烧录进FPGA,然后试着运行一下lwip工程,看能不能运行:
我们发现程序运行不了,一直不断地重启:
这是因为栈大小(Stack Size)太小了,由1KB改成3KB试试看:
改完,记得Build一下:
这下就可以运行成功了,果然是栈大小的问题:
检查一下Includes目录是否正常:
还要检查xparameters.h里面的定时器中断号是否变成0了。如果还是2的话,那就有问题,工程没有更新过来,需要检查一下怎么回事。
打开Platform工程里面的platform.spr文件,修改BSP设置,勾选xilisf库:
镁光SPI Flash的厂家号为5,所以将serial_flash_family的值改为5:
重新Build一下Platform工程:
新建一个Application工程:
工程起名bootloader:
这里要选择SREC SPI Bootloader模板:
工程建好后,打开blconfig.h文件,将FLASH_IMAGE_BASEADDR改为0x800000:
这个参数是烧写到QSPI FLASH里的DDR3主程序相对于基地址的偏移量,要根据后面bootloader和vivado bit文件合成生成的download.bit的大小来修改,保证lwip程序不会将bootloader部分覆盖掉。这里直接填写0x800000就好。
修改完成后,Build一下bootloader工程:
在bootloader工程的右键菜单上,点击Program FPGA命令:
选择刚才编译生成的bootloader.elf文件,点击Generate按钮,将Vivado的design_1_wrapper.bit文件和bootloader.elf文件合并,生成download.bit文件:
再在bootloader工程上点击Program Flash命令:
选择刚才合并生成的download.bit文件:
偏移地址为0,SPI Flash的型号为mt25ql128,烧写进去:
再次编译一下lwip工程:
在lwip工程的右键菜单上点击Program Flash:
选择lwip工程编译生成的lwip_test.elf文件:
偏移量设为0x800000(就是刚才在头文件里面写的值),下面要勾选Convert ELF to bootloadable SREC format and program,然后点击Program按钮,烧写进去:
烧写完毕后,板子重新上电,lwip程序就能运行成功了。
经测试,能够ping通板子的设备名,IPv4地址和IPv6地址,HTTP服务器也能正常访问。
串口发送t,可以看到sys_now()函数的返回值也是正确的,每秒增加1000:
如果发现设备名和IPv4能够ping通,能访问http网页服务器,但是就是ping不通IPv6地址,说明sys_now()函数出问题了,如下图所示,sys_now()函数始终为0,导致IPv6本地链路地址始终处于无效状态:
这是由于我们刚才在Vivado里面改了定时器的中断号,由2改为了0,然而Vitis工程的xparameters.h里面并没有得到更新,XPAR_INTC_0_TMRCTR_0_VEC_ID的值仍然等于2。程序里面使能的是2号中断,没有使能0号中断,定时器中断就无法触发,sys_ticks的值就一直为0。sys_now()函数也就一直返回0。
检查hello_world.c包含的<xparameters.h>头文件,发现包含的竟然是E盘里面另外一个完全不相关的文件夹里面的xparameters.h,里面XPAR_INTC_0_TMRCTR_0_VEC_ID的值等于2。实际上Platform工程里面的xparameters.h的XPAR_INTC_0_TMRCTR_0_VEC_ID值已经变成0了,但是就是编译的时候include到E盘里面几天前的工程里面的xparameters.h文件了!
解决办法就是,把vitis的.metadata文件夹删了,重启vitis,重新导入工程,clean,build,就好了。
【扩展阅读】
Xilinx Vitis 2020.1用SREC SPI Bootloader固化Microblaze程序,断电再通电后程序运行不了的解决办法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。