HPS SoC和FPGA联合使用例程

HPS SoC和FPGA联合使用例程本教程演示了如何使用 HPS ARM 与 FPGA 进行通信 我们将为 DE10 标准开发板介绍如何根据官方的 DE10 Standard GHRD 工程开发出自己的 My GRHD 工程 之后 我们会在 My GHRD 工程上运行我们自己改造过后的 HPS FPGA LED 应用程序 该应用程序会控制连接到 D

本教程演示了如何使用HPS/ARM与FPGA进行通信。我们将为DE10标准开发板介绍如何根据官方的DE10_Standard_GHRD工程开发出自己的My_GRHD工程。之后,我们会在My_GHRD工程上运行我们自己改造过后的HPS_FPGA_LED应用程序。该应用程序会控制连接到DE10标准开发板上FPGA部分的A的10个LED灯闪烁。其中,LEDR0将会通过闪烁模拟板子的心跳,LEDR1-8将会按照一定频率进行左移右移循环闪烁60次,LEDR9将会在LEDR1-8的每一次循环后闪烁一次。例程中HPS通过Lightweight HPS-to-FPGA Bridge控制FPGA部分连接的LED灯。而且,例程中FPGA部分是由HPS通过HPS中FPGA manager进行配置。

背景要求

假定开发人员已经具有以下背景知识:

FPGA RTL级设计
  • 基本的Quartus Prime操作技能
  • 基本的RTL编程技能
  • 基本的Qsys操作技能
  • 关于Memory-Mapped 接口的知识
C语言设计
  • 基本的SoC(Embedded Design Suite)操作技能
  • C语言编程和编译技巧
  • 使用配套的image镜像文件为DE10-Standard板创建Linux引导SD卡的技能
  • 在DE10-Standard板上从SD卡引导Linux的技能以及拷贝文件进入DE10-Standard板上Linux文件系统的基本Linux命令操作技能

系统要求

在开始本教程之前,请注意演示项目准备需要以下内容:

友晶DE10-Standard FPGA板,包括
  • 用于串口中断通信的Mini USB线缆
  • 存储空间4G以上Micros SD卡
  • Micros SD卡读卡器
一台x86架构的PC机
  • 装有64位Windows 7操作系统
  • 配有一个USB端口
  • 装有Quartus Prime 16.1或以上版本
  • 装有SoC EDS 16.1 或以上版本
  • 装有Win32 Disk Imager软件

Intel SoC FPGA的AXI 桥

在Intel SoC FPGA中,HPS逻辑与FPGA结构通过AXI(Advanced eXtensible Interface)桥进行连接。为了实现HPS逻辑与FPGA 结构的通信,需要通过使用Intel系统集成工具Qsys添加HPS组件来进行系统设计。从HPS组件的AXI主端口,HPS可以访问那些连接到AXI主端口的内存映射从端口。

HPS包含以下HPS-FPGA AXI桥

  • FPGA-to-HPS桥
  • HPS-to-FPGA桥
  • 轻量级的HPS-to-FPGA桥

FPGA-to-HPS桥接控制L3主开关,允许任何在FPGA结构的主实现(implemented)去访问在HPS中大多数从实现。

所有三个桥都包含全局程序员视图GPV寄存器。GPV寄存器控制网桥的行为。通过轻量级的HPS-to-FPGA桥访问可以所有三个桥的GPV寄存器。

这个例程向用户介绍了如何使用HPS/ARM与FPGA进行通信。这个与DE10-Standard板上ARM C程序配套的GHRD工程,演示了HPS/ARM程序如何控制连接到FPGA部分的红色LED。

GRHD工程

术语GHRD是黄金硬件参考设计(Golden Hardware Reference Design)的简称。友晶科技为DE10-Standard开发板提供的GRD项目位于CD文件夹中: CD-ROM\Demonstration\SOC_FPGA\ DE10_Standard_GHRD。

本项目由以下组成部分组成:

  • ARM Cortex™-A9 MPCore HPS
  • 四个用户按钮输入
  • 十个用户DIP开关输入
  • 10个用户I/O用于LED输出
  • 64KB片上存储器
  • • JTAG to Avalon master bridges
  • Interrupt capturer for use with System Console
  • System ID

My_GHRD工程

