de1-soc培训教材记录

第一章 准备

1.1 安装软件

《Altera De1-SoC培训教材》中的环境

  • quartus 13.1
  • embedded command shell 13.1
  • 我所用的linux是de1soc_lxde_1604

1.1.1下载链接 **

[1] 培训教材.https://pan.baidu.com/s/1uFRa-5kuf9m_q_UyVIRS4A
[2] Quartus下载. https://www.altera.com.cn/downloads/download-center.html
[3] DE1-SoC Board资源.https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=Taiwan&CategoryNo=173&No=869&PartNo=4
[4] Quartus 13.1 crack. https://pan.baidu.com/s/1xKbBXYKyD2_76tdNFyC9Sg

1.1.2 Embedded command shell出现问题

打开”~\altera\13.1\embedded”路径下的Embedded_Command_Shell.bat文件,出现两个warning

  1. WARNING: DS-5 install not detected in /cygdrive/d/altera/13.1/embedded/ds-5. SoC EDS may not function correctly without an embedded DS-5 install.
  2. find_fast_cwd: WARNING: Couldn’t compute FAST_CWD pointer

解决方法

  1. 打开同路径下的ds-5_installer,在同路径下安装ds-5。注意ds-5在ECS 13.1环境下需要安装在同路径下,否则shell无法找到
  2. 出现这个错误是embedded中的host_tools中cygwin版本过低,为1.7,应下载高版本如2.0。

1.2 驱动安装

开发板接通电源后,有两根线可以用来de1-soc与计算机连接

  • USB-Blaster II。用于配置FPGA与HPS Debug。在quartus安装目录~\altera\13.1\quartus\drivers\usb-blaster-ii\路径下寻找驱动
  • UART-to-USB。用于计算机与HPS通信。在《培训教材实验包》的tool\drivers\USB2UART_driver中寻找驱动

1.3 在DE1-SOC上运行Linux

1.3.1 电脑串口设置

使用串口终端工具putty与DE1-SOC连接。
de1-soc培训教材记录_第1张图片
如图保存设置后,打开开发板电源,点击putty中的open。注意串口不一定是COM3,要使用设备管理器查看

1.3.2 制作microSD card Image

使用tool工具包中Win32DiskImager将linux镜像刻录到microSD卡(4G以上)上

1.3.3 运行Linux

将刻录了Linux的SD卡插入开发板上microSD card的插槽上,打开开发板电源。
打开putty,load de1-soc_usb,点击open。
若putty没有反应,按下enter键,若开发板启动正常,应出现用户名输入。用户名为root,密码在下载的Linux镜像文件夹中找,是readme.txt。

1.3.4 计算机与开发板上linux进行数据传输

1. U盘传输

  1. 电脑中的文件拷贝到U盘中
  2. U盘插到DE1-soc的USB接口,1、2均可
  3. 输入命令mount –t vfat /dev/sda1 /mnt,将U盘挂载到开发板上
  4. 拷贝命令 cp /mnt/test.doc /home/root/test.doc将test.doc复制到root路径下

2. ftp传输

  1. 安装计算机文件传输工具filezillawinscp
  2. 开发板插入网线
  3. 检查linux中curl版本 curl –v/–version
  4. 写登陆网络的脚本
  5. 保存为connect.sh,然后chmod 777 conncect.sh。运行./connect.sh,连接校园网。
  6. 若./connect.sh | iconv –f gbk –t utf-8出现”连接成功”字样,说明连接成功。
    注意,如果是使用校园网登陆,不能固定ip。

网络登陆脚本connect.sh


#!/bin/bash
USERID=20**********
PASSWORD=20**********
echo login
curl ‘https://connect.cuc.edu.cn/action.jsp’ –data “act=1&userid=$USERID&passwd=$PASSWORD

注意

使用SSH安全登录开发板,用到了SSH密匙。 putty和filezilla均通过密匙登录开发板。
之后filezilla可以传输文件了。

第二章 de1-soc硬件实验

2.1 Qsys生成HPS及FPGA所需文件

  1. 通过Quartus 中的设计工具Qsys选择设计所需的硬件模块,定义Soc FPGA系统的硬件架构。原本是需要同时设计好HPS和FPGA两个部分,但HPS部分原则上只要修改de1_soc_training\lab\HW中的DE1_Soc_GHRD项目即可。FPGA部分,如LED/Button PIO组件,可自己手动添加。
  2. generate生成Qsys系统。它生成了可以被Quartus编译的HDL文件。

