DE1-SoC软件实验(三)—— HPS控制FPGA端的LED,实现流水灯的效果

文章目录

  • 实验目的
  • 实验内容
  • 知识需求
  • 实现的原理
  • hps_0.h头文件的理解
  • C程序编写
  • 下载sof文件到开发板
  • 启动DE1-SoC中的Linux系统执行例程

实验目的

本实验是为学习HPS(ARM)如何和FPGA进行交互。

实验内容

演示 HPS(ARM)如何控制FPGA端的LED。(FPGA端的LED作为外设,从而实现HPS对外设的控制)

知识需求

本实验主要分别两个部分,硬件设计部分和软件设计部分。(掌握Quartus硬件设计和C程序设计)

HPS和FPGA之间的协议通信主要是通过AXI高速总线,其包括 HPS-to-FPGA AXI、FPGA-to-HPS AXI以及Light-weight HPS-to-FPGA AXI。

当HPS作为主端(master)时,它可以访问FPGA端Avalon MM slave接口的所有组件,HPS作为主端时的AXI-Bridge包括:

  • HPS-to-FPGA AXI
  • Light-weight HPS-to-FPGA AXI

FPGA作为主端时的AXI-Bridge包括:

  • FPGA-to-HPS AXI
    本实验中采用 HPS-to-FPGA AXI 来实现HPS控制FPGA端的LED

实现的原理

下面来描述到底如何基于ARM(HPS)的Linux应用程序 来控制FPGA端的PIO控制器,另外控制器是连接在HPS lw h2f 总线上的,因此可获得其在HPS总线上的物理地址空间。基于此物理地址空间,我们就可以采用Linux内核内存映射设备(memory-mapped device)驱动访问PIO控制器寄存器,从而即可控制LED的行为。应用程序采用DS-5编写编译。

hps_0.h头文件的理解

在软件实验二中,已经讲解了如何生成hps_0.h头文件。那该头文件的用处是什么呢?

在该头文件中,包含了 qsys进行配置的一些信息。
例如:
包含了PIO控制器在Qsys中分配的相对于lwh2fAXI的基地址
它表现为一个宏定义PIO_LED_BASE
PIO控制器位宽信息表示为宏定义PIO_LED_DATA_WIDTH
这两个参数在驱动访问寄存器的时候要用到

#define PIO_LED_BASE 0x0
#define PIO_LED_DATA_WIDTH 10

C程序编写

打开SOCEDS,输入elcipse&,跳转打开DS-5软件,在该软件中新建C工程,并在工程上建source文件。

编写如下C程序,并进行全编译,未出现错误,即可得到可执行文件。

具体步骤和实验一相同。

#include 
#include 
#include 
#include 
#define soc_cv_av
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
#include "socal/alt_gpio.h"
#include "hps_0.h"

#define HW_REGS_BASE ( ALT_STM_OFST )
#define HW_REGS_SPAN ( 0x04000000 )
#define HW_REGS_MASK ( HW_REGS_SPAN - 1 )

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 );
	}
	//PIO的虚拟地址被定义为空指针h2p_lw_led_addr,后可用该指针变量访问PIO控制器的寄存器
	h2p_lw_led_addr=virtual_base + ( ( unsigned long  )( ALT_LWFPGASLVS_OFST + PIO_LED_BASE ) & ( unsigned long)( HW_REGS_MASK ) );
	

	// toggle the LEDs a bit
	//流水灯的切换
	loop_count = 0; //初始化,并循环60次
	led_mask = 0x01;
	led_direction = 0; // 0: left to right direction 
	while( loop_count < 60 ) {
		// control led,  add ~ because the led is low-active
		//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 << (PIO_LED_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 );
}

DE1-SoC软件实验(三)—— HPS控制FPGA端的LED,实现流水灯的效果_第1张图片
my_hps_led为生成的可执行文件,将其右键复制到SD卡中即可。

下载sof文件到开发板

由于此LED灯采用的是开发板FPGA部分的LED灯,因此我们需要将硬件设计的工程全编译,得到sof文件,将sof文件下载到开发板中。
DE1-SoC软件实验(三)—— HPS控制FPGA端的LED,实现流水灯的效果_第2张图片

启动DE1-SoC中的Linux系统执行例程

打开putty以root用户登录终端DE1-SoC软件实验(三)—— HPS控制FPGA端的LED,实现流水灯的效果_第3张图片
找到我们复制到SD卡中的文件,my_hps_led,并将该可执行程序复制到根目录
DE1-SoC软件实验(三)—— HPS控制FPGA端的LED,实现流水灯的效果_第4张图片
采用命令修改可执行文件的权限

chmod 777 my_hps_led

采用命令运行 可执行文件

./my_hps_led

在这里插入图片描述
此时即可看到开发板上的LED灯做60次的流水灯操作。

总结:
本实验分为两个大的部分,硬件设计和软件设计。

  • 硬件设计:采用quartus中的qsys来搭建硬件系统,将我们所需要的led组件配置进来,并将其例化到顶层中,全编译即可生成sof文件,以及sopcinfo文件。
    sof文件需要将其下载到开发板
    sopcinfo文件用来根据sh文件生成hps_0.h头文件
  • 软件设计:采用DS-5软件来编写C程序,重点包括了LED的控制方式,以及通过硬件文件生成的hps_0.h头文件,全编译生成可执行文件,并将其放到SD卡。

最终我们将quartus生成的sof文件下载到开发板,采用串口终端调试软件putty 以实现在开发板上运行Linux系统,并通过命令找到我们所需要的可执行文件,修改权限并执行,至此,即可在开发板上看到实验效果。

你可能感兴趣的:(DE1-SoC,fpga开发)