在实际的应用过程中,友晶科技提供的DE10_Standard_GHRD工程并不是十分契合我们的开发需要,这可能包括外围设备的冗余和不足。下面为了实现本教程开篇所定的目标,我们需要根据DE10_Standard_GHRD工程进行修改。其中友晶科技提供的DE10_Standard_GHRD工程实现的是LEDR0通过闪烁模拟板子的心跳,LEDR1-9按照一定频率进行左移右移循环闪烁60次;我们的目标是LEDR0通过闪烁模拟板子的心跳,LEDR1-8按照一定频率进行左移右移循环闪烁60次,LEDR9在LEDR1-8的每一次循环后闪烁一次。可以看出,我们只需要将DE10_Standard_GHRD工程中的LEDR9的设计进行更改就可以打到我们的目的。下面正式开始更改操作。

准备设计文件

新建文件夹:E:\work\Quartus\My_GHRD,然后将DE10_Standard_GHRD工程目中的一下文件复制到工程目录下:

  • 文件夹:hps_isw_handoff
  • 文件夹:ip
  • 文件:DE10_Standard_GHRD.v
  • 文件:DE10_Standard_GHRD.sdc
  • 文件:generate_hps_qsys_header.sh
  • 文件:hps_common_board_info.xml
  • 文件:soc_system.qsys
  • 文件:soc_system_board_info.xml
创建My_GHRD工程
Qsys设计

由于我们需要在DE10_Standard_GHRD工程的基础上更改Qsys的设计来实现对LEDR9的单独控制,所以我们需要在Qsys中添加一个1位的PIO端口来实现对LEDR9的控制,同时需要将原来用于同时控制LEDR0-9的10位PIO端口的改为9位的PIO端口。

  • led_pio9.clk—clk_0.clk
  • led_pio9.reset—clk_0.clk_reset
  • led_pio9.s1—mm_bridge_0.m0—fpga_only_master.master

在上述界面中可以看到文件:hps_reset_bb.qip和hps_reset_bb.v,这一组文件的定义了模块:hps_reset。但是,由于 文件:hps_reset.qip和hps_reset.v这一组文件同样也定义了模块:hps_reset,所以hps_reset_bb.qip和hps_reset_bb.v的加入会导致模块:hps_reset的重复定义。

至此,工程My_GHRD中Qsys部分的设计已经完成。接下来我们需要对工程中的硬件描述文件.v文件进行修改。其实,我们在DE10_Standard_GHRD工程的基础上只用对My_GHRD中顶层实体文件My_GHRD.v中各个模块的引脚及其连接关系进行描述即可。

硬件描述设计
  • 将原来与LEDR[9:1]连接的变量wire [8:0] fpga_led_internal改为:与LEDR[8:1]连接的wire
    [7:0] fpga_led_internal

  • 定义新的变量wire fpga_led9_internal与LEDR[9]连接
  • 将新的变量wire fpga_led9_internal另一端与模块soc_system u0中的端口led_pio9_external_connection_export进行连接

在这里插入图片描述
在这里插入图片描述

My_GHRD工程编译

C语言设计

本节将介绍如何设计一个ARM C程序来控制PIO控制器led_pio。SoC EDS用于编译C项目。为了让ARM程序控制PIO组件led_pio,我们需要led_pio地址。使用Linux内置驱动程序’ /dev/mem ‘和mmap system-call可以将led_pio组件的物理基址映射到Linux应用软件可以直接访问的虚拟地址。

HPS头文件

ARM C程序需要led_pio的组件信息,因为程序会尝试控制组件。这部分将会描述如何使用一个给定的Linux shell批处理文件将Qsys HPS信息提取到一个头文件中,这个头文件稍后将包含在C程序中。

cmd="sopcinfo2swinfo --input=$sopc_design_file --output=$swinfo_tmp_fname ${sopcinfo2swinfo_args[@]}" /cygdrive/d/intelFPGA/Quartus16.1/quartus/sopc_builder/bin/sopcinfo2swinfo --input="$sopc_design_file" --output="$swinfo_tmp_fname" ${sopcinfo2swinfo_args[@]} || { 
      echo "$PN: $cmd failed" exit 1 } 