2.2 Quartus生成FPGA所需的.soc文件,下载并测试。

  1. assignments-settings中增加soc_system.qip和soc_system_timing.sdc
  2. 修改ghrd_top.v中soc_system u0模块中led_pio_external_connection_export(LEDR)/button_pio_external_connection_export(KEY)
  3. analysis and synthesis
  4. 打开tools-tcl script,选择hps_sdram_p0_pin_assignments.tcl,然后run
    complication
  5. 下载.soc置de1-soc中
  6. 根据培训教材测试

2.3 Qsys生成的供SoC系统开发的文件

  • SOPC info file(.sopcinfo):文档用于生成Device Tree
  • Handoff Folder:里面有关于产生preloader相关配置文件【暂时用不到】
  • System View Descr(.svd):用户DS-5 debug功能【暂时用不到】

解释

  • Device Tree:Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。https://blog.csdn.net/21cnbao/article/details/8457546
  • preload:将目标文件加入RAM中,系统启动更快
  • DS-5:调试用,基本用不到

2.3.1 生成preloader image file过程【软件实验中没有用到】

  1. 使用soc eds目录中的embedded command shell.bat启动bsp-editor
  2. 选择handoff\soc_system_hps_0文件夹中的配置,则系统在工程内产生software文件夹,并产生settings.bsp文件。
  3. 按下bsp-editor的generate按钮,生成preloader的原始文档以及makefile。文档存放位置为software\spl_bsp\generated文件夹下
  4. 然后使用embedded command shell.bat进入software\spl_bsp文件夹,make生成u-boot-spl和u-boot-spl.bin两个文件,前者是可执行文件preloader elf file,后者是二进制文件preloader binary file,两个文件在DE1_SoC_GHRD\software\spl_bsp\uboot-socfpga\spl文件夹下.
  5. 最后将u-boot-spl.bin复制到software\spl_bsp文件夹下,shell到该路径,输入指令mkpimage –o preloader_with_header.img u-boot-spl.bin生成preloader_with_header.img文件。

2.3.1 生成Device Tree

在软件实验三种用到了SOPC info file(.sopcinfo)

第三章 软件实验一

目标:在DE1-SoC上输出“Hello World\n”
文件
main.c

#include 
int main(int argc, char **argv)
{
    printf("hello world\n");
    return 0;
}

Makefile

TARGET = my_first_hps

CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -g -Wall -I $(SOCEDS_DEST_ROOT)/ip/altera/hps/altera_hps/hwlib/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 *~

编译运行步骤

  1. 使用embedded command shell.bat编译,在main.c和Makefile的路径下输入命令“make”,生成了my_first_hps文件
  2. 将my_first_hps通过网络/U盘放入DE1-SoC linux系统中
  3. 使用命令“chmod 777 my_first_hps”将my_first_hps改为可执行文件
  4. 输入命令“./my_first_hps”,可看到putty屏幕输出“hello world”

第四章 软件实验二

本实验与实验一相同,只用到DE1-SoC的HPS部分。只需在embedded command shell.bat中使用两个文件*.c和Makefile生成可执行文件,将文件传输到linux系统中并改成可执行文件,即可运行。

4.1. 目标

控制HPS的LED和KEY。运行可执行文件后,HPS的LED会先闪烁两次。之后按下HPS的KEY,LED亮起,否则熄灭。

4.2. 原理

通过linux内核memory-mapped device访问GPIO控制器。

4.3. 软件API

可以通过如下软件 API 访问 GPIO 控制器的寄存器

* open: 打开内存映射设备驱动 
* mmap: 映射物理地址到用户空间 
* alt_read_word: 从指定寄存器读取一个值 
* alt_write_word: 写入一个值到指定寄存器 
* munmap:清除内存映射 
* close:关闭设备驱动

通过一些宏访问寄存器

* alt_setbits_word:设定制定寄存器的指定位为1
* alt_clrbits_word:设定制定寄存器的指定位为0

4.4. 关键命令

配置LED引脚为输出引脚

