实验目的:在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.编译成功后烧录程序
点击program device
插上JTAG线,启动开发板电源,选择hardware setup
点击auto detect 选择型号
选择生成的.sof文件烧录
第二步编写HPS程序
生成HPS头文件
1.找到 sopc-create-header-files并把文件改为.sh文件
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
编写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