FPGA与HPS之间的通信实验 ——流水灯

实验目的:在DE10-Standard 下通过HPS控制FPGA实现流水灯

实验环境:

  • Quartus15.0-Lite

  • Soc EDS 17.0 (DS-5部分若需使用需付费)

  • Win32DiskImager

参考手册:

  • DE10官方手册(DE10-Standard_v.1.2.4_SystemCD\Manual)

  • DE10-Standard Getting Started Guide

  • DE10-Standard User Manual Chapter 7

第一步:打开FPGA例程,修改引脚

位置:DE10-Standard_v.1.2.4_SystemCD\Demonstration\SoC_FPGA\DE10_Standard_GHRD

1.打开Quartus->File->Open Project->定位到官方例程的位置选择qpf文件打开工程

创建工程

2.点击pin planner 根据新的开发板电路图为 led0-led9重新分配引脚

分配引脚

具体引脚分配如上图所示,绑定引脚过程中,若存在当前引脚已分配,则删除之前被绑定的部分,然后将引脚绑定到led上

3.编译程序

编译程序

4.编译成功后烧录程序

烧录程序1

点击program device

插上JTAG线,启动开发板电源,选择hardware setup


烧录程序2

点击auto detect 选择型号

autodetect

选择生成的.sof文件烧录

选择sof
烧录

第二步编写HPS程序

生成HPS头文件

1.找到 sopc-create-header-files并把文件改为.sh文件

sopc-create-header-files

2.复制文件到FPGA工程下,并更改sopc-create-header-files的最后几行的内容

修改文件内容

具体修改如下

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

cmd="swinfo2header --swinfo $swinfo_tmp_fname --sopc $sopc_design_file ${swinfo2header_args[@]}"
/cygdrive/d/altera/15.0/quartus/sopc_builder/bin/swinfo2header --swinfo "$swinfo_tmp_fname" --sopc "$sopc_design_file" "${swinfo2header_args[@]}" || {
    echo "$PN: $cmd failed"
    exit 1
}

exit 0

3.打开SoCDES的shell,切到工程目录下执行
执行如下语句,便可在工程目录下生成hps0.h文件

./sopc-create-header-files.sh soc_system.sopcinfo --single hps_0.h --module hps_0
生成HPS头文件

编写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"

#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 );
    }
    
    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文件

#
TARGET = HPS_FPGA_LED

#
ALT_DEVICE_FAMILY ?= soc_cv_av
SOCEDS_ROOT ?= $(SOCEDS_DEST_ROOT)
HWLIBS_ROOT = $(SOCEDS_ROOT)/ip/altera/hps/altera_hps/hwlib
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -g -Wall   -D$(ALT_DEVICE_FAMILY) -I$(HWLIBS_ROOT)/include/$(ALT_DEVICE_FAMILY)   -I$(HWLIBS_ROOT)/include/
LDFLAGS =  -g -Wall 
CC = $(CROSS_COMPILE)gcc
ARCH= arm

build: $(TARGET)
$(TARGET): main.o 
    $(CC) $(LDFLAGS)   $^ -o $@  
%.o : %.c
    $(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -f $(TARGET) *.a *.o *~ 

打开SoCDES的shell切到.c文件所在的文件夹之后make即可生成可执行文件

第三步,将生成的可执行文件拷贝到操作系统中运行即可

参考:

http://www.ngui.cc/51cto/show-59734.html

https://www.pianshen.com/article/2638914458/

https://blog.csdn.net/guet208/article/details/109074277

你可能感兴趣的:(FPGA与HPS之间的通信实验 ——流水灯)