alt_setbits_word( (virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DDR_ADDR ) & ( uint32_t)( HW_REGS_MASK ) ) ), USER_IO_DIR );

点亮LED

alt_setbits_word( (virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t)( HW_REGS_MASK ) ) ), BIT_LED );

读取KEY值

alt_read_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_EXT_PORTA_ADDR ) & ( uint_t )( HW_REGS_MASK ) ) ) );

4.5. 代码

main.c

#include 
#include 
#include 
#include 
#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"
#include "socal/alt_gpio.h"

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

#define USER_IO_DIR     (0x01000000)
#define BIT_LED         (0x01000000)
#define BUTTON_MASK     (0x02000000)

int main(int argc, char **argv) {

    void *virtual_base;
    int fd;
    uint32_t  scan_input;
    int i;      
    // 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 );
    }
    // initialize the pio controller
    // led: set the direction of the HPS GPIO1 bits attached to LEDs to output
    alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DDR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), USER_IO_DIR );
    printf("led test\r\n");
    printf("the led flash 2 times\r\n");
    for(i=0;i<2;i++)
    {
        alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
        usleep(500*1000);
        alt_clrbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
        usleep(500*1000);
    }
    printf("user key test \r\n");
    printf("press key to control led\r\n");
    while(1){
        scan_input = alt_read_word( ( virtual_base + ( ( uint32_t )(  ALT_GPIO1_EXT_PORTA_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ) );      
        //usleep(1000*1000);        
        if(~scan_input&BUTTON_MASK)
            alt_setbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
        else    alt_clrbits_word( ( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ), BIT_LED );
    }   
    // 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_gpio

#
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -g -Wall  -I ${SOCEDS_DEST_ROOT}/ip/altera/hps/altera_hps/hwlib/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 *~

4.6. 编译运行步骤

  1. 同软件实验一,使用embedded command shell.bat编译,在main.c和Makefile的路径下输入命令“make”,生成了hps_gpio文件
  2. 将hps_gpio通过网络/U盘放入DE1-SoC linux系统中
  3. 使用命令“chmod 777 hps_gpio”将hps_gpio改为可执行文件
  4. 输入命令“./ hps_gpio”,可看到开发板上属于HPS的LED灯先闪烁两次,然后按下HPS的按钮可以控制LED亮灭

第五章 软件实验三

本章实现HPS与FPGA交互。

5.1 目标

使用HPS控制FPGA的10颗LED灯闪烁60次

5.2 原理

FPGA端的PIO控制器pio_led连接到HPS/ARM lightweight axi bridge,获得在HPS/ARM总线上的物理地址空间。linux通过内核memory-mapped device驱动访问PIO控制器pio_led的寄存器物理地址,从而控制pio_led【同软件实验二】

5.3 过程

5.3.1 生成HPS头文件hps0.h

  1. 与硬件实验的步骤相同,建Quartus工程,使用Qsys生成SOPC info file(.sopcinfo)文件,该文件存放在Quartus工程的目录下
  2. 在Quartus工程路径下编写文件generate_hps_qsys_header.sh。该脚本用来生成hps头文件hps0.h。
  3. 打开embedded command shell,到Quatus工程路径下,输入命令”./generate_hps_qsys_header.sh”,生成hps头文件

generate_hps_qsys_header.sh

#!/bin/sh
export PATH=$PATH:/cygdrive/d/altera/quartus13.1/quartus/sopc_builder/bin
sopc-create-header-files "./soc_system.sopcinfo" --single hps_0.h --module hps_0

5.3.2 生成HPS可执行文件

注意hps0.h和main.c及Makefile在一个文件夹中
main.c

#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 + PIO_LED_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,  add ~ because the led is low-active
        *(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 );
}

Makefile

#
TARGET = my_first_hps-fpga

#
CROSS_COMPILE = arm-linux-gnueabihf-
CFLAGS = -static -g -Wall  -I${SOCEDS_DEST_ROOT}/ip/altera/hps/altera_hps/hwlib/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 *~ 

5.3.3 编译运行

  1. embedded command shell.bat生成文件my_first_hps-fpga,放入Linux中
  2. 编译Quartus工程,将.soc文件下载到DE1-soc中
  3. 可以观察到FPGA的10颗LED闪烁60次

你可能感兴趣的:(fpga)