cmd=“swinfo2header –swinfo s w i n f o t m p f n a m e < / s p a n > − − s o p c < s p a n c l a s s = " t o k e n v a r i a b l e " > swinfo_tmp_fname –sopc swinfotmpfname</span>sopc<spanclass=tokenvariable>sopc_design_file s w i n f o 2 h e a d e r a r g s [ @ ] < / s p a n > ” < / s p a n > / c y g d r i v e / d / i n t e l F P G A / Q u a r t u s 16.1 / q u a r t u s / s o p c b u i l d e r / b i n / s w i n f o 2 h e a d e r − − s w i n f o < s p a n c l a s s = " t o k e n s t r i n g " > ” < s p a n c l a s s = " t o k e n v a r i a b l e " > {swinfo2header_args[@]} /cygdrive/d/intelFPGA/Quartus16.1/quartus/sopc_builder/bin/swinfo2header –swinfo swinfo2headerargs[@]</span></span>/cygdrive/d/intelFPGA/Quartus16.1/quartus/sopcbuilder/bin/swinfo2headerswinfo<spanclass=tokenstring><spanclass=tokenvariable>swinfo_tmp_fname –sopc s o p c d e s i g n f i l e < / s p a n > ” < / s p a n > < s p a n c l a s s = " t o k e n s t r i n g " > ” < s p a n c l a s s = " t o k e n v a r i a b l e " > sopc_design_file sopcdesignfile</span></span><spanclass=tokenstring><spanclass=tokenvariable>{swinfo2header_args[@]} || {
echo P N < / s p a n > : < s p a n c l a s s = " t o k e n v a r i a b l e " > PN: PN</span>:<spanclass=tokenvariable>cmd failed”
exit 1
}






  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

一定注意,我们之间的Quartus安装路径是不同的,你需要根据自己的安装路径指定应用程序的路径,以便软件能够找到它们。

在这里插入图片描述
执行批处理文件:generate_hps_qsys_header.sh by
在这里插入图片描述
此时,会在My_GHRD工程目录下生成HPS头文件:hps_0.h。
在这里插入图片描述
现在,我们已经得到所需的头文件:hps_0.h。我们可以用一些代码查看编辑软件查看一下它里面的内容,我这里用的代码查看编辑软件是Source Insight。可以看到,生成的头文件:hps_0.h中已经为我们新增的PIO模块led_pio9生成了一系列宏定义。在头文件中,led_pio9的基地址由一个常量LED_PIO9_BASE表示,led_pio9的数据宽度由一个常量LED_PIO9_DATA_WIDTH表示,这两个常量将会在后面的C语言代码中被使用。
在这里插入图片描述












LED_PIO地址映射
  • 轻量级的HPS-to- fpga AXI总线相对于HPS基址的偏移地址
  • Pio_led 相对 于 Lightweight HPS-to-FPGA AXI 总线的偏移地址
控制LED

C程序员需要理解LED_PIO的PIO核的寄存器映射,然后才能控制它。下图显示了PIO核的寄存器映射。每个寄存器的宽度是32位。详情可以参阅PIO Core数据手册。对于led控制,我们只需要将输出值写入相对于基于地址0x10040的偏移地址为0寄存器。因为DE10-Standard板上的LED是高电平触发的,将值0x00000000写入偏移地址为0的寄存器将关闭所有9个红色led。DE10-Standard上有10个红色led,其中9个连接到这个控制器上。最后一个LED (LED0)用于模拟FPGA心跳。将值0x000001ff写入偏移地址为0寄存器将打开所有9个红色led。在C程序中,向pio_led的0偏移寄存器写入值0x000001ff可以表示为:

*(uint32_t *)h2p_lw_led_addr = 0x000001ff;  
  
 
  • 1
主程序

在友晶科技提供的例程中,又一个应用程序例程HPS_FPGA_LED。它的功能为:控制LEDR1-9进行LED移位闪烁操作,完成60次循环移位闪烁后,程序终止。我们的设计目标是:控制LEDR1-8进行LED移位闪烁操作,LEDR9随着LEDR1-8每一次移位而闪烁一次,完成60次循环移位闪烁后,程序终止。例程HPS_FPGA_LED的功能与我们的设计目标非常接近,所以我们可以在例程HPS_FPGA_LED的设计基础上进行更改。

