[X]关闭

1-2-05Microblaze最小系统搭建及GPIO测试

文档创建者:uisrc
浏览次数:1442
最后更新:2023-09-11
文档课程分类
AMD: FPGA部分(2024样板资料) » 1_START(适配所有型号) » 2-快速入门
件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用AMD-XILINX A7/K7/Z7/ZU/KU系列FPGA
登录"米联客"SOC|SOC社区-www.uisrc.com视频课程、答疑解惑!
1 概述
前面我们快速学习了FPGA工程的创建,仿真,调试。FPGA的功能非常强大,还可以在FPGA上做一个CPU.我们这节课给读者演示如何在FPGA上部署一个CPU软核,实现一个最小的SOC。
一般如果你是搞FPGA开发的肯定学习过C语言,学习C语言的时候,我们跑的第一个工程大多都是跑一个Hello World!不同于ZYNQ自带了硬核,FPGA嵌入软核CPU,这个软核是由FPGA内部的逻辑资源实现,虽然性能上比不了ZYNQ的硬件,但在一些控制的领域还是能做到游刃有余。同样的,AMD-XILINX也提供了软核的IP,这就是MicroBlaze。
MicroBlaze™ CPU 是嵌入式、可修改预置 32 位 RISC 微处理器配置系列。利用没有成本、基于 Eclipse 的 AMD-XILINX 软件开发套件,系统设计人员可在没有任何 FPGA 经验的情况下,使用所选的评估套件立即启动 MicroBlaze 处理器的开发。MicroBlaze 处理器符合大量不同应用的需求,这些应用包括工业、医疗、汽车、消费类以及通信市场等。
2 系统框图
一个MicroBlaze最小系统主要由四个部分组成:CPU、内存(BRAM或者DDR等)、FLASH和UART,下一个实验我们会在当前的系统加入MIG DDR控制器。接下来分别介绍这四个部分的搭建,最后使之成为一个完整的系统。
2504661-20230911185537835-494180119.jpg
3 基于图形化设计SOC系统3.1 创建vivado工程
1-1:在打开的VIVADO2021.1软件界面,单击Create Project。
2504661-20230911185538258-1444158585.jpg 2504661-20230911185538674-871101431.jpg
1-2:单击NEXT,在弹出的窗口中输入工程名和选择保存路径,然后单击Next。
2504661-20230911185539057-2080340050.jpg
1-3:选择RTL Project,单击NEXT
2504661-20230911185539695-984427227.jpg
1-4:在弹出的窗口中选择与板卡对应的芯片型号,这里的图片仅作参考
2504661-20230911185540107-707407971.jpg
1-5:单击Finish完成工程的创建
2504661-20230911185540580-71723249.jpg
3.2 CPU配置
MicroBlaze 是基于AMD-XILINX公司FPGA的一款32/64位软核嵌入式处理器,已针对AMD-XILINX FPGA的实现进行了优化。
MicroBlaze内部有32个32/64位通用寄存器和16个32/64位特殊寄存器。为了提高性能,MicroBlaze还具有指令和数据缓存。所有的指令字长都是32位,有3个操作数和2种寻址模式。指令按功能划分有逻辑运算、算术运算、分支、存储器读/写和特殊指令等。指令执行的流水线是并行流水线,它分为3级流水:取指、译码和执行。MicroBlaze可以响应软件和硬件中断,进行异常处理,通过外加控制逻辑,可以扩展外部中断。
下图显示了MicroBlaze内核的功能框图。
2504661-20230911185541213-1019196443.jpg
针对AMD-XILINX不同系列的芯片,下表中提供了MicroBlaze内核的最大频率。
2504661-20230911185541581-142554208.jpg
MicroBlaze官方提供了三种预设配置: Microcontroller(运行裸机应用程序的简单微控制器)、FreeRTOS(一种具有高速缓存和存储器保护单元接口的实时系统处理器、Application(运行Linux的内存管理单元的应用处理器)。下表显示了这三种配置在官方XC7A200T芯片设备上的性能和利用率
2504661-20230911185541896-2012406892.jpg
创建一个空的FPGA工程

创建Block Design
2504661-20230911185542307-1066031869.jpg
BD(block design)命名为system
2504661-20230911185542669-147397470.jpg
添加IP
2504661-20230911185543011-981174748.jpg
2504661-20230911185543342-588729234.jpg
2504661-20230911185543726-1218070843.jpg
双击MicroBlaze图标,对其进行配置
预设配置:选择current setting。
处理器配置:默认32-bit处理器
2504661-20230911185544130-1891261153.jpg
Select implemention to optimize(优化设置):
area(面积优先)。如果选了这个,implementation就会优化面积,尤其是减少流水线数量,从5条减少到3条。(推荐:建议在资源比较紧张的架构,如Artix-7,使能这个选项。然而,如果对性能有敏感的要求,就不要选这个选项,因为一些指令需要额外的时钟周期去执行。另外,对于MMU, Branch Target Cache, Instruction Cache Streams, Instruction Cache Victims, Data Cache Victims, ACE是不能进行面积优化的。)
2504661-20230911185544564-690972307.jpg
Enable MicroBlaze Debug Module Interface(调试接口)
使能调试功能。用AMD-XILINX Microprocessor Debugger来下载、调试程序。(推荐:除非面积资源奇缺,否则不要禁止这个功能。)
Use Instruction and Data Caches(指令和数据cache,当使用外置DDR的时候使用):
当执行放在LMB之外的程序的时候,可以使用指令缓存来改善性能。指令缓存有如下特点:当使用外部存储时,激活这个选项可以明显地改善性能,即使这个缓存很小。
勾选Use Instruction and Data Caches
2504661-20230911185544988-874072867.jpg
Enable Exceptions(异常处理使能)
当使用一个支持异常的操作系统时,需要激活这个选项。或者在一个单独的程序中添加异常回调函数。
Use Memory Management(内存管理)
当使用一个支持虚拟内存保护的操作系统时(如Linux),需要激活。(当你使能面积优化或者堆栈保护功能时,内存管理单元是不可见的,自动禁止)

Enable Discrete Ports:使能软核上的独立端口。

2504661-20230911185545393-1207039293.jpg
单击NEXT进入下一页配置:
这一页是关于移位器、浮点单元、整形乘法器,整形除法器、模式比较器、其他机器状态寄存器指令、加载/存储和交换指令、额外的流指令、容错功能。
2504661-20230911185545777-581244669.jpg
使能桶型移位器(Enable Barrel Shifter):使能软核中的筒形移位器硬件。激活这个参数,就可以使用如下指令(bsrl,bsra,...)使能这个可以提高应用的性能,但是会增大软核的尺寸。如果激活,编译器会自动使用筒形移位器指令。

使能浮点单元(Enable Floating Point Unit):使能一个单精度浮点单元(FPU)。使用FPU可以明显地提高应用的单精度浮点性能,同时也会增大软核的尺寸。

使能整形乘法器(Enable Integer Multiplier):使能一个整形乘法器硬件。若激活,则可以在给MUL32赋值时,使用mul和muli指令。当给MUL64赋值时,使用mulh,mulhu,mulhsu指令。这个参数可以设置为NONE,可以把MUL或者DSP48释放,用作其他用途。这样做对软核的面积影响很小。当使用这个选项,编译器自动使用mul指令。

使能整形除法器(Enable Integer Divider):使能一个整形除法器硬件。若激活,可以使用idiv,iduvu指令。使能这个选项可以提高应用中的除法性能,但是增大了软核的尺寸。当使用这个选项,编译器自动使用idiv指令。

使能额外机器状态寄存器指令(Enable Additional Machine Status Register Instructions):若激活,则可以读写MSR,使用msrset和msrclr命令。可以提高访问MSR的性能。

使能模式比较器(Enable Pattern Comparator):如激活,则可以使用模式匹配指令pcmpbf,pcmpeq,pcmpne。模式匹配字节查找指令(pattern comparator byte find, pcmpbf)返回找到的第一个字节的位置,提高字符串和模式匹配操作的效率。若使能,SDK库会自动使用这个指令。pcmfeq和pcmpne指令根据两个字是否相同,返回1或者0。这些指令会提高setting flags的效率,编译器会自动使用它们。激活这个选项还可以count leading zeros指令,clz。clz指令能提高优先级编码的效率。

使能保留的加载/保存和交换指令(Enable Reserved Load/Store and Swap Instructions):lbur,lhur,lwr,sbr,shr,swr,swapb,和swaph。这些指令能够以相对的字节序来读写数据,交换指令能交换字节或者半个字长。当用little-endian的MicroBlaze访问big-endian的网络时,可以提高效率。

使能额外的流命令(Enable Additional Stream Instructions):当使用AXI4-Stream链接时,提供额外的功能。这包括动态访问指令GETD和PUTD,这两个指令用寄存器来选择接口。(重要:一定要激活流异常功能,才能使用这些指令,而且知道选择一个流链接)
单击Next进入下一页配置:使能cache修改如下
2504661-20230911185546185-264303543.jpg
单击Next进入下一页配置:
这一页是对microblaze的调试接口进行配置,选择默认的BASIC配置
2504661-20230911185546582-722931452.jpg
单击Next进入下一页配置:
该页面主要用于设置总线接口,设置本地内存总线接口、AXI总线接口、Stream总线接口
2504661-20230911185546972-24668.jpg
单击OK 完成配置

2504661-20230911185547336-468380059.jpg
产生使用VIVADO BD的自动化功能
2504661-20230911185547752-958956217.jpg
设置如下
2504661-20230911185548132-1870897480.jpg
自动化连线后
2504661-20230911185548563-1283035074.jpg
3.3 添加AXI UARTLite IP
我们还要添加一个UART用于串口打印,因为不需要复杂功能,我们只要添加一个基本的UART IP
2504661-20230911185548920-1410169892.jpg
2504661-20230911185549241-1304408995.jpg
设置UART核,修改波特率为115200。
2504661-20230911185549596-89370652.jpg
通过连线的方式,连接到AXI interconnect,增加AXI interconnect的接口
2504661-20230911185549982-847014391.jpg
2504661-20230911185550339-1545262092.jpg
连接AXI接口到UART的AXI接口
2504661-20230911185550692-1060641225.jpg
连接中断
2504661-20230911185551061-1371856121.jpg
连接时钟
2504661-20230911185551497-1967504349.jpg
连接复位
2504661-20230911185551875-1491139808.jpg
3.4 CLK_WIZ时钟设置
修改clk_wiz时钟输入,这里注意每个板子的输入可能不一样,有单端,有差分,有25M 50M 100M 200M,请大家核对原理图
2504661-20230911185552327-846111345.jpg
取消时钟复位
2504661-20230911185552972-1615750985.jpg
2504661-20230911185553477-89785758.jpg
把时钟输入,和UART端口引出
2504661-20230911185554023-2003239295.jpg
2504661-20230911185554995-1156925814.jpg
相同方法,引出时钟
2504661-20230911185555490-237220996.jpg
修改时钟名,让时钟名符合使用习惯
2504661-20230911185555959-879253638.jpg
3.5 添加AXI-Interconnect IP
添加1个axi-interconnect IP,互联到这两个接口
2504661-20230911185556335-880157210.jpg
双击该IP
2504661-20230911185556847-834275878.jpg
修改设置如下
2504661-20230911185557512-2064321824.jpg
2504661-20230911185557929-705846476.jpg
3.6 添加MIG IP核心(添加DDR配置)
AMD-XILINX DDR通过MIG控制,添加MIG IP核
2504661-20230911185558284-1108106246.jpg
双击IP配置
2504661-20230911185558636-226799093.jpg
MIG核设置
2504661-20230911185559219-1823785522.jpg
2504661-20230911185559745-465293273.jpg
2504661-20230911185600415-1568502519.jpg
2504661-20230911185600884-2038281594.jpg

2504661-20230911185602019-1980868236.jpg 2504661-20230911185605592-39436584.jpg
2504661-20230911185606514-122471665.jpg
2504661-20230911185607236-534109748.jpg
2504661-20230911185607701-1749278048.jpg
2504661-20230911185608107-237173172.jpg
2504661-20230911185608827-76995643.jpg
导入DDR的IO约束,这个文件也是我们从已经做好的工程导出的,直接导入可以提高效率,不同的板子文件名可能不一样注意下。

2504661-20230911185609667-330266211.jpg
2504661-20230911185610234-162327129.jpg
校对
2504661-20230911185611068-1982177680.jpg
既然可以导入,那么也可以通过Save Pin Out 导出设置,这里就不再演示
2504661-20230911185612026-994414997.jpg
2504661-20230911185612712-1965435681.jpg
2504661-20230911185613444-213149915.jpg
2504661-20230911185613933-89486528.jpg
2504661-20230911185614952-64740226.jpg

2504661-20230911185615560-121316888.jpg
MIG核配置完成后
2504661-20230911185616293-1968097227.jpg
3.7 完成信号连线设计
连线的过程不再重复描述,根据我们最终的截图,完成IP之间的连线,并且引出MIG DDR接口
2504661-20230911185617192-557724897.jpg
因为只用到1个中断,修改concat IP,改为1
2504661-20230911185617600-602587694.jpg
2504661-20230911185618081-2019289664.jpg
3.8 添加AXI QUAD SPI IP核
接下来,添加一个axi_quad_spi核
2504661-20230911185618463-1075730644.jpg
双击设置如下
2504661-20230911185618977-372218931.jpg
增加axi-interconnect
2504661-20230911185619388-1993359240.jpg
使用相同的方法,完成axi-interconnect IP的连线
2504661-20230911185619873-498706532.jpg
3.9 完成基于IP图形化的最小系统设计
完成后的最小系统如下包含了CPU、中断、调试模块、UART、QSPI、DDR:
2504661-20230911185620403-1207489329.jpg
3.10 BD(block design)层次化功能
我们可以利用BD的层次化功能,把目前的最小系统层次化为1个最小系统,按下ctrl选中所有IP
2504661-20230911185621078-2079780809.jpg
然后右击,创建层次化
2504661-20230911185621636-840166781.jpg
我们可以取一个名字,这里我们输入MinSoc
2504661-20230911185622109-807960985.jpg
现在看起很不舒服
2504661-20230911185622525-252526776.jpg
继续右击,选中Regenerate Layout
2504661-20230911185622871-354173737.jpg
现在看起来非常清爽了,端口只包含了时钟输入、串口、FLASH、DDR
2504661-20230911185623247-867053146.jpg
3.11 添加AXI_GPIO
2504661-20230911185623715-65576566.jpg
AXI-GPIO的设置如下,输出输出各设置2bit,支持中断,本实验不讲解中断后面再做中断实验
2504661-20230911185624140-1681269021.jpg
将接口连接到位,初学者可能不知道如何从我们外部连接到Minsoc,我们只需要右键接口,然后右键make Connection随后选择需要连接的接口即可自动完成连线。
2504661-20230911185624567-1034001873.jpg
连线完成
2504661-20230911185624928-1454781579.jpg

3.12 地址空间的分配
PS(microblaze cpu 或者ARM 简称PS)通过访问地址空间可以实现寄存器,或者内存的访问。
检查地址空间的分配, BRAM的地址空间已经分配,AXI_INTC IP地址也已经分配,UART和SPI的的地址没有分配。
2504661-20230911185625334-1744155874.jpg
选中assign ALL

分配完成后
2504661-20230911185625747-2083309994.jpg
3.13 VIVADO自动校对功能
利用VIVADO自动化校验功能
2504661-20230911185626107-1649396818.jpg
2504661-20230911185626426-2026321631.jpg
现在图形化的设计已经完成
3.14自动产生调用BD代码的接口代码
BD图形化设计本质还是FPGA代码,是一种图形化形象编程的方式。
2504661-20230911185626770-1924454734.jpg
2504661-20230911185627120-243525384.jpg
2504661-20230911185627572-1228987469.jpg
检查自动产生的顶层文件,可以看到顶层文件调用了BD模块
3.15绑定FPGA pin脚
绑定FPGA管脚前文已经有详细的介绍,此处不再重复赘述,xdc文件存放路径为uisrc/04_pin
3.16 编译FPGA工程
2504661-20230911185627914-19276715.jpg

4 编译完成后,导出硬件
2504661-20230911185628308-1258000458.jpg
米联客会新建3个文件路径
2504661-20230911185628667-1434748802.jpg
2504661-20230911185629012-229438298.jpg
到此,完成了SOC FPGA部分的设计工作
5 导出导入BD的tcl脚本方法
最小系统搭建完成之后,在之后的设计中可能会再次使用到这一部分的设计,为了避免重复的设计,浪费开发时间,笔者这里介绍一种高效的工程管理方式——将BD文件导出为tcl脚本。导出tcl脚本之后,在下次设计中,我们就只需要运行tcl脚本即可完成此部分电路的配置,能有效的节省开发时间。
5.1 导出BD为tcl
首先确保Block design处于被打开的状态,在TCL控制台中输入如下命令可将BD文件导出为tcl脚本。
2504661-20230911185629410-341565593.jpg
2504661-20230911185629750-1807000158.jpg
5.2 导入BD tcl
新建一个vivado工程
自定义IP(如果用户用到自定义IP需要设置,没用到不需要设置)路径设置,如果用到必须设置,否则导入tcl会找不到自定义IP.
2504661-20230911185630131-302373209.jpg
本实验没有用到自定义IP
2504661-20230911185630649-1955929989.jpg
导入TCL到新的vivado工程
2504661-20230911185630996-1203112108.jpg
运行完source指令之后,系统会自动生成我们之前搭建好的BD文件,之后我们就可以使用这个文件来搭建最小系统。
6 搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程。
6.1 创建SDK Platform工程
启动Vitis-Sdk
2504661-20230911185631403-25865963.jpg
设置好路径
2504661-20230911185631754-173547351.jpg
米联客资料中的路径规范如下图:
soc_prj里面是基于SOC的硬件工程源码
soc_hw里面是xsa格式文件,soc_prj编译会导出system_wrapper.xsa到这个文件
soc_sdk里面是裸机的sdk工程,sdk工程创建依赖soc_hw中的system_wrapper.xsa
2504661-20230911185632114-1567207124.jpg
单击Create Platform Project 创建基于开发平台的工程
2504661-20230911185632504-709052187.jpg
2504661-20230911185632910-1827422462.jpg
添加之前创建的system_wrapper.xsa文件
2504661-20230911185633333-1698012422.jpg

2504661-20230911185633722-1996003646.jpg
2504661-20230911185634135-170588243.jpg
2504661-20230911185634530-888302287.jpg
6.2 创建hello_world APP工程
2504661-20230911185634949-76552615.jpg
2504661-20230911185635344-1274337787.jpg
2504661-20230911185636099-1538598670.jpg
2504661-20230911185636515-1453274433.jpg
2504661-20230911185636944-1766644460.jpg
2504661-20230911185637354-1023271766.jpg
自动产生一个helloworld传输输出程序
2504661-20230911185637761-541194869.jpg
右击工程编译
2504661-20230911185638213-1885645633.jpg
6.3 创建axi_gpio_test APP工程
"axi_gpio_test "APP工程代码,我们直接源码,用户直接新建一个空的工程,然后将源码直接复制粘贴即可,我们对于空工程的新建不做过多的讲解。
新建完成后工程如下图所示:
2504661-20230911185638641-1237950050.jpg
7 程序分析
hello_word APP就是简单通过调用FPGA工程师中的uart-lite IP串口输出一些字符信息,程序代码简单不做分析。
7.1 axi_gpio_test.c测试程序
#include "sys_xintr.h"
#include "axi_gpio_intr.h"
#include "sleep.h"

extern XGpio Gpio; //定义GPIO实列
extern XIntc Intc; //定义系统中断实列

extern volatile u32 gpio_intr_flag; //中断标志
extern volatile u32 gpio_val; //保存GPIO按键输入读取值

void init_intr_sys(void)
{

    XInit_Intr_System(&Intc , 0);//初始化系统中断
    Gpiopl_init(&Gpio, AXI_GPIO_DEV_ID); //初始化GPIO
    Gpiopl_Setup_Intr_System(&Intc, &Gpio, GPIO_INTR_ID); //初始化GPIO中断
    XSetup_Intr_Exception(&Intc); //设置中断异常
}


int main(void)
{
    init_intr_sys();//初始化系统中断
    while(1)
    {
        if(gpio_intr_flag)
        {
            gpio_intr_flag = 0;
            XGpio_DiscreteWrite(&Gpio,2,gpio_val);
            printf("SW=%d int\n\r", gpio_val);
        }
    }
    return XST_SUCCESS;
}


7.2 axi_gpio_intr.c程序
#include "axi_gpio_intr.h"

volatile u32 gpio_intr_flag;
volatile u32 gpio_val;

//中断回调函数
void GpioplIntrHandler(void *Callback)
{
    XGpio *GpioPtr = (XGpio *)Callback;
    u32 IrqStatus;

    IrqStatus = XGpio_InterruptGetStatus(GpioPtr); //获取中断状态

    if((IrqStatus & 0x01) == 0x01)
    {
        gpio_val = XGpio_DiscreteRead(GpioPtr, 1); //GPIO中断需要读按键状态知道哪一个按键产生了中断
        gpio_intr_flag = 1; //设置中断标志
    }

    XGpio_InterruptClear(GpioPtr, IrqStatus); //清除中断

}

//设置中断
void Gpiopl_Setup_Intr_System(XIntc *GicInstancePtr, XGpio *InstancePtr, u16 IntrId)
{
XIntc_Connect(GicInstancePtr, IntrId, //设置中断回调函数
(Xil_ExceptionHandler)GpioplIntrHandler,
(void *)InstancePtr);

XIntc_Enable(GicInstancePtr, IntrId);//使能中断号指定的中断

    XGpio_InterruptEnable(InstancePtr, 0x01);//使能中断

    XGpio_InterruptGlobalEnable(InstancePtr); //使能全局中断

}

int Gpiopl_init(XGpio *InstancePtr, u32 DeviceId)
{

    int Status;
    /* Initialize AXI GPIO */
    Status = XGpio_Initialize(InstancePtr, DeviceId);
    if (Status != XST_SUCCESS) {
        xil_printf("AXI GPIO config failed!\r\n");
        return XST_FAILURE;
    }

    XGpio_SetDataDirection(InstancePtr, 1, 0x3);//设置GPIO通道1用于输入

    XGpio_SetDataDirection(InstancePtr, 2, 0x0); //设置GPIO通道2用于输出

    XGpio_SetDataDirection (&Gpio, 1, 0x3); //输入设置上拉

    XGpio_SetDataDirection (&Gpio, 2, 0x0); //输出设置输出0

return 1;
}


在初始化函数中,设置channel1 的2个IO为输入,channel2 的2个IO为输出
2504661-20230911185639089-1621509974.jpg
在Gpiopl_Setup_Intr_System(XIntc *GicInstancePtr, XGpio *InstancePtr, u16 IntrId)函数中主要是对,AXI-GPIO的全局中断使能寄存器GIER和IPIER中断使能寄存器进行设置
2504661-20230911185639424-230945444.jpg
当GPIO的电平状态发生改变就会触发中断,回调函数中,首先读取AXI-GPIO的状态寄存器,然后判断是否是channel1产生的中断。之后读取GPIO的按键输入状态,设置中断触发变量为1。最后清除中断。
2504661-20230911185639786-1076357320.jpg
8 实验演示8.1 硬件准备
2504661-20230911185640170-1128624046.jpg
8.2 helloworld实验结果
为了观察实现结果,需要打开串口
首选选中Debug,出来Vitis Serial Terminal,串口终端
2504661-20230911185640642-958780500.jpg
设置正确的串口号
2504661-20230911185641041-845266332.jpg
单击OK 打开终端
2504661-20230911185641417-698526778.jpg
选中Design切换界面
2504661-20230911185641798-1792953491.jpg
右击选中调试
2504661-20230911185642373-1439686300.jpg
双击System Project Debug
2504661-20230911185642907-9585858.jpg
选中SystemDebug_hellowrld_sytem 单击debug
2504661-20230911185643931-1902090649.jpg
输入结果如下,最小系统运行正常
2504661-20230911185644647-1652706325.jpg
8.3 axi_gpio_test实验结果
除了通过串口观察按键中断的结果,而且可以通过LED观察。每次按下按键产生一个中断,每次松开按键也会产生一个中断。总之,只要按键的状态发生改变就会产生中断。
2504661-20230911185645057-513965525.jpg
9本章小结
本章节我们学会了搭建Microblaze最小系统,并且该系统可以在多种场合重复使用,并且利用我们搭建的最小系统完成一个简单的AXI_GPIO的使用。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则