首先,在光盘目录下找到例程HPS_FPGA_LED所在的文件夹:DE10-Standard_v.1.2.8_SystemCD\Demonstration\SoC_FPGA\HPS_FPGA_LED。将应用程序目录HPS_FPGA_LED复制到My_GHRD工程目录下,并把My_GHRD工程目录下的hps_0.h放到应用程序目录HPS_FPGA_LED下。

现在就可以开始根据我们的目标修改应用程序目录HPS_FPGA_LED下的:main.c。

我们要在主程序中设置一个void指针变量h2p_lw_led9_addr来存放新增的PIO组件LED_PIO9的虚拟地址。

h2p_lw_led9_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + LED_PIO9_BASE ) & ( unsigned long)( HW_REGS_MASK ) );  
  
 
  • 1

对于LEDR9的控制,我们只需要在虚拟地址h2p_lw_led9_addr所指向的地址空间中写入0x1点亮LEDR9、写入0x0熄灭LEDR9。

*(uint32_t *)h2p_lw_led9_addr = 0x1; //点亮LEDR9 *(uint32_t *)h2p_lw_led9_addr = 0x0; //熄灭LEDR9  
  
 
  • 1
  • 2

但是为了使LEDR9随着LEDR1-8的移位进行闪烁,我们可以设置一个int变量n,让其随着LEDR1-8移位进行+1操作。我们对变量n进行取余操作后,将余值写入虚拟地址h2p_lw_led9_addr所指向的地址空间中即可。

*(uint32_t *)h2p_lw_led9_addr = n%2; n = n+1;  
  
 
  • 1
  • 2

最终,main.c文件内容如下:

/* This program demonstrate how to use hps communicate with FPGA through light AXI Bridge. uses should program the FPGA by GHRD project before executing the program refer to user manual chapter 7 for details about the demo */

#include


#include


#include


#include


#include “hwlib.h”
#include “socal/socal.h”
#include “socal/hps.h”
#include “socal/alt_gpio.h”
#include “hps_0.h”
























int main() {

void *virtual_base; int fd; int loop_count; int led_direction; int led_mask; void *h2p_lw_led_addr; // map the address space for the LED registers into user space so we can interact with them. // we'll actually map in the entire CSR span of the HPS since we want to access various registers within that span if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) { printf( "ERROR: could not open \"/dev/mem\"...\n" ); return( 1 ); } virtual_base = mmap( NULL, HW_REGS_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, HW_REGS_BASE ); if( virtual_base == MAP_FAILED ) { printf( "ERROR: mmap() failed...\n" ); close( fd ); return( 1 ); } h2p_lw_led_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + LED_PIO_BASE ) & ( unsigned long)( HW_REGS_MASK ) ); // toggle the LEDs a bit loop_count = 0; led_mask = 0x01; led_direction = 0; // 0: left to right direction while( loop_count < 60 ) { // control led *(uint32_t *)h2p_lw_led_addr = ~led_mask; // wait 100ms usleep( 100*1000 ); // update led mask if (led_direction == 0){ led_mask <<= 1; if (led_mask == (0x01 << (LED_PIO_DATA_WIDTH-1))) led_direction = 1; }else{ led_mask >>= 1; if (led_mask == 0x01){ led_direction = 0; loop_count++; } } } // while // clean up our memory mapping and exit if( munmap( virtual_base, HW_REGS_SPAN ) != 0 ) { printf( "ERROR: munmap() failed...\n" ); close( fd ); return( 1 ); } close( fd ); return( 0 ); 

}

Makefile与编译

Makefile的内容如下:该程序包括SoC EDS提供的头文件。在Makefile中,还指定了ARM-linux交叉编译。

\———————————————–\

TARGET = HPS_FPGA_LED

要编译这个应用程序HPS_FPGA_LED,在SoC EDS Command Shell中进入应用程序目录HPS_FPGA_LED下。

cd HPS_FPGA_LED/  
  
 
  • 1

使用ls命令查看HPS_FPGA_LED目录下的文件,可以发现其中含有根据原来的main.c文件编译出的main.o文件和可执行文件:HPS_FPGA_LED。

ls  
  
 
  • 1

我们需要清除根据原来的main.c文件编译出的main.o文件和可执行文件:HPS_FPGA_LED。现在执行make clean命令。

make clean  
  
 
  • 1

再次使用ls命令,可以看到根据原来的main.c文件编译出的main.o文件和可执行文件:HPS_FPGA_LED已经被清除了。

ls  
  
 
  • 1

现在,使用make命令根据更改后的main.c文件编译出main.o文件和可执行文件:HPS_FPGA_LED。

make  
  
 
  • 1

系统测试

现在,我们需要在DE10_Standard开发板上进行系统测试,验证我们之前硬件逻辑设计和应用程序设计。这部分主要包括硬件逻辑的下载和应用程序的运行,硬件逻辑信息包含在文件My_GHRD.sof中,我们需要用它对FPGA进行编程;应用程序的运行其实就是在开发板上执行可执行文件HPS_FPGA_LED。

启动开发板
  • Protocol:Serial
  • Port:COM9 USB Serial Port
  • Baud rate:
  • Data bits:8
  • Parity:None
  • Stop bits:1
    点击:Connect按钮。
    在这里插入图片描述
    点击SecureCRT主界面左侧的:Session Manager。选中:serial-com9,右击选中:Rename。重命名为:DE10-SoC。
    在这里插入图片描述
    按下开发板的电源开关,启动开发板。此时会在串口工具SecureCRT中看到开发板启动信息。等待提示输入用户名登录命令。在用户登录处键入:root,回车。用户登录密码处不用填写,直接回车。
    在这里插入图片描述
    到此,开发板启动的相关工作已经完成。














硬件逻辑下载

硬件逻辑下载的方式有很多种。可以通过USB Blaster II缆线将包含有硬件逻辑信息的文件My_GHRD.sof下载到SoC FPGA的FPGA上;也可以通过USB Blaster II缆线将包含有硬件逻辑信息的文件My_GHRD.jic下载到EPCS中;还可以通过串口或者网口将有硬件逻辑信息的文件soc_sytem.rbf和设备树覆盖文件fpga.dtbo放到SD卡的Linux系统中,由Linux对FPGA进行配置。

应用程序运行

在完成FPGA的硬件逻辑配置后,我们就可以将应用程序发送到开发板中执行了。

文件传输

我们采用网口文件传输方式将应用程序可执行文件HPS_FPGA_LED发送开发板的Linux系统中。

进入串口工具SecureCRT中,输入命令:ifconfig,查看当前开发板的网络端口号及其IP地址信息。可以看到,开发板的网络端口号为:eth0,IP地址为:192.168.137.3。这已经是我们要设定的IP地址了。
在这里插入图片描述

当然,如果我们是第一次在开发板上运行友晶科技提供的镜像,这时启动的Linux系统中的网络IP地址并非如此,我们需要对其进行设定。IP地址设定有两种方法:一种是设定临时的静态IP地址;一种是设定永久的静态IP地址。前者在关闭开发板后IP地址将自动失效;后者的IP地址是永久生效的,除非再次更改。

我们这里只设定临时静态IP地址。在串口工具中输入命令:ifconfig eht0 192.168.137.3,即可设定IP地址。可以再次运行命令:ifconfig确认IP地址设定是否成功。

在这里插入图片描述
IP地址设置完成后,我们就可以进行文件传输了。进入SoC EDS Command Shell中,进入应用程序所在的目录下。输入:scp HPS_FPGA_LED root@192.168.137.3:~/,回车。此时将会启动文件传输,接着在:Are you sure you want to continue connecting

?后面输入:
yes,可执行文件HPS_FPGA_LED将会自动传输到开发板上Linux系统的root用户主目录下。

在这里插入图片描述
在串口工具SecureCRT中,输入命令ls可以查看当前所在的root用户主目录下已经存在可执行文件HPS_FPGA_LED。
在这里插入图片描述
至此,使用网口进行文件传输已经完成。












当然,我们也可以采用比较通用的FTP服务通过网口进行传输,读者可以自行学习。

文件执行

文件执行前我们需要更改可执行文件HPS_FPGA_LED的权限。在串口工具中输入命令:chmod 777 HPS_FPGA_LED。然后,输入命令:./HPS_FPGA_LED执行可执行文件。
在这里插入图片描述
按下键盘的:Ctrl + C可以终止程序运行。
在这里插入图片描述






版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212574.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午7:44
下一篇 2026年3月18日 下午7:45


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号